147 lines
3.5 KiB
Go
147 lines
3.5 KiB
Go
// +build linux
|
|
|
|
package seccomp
|
|
|
|
import (
|
|
"errors"
|
|
"syscall"
|
|
)
|
|
|
|
const labelTemplate = "lb-%d-%d"
|
|
|
|
// Action is the type of action that will be taken when a
|
|
// syscall is performed.
|
|
type Action int
|
|
|
|
const (
|
|
Kill Action = iota - 3 // Kill the calling process of the syscall.
|
|
Trap // Trap and coredump the calling process of the syscall.
|
|
Allow // Allow the syscall to be completed.
|
|
)
|
|
|
|
// Syscall is the specified syscall, action, and any type of arguments
|
|
// to filter on.
|
|
type Syscall struct {
|
|
// Value is the syscall number.
|
|
Value uint32
|
|
// Action is the action to perform when the specified syscall is made.
|
|
Action Action
|
|
// Args are filters that can be specified on the arguments to the syscall.
|
|
Args Args
|
|
}
|
|
|
|
func (s *Syscall) scmpAction() uint32 {
|
|
switch s.Action {
|
|
case Allow:
|
|
return retAllow
|
|
case Trap:
|
|
return retTrap
|
|
case Kill:
|
|
return retKill
|
|
}
|
|
return actionErrno(uint32(s.Action))
|
|
}
|
|
|
|
// Arg represents an argument to the syscall with the argument's index,
|
|
// the operator to apply when matching, and the argument's value at that time.
|
|
type Arg struct {
|
|
Index uint32 // index of args which start from zero
|
|
Op Operator // operation, such as EQ/NE/GE/LE
|
|
Value uint // the value of arg
|
|
}
|
|
|
|
type Args [][]Arg
|
|
|
|
var (
|
|
ErrUnresolvedLabel = errors.New("seccomp: unresolved label")
|
|
ErrDuplicateLabel = errors.New("seccomp: duplicate label use")
|
|
ErrUnsupportedOperation = errors.New("seccomp: unsupported operation for argument")
|
|
)
|
|
|
|
// Error returns an Action that will be used to send the calling
|
|
// process the specified errno when the syscall is made.
|
|
func Error(code syscall.Errno) Action {
|
|
return Action(code)
|
|
}
|
|
|
|
// New returns a new syscall context for use.
|
|
func New() *Context {
|
|
return &Context{
|
|
syscalls: make(map[uint32]*Syscall),
|
|
}
|
|
}
|
|
|
|
// Context holds syscalls for the current process to limit the type of
|
|
// actions the calling process can make.
|
|
type Context struct {
|
|
syscalls map[uint32]*Syscall
|
|
}
|
|
|
|
// Add will add the specified syscall, action, and arguments to the seccomp
|
|
// Context.
|
|
func (c *Context) Add(s *Syscall) {
|
|
c.syscalls[s.Value] = s
|
|
}
|
|
|
|
// Remove removes the specified syscall configuration from the Context.
|
|
func (c *Context) Remove(call uint32) {
|
|
delete(c.syscalls, call)
|
|
}
|
|
|
|
// Load will apply the Context to the calling process makeing any secccomp process changes
|
|
// apply after the context is loaded.
|
|
func (c *Context) Load() error {
|
|
filter, err := c.newFilter()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := prctl(prSetNoNewPrivileges, 1, 0, 0, 0); err != nil {
|
|
return err
|
|
}
|
|
prog := newSockFprog(filter)
|
|
return prog.set()
|
|
}
|
|
|
|
func (c *Context) newFilter() ([]sockFilter, error) {
|
|
var (
|
|
labels bpfLabels
|
|
f = newFilter()
|
|
)
|
|
for _, s := range c.syscalls {
|
|
f.addSyscall(s, &labels)
|
|
}
|
|
f.allow()
|
|
// process args for the syscalls
|
|
for _, s := range c.syscalls {
|
|
if err := f.addArguments(s, &labels); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
// apply labels for arguments
|
|
idx := int32(len(*f) - 1)
|
|
for ; idx >= 0; idx-- {
|
|
lf := &(*f)[idx]
|
|
if lf.code != (syscall.BPF_JMP + syscall.BPF_JA) {
|
|
continue
|
|
}
|
|
rel := int32(lf.jt)<<8 | int32(lf.jf)
|
|
if ((jumpJT << 8) | jumpJF) == rel {
|
|
if labels[lf.k].location == 0xffffffff {
|
|
return nil, ErrUnresolvedLabel
|
|
}
|
|
lf.k = labels[lf.k].location - uint32(idx+1)
|
|
lf.jt = 0
|
|
lf.jf = 0
|
|
} else if ((labelJT << 8) | labelJF) == rel {
|
|
if labels[lf.k].location != 0xffffffff {
|
|
return nil, ErrDuplicateLabel
|
|
}
|
|
labels[lf.k].location = uint32(idx)
|
|
lf.k = 0
|
|
lf.jt = 0
|
|
lf.jf = 0
|
|
}
|
|
}
|
|
return *f, nil
|
|
}
|