You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

108 lines
3.0 KiB

// Copyright 2015 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package seccomp
import (
"fmt"
)
// #include <linux/filter.h>
import "C"
// BPF machine opcodes. These are the only ones we use.
const (
opLOAD = C.BPF_LD + C.BPF_W + C.BPF_ABS
opJEQ = C.BPF_JMP + C.BPF_JEQ + C.BPF_K
opJSET = C.BPF_JMP + C.BPF_JSET + C.BPF_K
opJUMP = C.BPF_JMP + C.BPF_JA
opRET = C.BPF_RET + C.BPF_K
)
// SockFilter encodes one BPF machine instruction.
// This struct mirrors struct sock_filter from <linux/filter.h>.
type SockFilter struct {
Code uint16 // Actual filter code.
JT uint8 // Jump true.
JF uint8 // Jump false.
K uint32 // Generic multiuse field.
}
// SockFprog encodes a BPF machine program.
// This struct mirrors struct sock_fprog from <linux/filter.h>.
type SockFprog struct {
Len uint16 // Number of BPF machine instructions.
Filter *SockFilter // Pointer to the first instruction.
}
// C versions of the structs used for sanity checking.
type sock_filter C.struct_sock_filter
type sock_fprog C.struct_sock_fprog
// bpfInsn constructs one BPF machine instruction.
func bpfInsn(code uint16, k uint32, jt, jf uint8) SockFilter {
return SockFilter{code, jt, jf, k}
}
// bpfStmt constructs one BPF machine statement.
func bpfStmt(code uint16, k uint32) SockFilter {
return bpfInsn(code, k, 0, 0)
}
// bpfLoad returns the instruction to load the word at the given offset.
func bpfLoad(offset uintptr) SockFilter {
return bpfStmt(opLOAD, uint32(offset))
}
// bpfJeq returns an instruction encoding "jump-if-equal".
// Register A is compared with val.
// Both jt and jf are relative offsets. Offset 0 means fallthrough.
func bpfJeq(val uint32, jt, jf uint8) SockFilter {
return bpfInsn(opJEQ, val, jt, jf)
}
// bpfJset returns an instruction encoding "jump-if-set".
// Register A is bitwise anded with val and result compared with zero.
// Both jt and jf are relative offsets. Offset 0 means fallthrough.
func bpfJset(val uint32, jt, jf uint8) SockFilter {
return bpfInsn(opJSET, val, jt, jf)
}
// bpfJump returns an instruction encoding an unconditional jump to a relative offset.
// Offset 0 means fallthrough (NOP).
func bpfJump(offset int) SockFilter {
return bpfStmt(opJUMP, uint32(offset))
}
// bpfRet returns the instruction to return the value val.
func bpfRet(val uint32) SockFilter {
return bpfStmt(opRET, val)
}
// String returns a readable representation of a BPF machine instruction.
func (f SockFilter) String() string {
var code string
switch f.Code {
case opLOAD:
code = "Load"
case opJEQ:
code = "Jeq"
case opJSET:
code = "Jset"
case opJUMP:
code = "Jump"
case opRET:
code = "Return"
default:
code = fmt.Sprintf("%04x", f.Code)
}
return fmt.Sprintf("%8s %08x, %02x, %02x\n", code, f.K, f.JT, f.JF)
}
// ptr returns a pointer to a copy of the argument, useful in cases
// where the & syntax isn't allowed. e.g. ptr(bpfInsn(...)).
func ptr(f SockFilter) *SockFilter {
return &f
}