Skip to content

Commit

Permalink
Fix integer overflow in BPF conditional jumps
Browse files Browse the repository at this point in the history
If the list of syscalls is too long (>256) then the library sends incorrect
BPF code and this results in crashes, because some syscalls are denied. This
commit fixes the crash by splitting the list of syscalls into groups of
size 256 in Policy.Assemble. Also I found another similar overflow in
SyscallGroup.Assemble and fixed it as well.
  • Loading branch information
starius committed Apr 1, 2019
1 parent 5bed103 commit b286f7d
Showing 1 changed file with 38 additions and 16 deletions.
54 changes: 38 additions & 16 deletions filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,11 +190,21 @@ func (p *Policy) Assemble() ([]bpf.Instruction, error) {
}
}

program := []bpf.Instruction{
bpf.LoadAbsolute{Off: archOffset, Size: 4},
bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: uint32(p.arch.ID), SkipTrue: uint8(1 + len(x32Filter) + len(instructions))},
bpf.LoadAbsolute{Off: syscallNumOffset, Size: 4},
program := make([]bpf.Instruction, 0, len(x32Filter)+len(instructions)+5)

program = append(program, bpf.LoadAbsolute{Off: archOffset, Size: 4})

// If the loaded arch ID is not equal p.arch.ID, jump to the final Ret instruction.
jumpN := 1 + len(x32Filter) + len(instructions)
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: 4})
program = append(program, x32Filter...)
program = append(program, instructions...)
program = append(program, bpf.RetConstant{Val: uint32(action)})
Expand Down Expand Up @@ -237,20 +247,32 @@ func (g *SyscallGroup) Assemble() ([]bpf.Instruction, error) {
}

insts := make([]bpf.Instruction, 0, len(syscallNums))
for i, num := range syscallNums {
jumpN := uint8(len(g.Names) - i - 1)
jeq := bpf.JumpIf{Cond: bpf.JumpEqual, Val: num, SkipTrue: jumpN}
if jumpN == 0 {
// Skip the return statement if the last condition was not satisfied.
jeq.SkipFalse = 1

for len(syscallNums) > 0 {
// JumpIf can not handle long jumps, so we insert a Ret after each group of 256 checks.
size := len(syscallNums)
if size > 256 {
size = 256
}
syscallNums256 := syscallNums[:size]
syscallNums = syscallNums[size:]

for i, num := range syscallNums256 {
jumpN := uint8(len(syscallNums256) - i - 1)
jeq := bpf.JumpIf{Cond: bpf.JumpEqual, Val: num, SkipTrue: jumpN}
if jumpN == 0 {
// Skip the return statement if the last condition was not satisfied.
jeq.SkipFalse = 1
}
insts = append(insts, jeq)
}
insts = append(insts, jeq)
}

action := g.Action
if action == ActionErrno {
action |= Action(errnoEPERM)
action := g.Action
if action == ActionErrno {
action |= Action(errnoEPERM)
}
insts = append(insts, bpf.RetConstant{Val: uint32(action)})
}
insts = append(insts, bpf.RetConstant{Val: uint32(action)})

return insts, nil
}

0 comments on commit b286f7d

Please sign in to comment.