in filter.go [202:258]
func (p *Policy) Assemble() ([]bpf.Instruction, error) {
if err := p.Validate(); err != nil {
return nil, err
}
// Ensure arch has been set for the policy.
if p.arch == nil {
arch, err := arch.GetInfo("")
if err != nil {
return nil, err
}
p.arch = arch
}
// Build the syscall filters.
var instructions []bpf.Instruction
for _, group := range p.Syscalls {
if group.arch == nil {
group.arch = p.arch
}
groupInsts, err := group.Assemble(p.DefaultAction)
if err != nil {
return nil, err
}
instructions = append(instructions, groupInsts...)
}
// Filter out x32 to prevent bypassing blacklists by using the 32-bit ABI.
var x32Filter []bpf.Instruction
if p.arch.ID == arch.X86_64.ID {
x32Filter = []bpf.Instruction{
bpf.JumpIf{Cond: bpf.JumpGreaterOrEqual, Val: uint32(arch.X32.SeccompMask), SkipFalse: 1},
bpf.RetConstant{Val: uint32(ActionErrno) | uint32(errnoENOSYS)},
}
}
program := make([]bpf.Instruction, 0, len(x32Filter)+len(instructions)+5)
program = append(program, bpf.LoadAbsolute{Off: archOffset, Size: sizeOfUint32})
// If the loaded arch ID is not equal p.arch.ID, jump to the final Ret instruction.
jumpN := len(x32Filter) + len(instructions) - 1
if jumpN <= 255 {
program = append(program, bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: uint32(p.arch.ID), SkipTrue: uint8(jumpN)})
} else {
// JumpIf can not handle long jumps, so we switch to two instructions for this case.
program = append(program, bpf.JumpIf{Cond: bpf.JumpEqual, Val: uint32(p.arch.ID), SkipTrue: 1})
program = append(program, bpf.Jump{Skip: uint32(jumpN)})
}
program = append(program, bpf.LoadAbsolute{Off: syscallNumOffset, Size: sizeOfUint32})
program = append(program, x32Filter...)
program = append(program, instructions...)
return program, nil
}