github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/pkg/bpf/bpf.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package bpf provides tools for working with Berkeley Packet Filter (BPF) 16 // programs. More information on BPF can be found at 17 // https://www.freebsd.org/cgi/man.cgi?bpf(4) 18 package bpf 19 20 import ( 21 "fmt" 22 23 "github.com/metacubex/gvisor/pkg/abi/linux" 24 ) 25 26 const ( 27 // MaxInstructions is the maximum number of instructions in a BPF program, 28 // and is equal to Linux's BPF_MAXINSNS. 29 MaxInstructions = 4096 30 31 // ScratchMemRegisters is the number of M registers in a BPF virtual machine, 32 // and is equal to Linux's BPF_MEMWORDS. 33 ScratchMemRegisters = 16 34 ) 35 36 // Parts of a linux.BPFInstruction.OpCode. Compare to the Linux kernel's 37 // include/uapi/linux/filter.h. 38 // 39 // In the comments below: 40 // 41 // - A, X, and M[] are BPF virtual machine registers. 42 // 43 // - K refers to the instruction field linux.BPFInstruction.K. 44 // 45 // - Bits are counted from the LSB position. 46 const ( 47 // Instruction class, stored in bits 0-2. 48 Ld = 0x00 // load into A 49 Ldx = 0x01 // load into X 50 St = 0x02 // store from A 51 Stx = 0x03 // store from X 52 Alu = 0x04 // arithmetic 53 Jmp = 0x05 // jump 54 Ret = 0x06 // return 55 Misc = 0x07 56 instructionClassMask = 0x07 57 58 // Size of a load, stored in bits 3-4. 59 W = 0x00 // 32 bits 60 H = 0x08 // 16 bits 61 B = 0x10 // 8 bits 62 loadSizeMask = 0x18 63 64 // Source operand for a load, stored in bits 5-7. 65 // Address mode numbers in the comments come from Linux's 66 // Documentation/networking/filter.txt. 67 Imm = 0x00 // immediate value K (mode 4) 68 Abs = 0x20 // data in input at byte offset K (mode 1) 69 Ind = 0x40 // data in input at byte offset X+K (mode 2) 70 Mem = 0x60 // M[K] (mode 3) 71 Len = 0x80 // length of the input in bytes ("BPF extension len") 72 Msh = 0xa0 // 4 * lower nibble of input at byte offset K (mode 5) 73 loadModeMask = 0xe0 74 75 // Source operands for arithmetic, jump, and return instructions. 76 // Arithmetic and jump instructions can use K or X as source operands. 77 // Return instructions can use K or A as source operands. 78 K = 0x00 // still mode 4 79 X = 0x08 // mode 0 80 A = 0x10 // mode 9 81 operandMask = K | X | A 82 srcAluJmpMask = 0x08 83 srcRetMask = 0x18 84 85 // Arithmetic instructions, stored in bits 4-7. 86 Add = 0x00 87 Sub = 0x10 // A - src 88 Mul = 0x20 89 Div = 0x30 // A / src 90 Or = 0x40 91 And = 0x50 92 Lsh = 0x60 // A << src 93 Rsh = 0x70 // A >> src 94 Neg = 0x80 // -A (src ignored) 95 Mod = 0x90 // A % src 96 Xor = 0xa0 97 aluMask = 0xf0 98 99 // Jump instructions, stored in bits 4-7. 100 Ja = 0x00 // unconditional (uses K for jump offset) 101 Jeq = 0x10 // if A == src 102 Jgt = 0x20 // if A > src 103 Jge = 0x30 // if A >= src 104 Jset = 0x40 // if (A & src) != 0 105 jmpMask = 0xf0 106 107 // Miscellaneous instructions, stored in bits 3-7. 108 Tax = 0x00 // A = X 109 Txa = 0x80 // X = A 110 miscMask = 0xf8 111 112 // Masks for bits that should be zero. 113 unusedBitsMask = 0xff00 // all valid instructions use only bits 0-7 114 storeUnusedBitsMask = 0xf8 // stores only use instruction class 115 retUnusedBitsMask = 0xe0 // returns only use instruction class and source operand 116 ) 117 118 // Instruction is a type alias for linux.BPFInstruction. 119 // It adds a human-readable stringification and other helper functions. 120 // 121 // +marshal slice:InstructionSlice 122 // +stateify savable 123 // +stateify identtype 124 type Instruction linux.BPFInstruction 125 126 // String returns a human-readable version of the instruction. 127 func (ins *Instruction) String() string { 128 s, err := Decode(*ins) 129 if err != nil { 130 return fmt.Sprintf("[invalid %v: %v]", (*linux.BPFInstruction)(ins), err) 131 } 132 return s 133 } 134 135 // Stmt returns an Instruction representing a BPF non-jump instruction. 136 func Stmt(code uint16, k uint32) Instruction { 137 return Instruction{ 138 OpCode: code, 139 K: k, 140 } 141 } 142 143 // Jump returns an Instruction representing a BPF jump instruction. 144 func Jump(code uint16, k uint32, jt, jf uint8) Instruction { 145 return Instruction{ 146 OpCode: code, 147 JumpIfTrue: jt, 148 JumpIfFalse: jf, 149 K: k, 150 } 151 } 152 153 // Equal returns whether this instruction is equivalent to `other`. 154 func (ins Instruction) Equal(other Instruction) bool { 155 if ins.OpCode != other.OpCode { 156 // If instructions don't have the same opcode, they are not equal. 157 return false 158 } 159 switch ins.OpCode & instructionClassMask { 160 case Ld, Ldx: 161 if ins.OpCode&loadModeMask == Len { 162 // Length instructions are independent of the K register. 163 return true 164 } 165 // Two load instructions are the same if they load from the same offset. 166 return ins.K == other.K 167 case St, Stx: 168 // Two store instructions are the same if they store at the same offset. 169 return ins.K == other.K 170 case Alu: 171 if ins.OpCode == Alu|Neg { 172 return true // The negation instruction has no operands. 173 } 174 if ins.OpCode&operandMask == X { 175 // If we use X, no need to check anything. 176 return true 177 } 178 if ins.OpCode&operandMask == K { 179 // If use K, check that it's the same. 180 return ins.K == other.K 181 } 182 // Otherwise, we use the whole instruction. 183 case Ret: 184 switch ins.OpCode { 185 case Ret | A: 186 // All instructions that return the A register are equivalent. 187 return true 188 case Ret | K: 189 // All instructions that return the same value are equivalent. 190 return ins.K == other.K 191 } 192 case Jmp: 193 if ins.IsUnconditionalJump() { 194 // Unconditional jumps to the same offset are equivalent. 195 return ins.K == other.K 196 } 197 if ins.OpCode&operandMask == X { 198 // If we use X as the operand, check the conditional jump targets only. 199 return ins.JumpIfTrue == other.JumpIfTrue && ins.JumpIfFalse == other.JumpIfFalse 200 } 201 // Otherwise, we use the whole instruction. 202 case Misc: 203 if ins.OpCode == Misc|Tax || ins.OpCode == Misc|Txa { 204 // Swapping X and A, we don't care about the other fields. 205 return true 206 } 207 } 208 // All other instructions need full bit-for-bit comparison. 209 return ins == other 210 } 211 212 // IsReturn returns true if `ins` is a return instruction. 213 func (ins Instruction) IsReturn() bool { 214 return ins.OpCode&instructionClassMask == Ret 215 } 216 217 // IsJump returns true if `ins` is a jump instruction. 218 func (ins Instruction) IsJump() bool { 219 return ins.OpCode&instructionClassMask == Jmp 220 } 221 222 // IsConditionalJump returns true if `ins` is a conditional jump instruction. 223 func (ins Instruction) IsConditionalJump() bool { 224 return ins.IsJump() && ins.OpCode&jmpMask != Ja 225 } 226 227 // IsUnconditionalJump returns true if `ins` is a conditional jump instruction. 228 func (ins Instruction) IsUnconditionalJump() bool { 229 return ins.IsJump() && ins.OpCode&jmpMask == Ja 230 } 231 232 // JumpOffset is a possible jump offset that an instruction may jump to. 233 type JumpOffset struct { 234 // Type is the type of jump that an instruction may execute. 235 Type JumpType 236 237 // Offset is the number of instructions that the jump skips over. 238 Offset uint32 239 } 240 241 // JumpOffsets returns the set of instruction offsets that this instruction 242 // may jump to. Returns a nil slice if this is not a jump instruction. 243 func (ins Instruction) JumpOffsets() []JumpOffset { 244 if !ins.IsJump() { 245 return nil 246 } 247 if ins.IsConditionalJump() { 248 return []JumpOffset{ 249 {JumpTrue, uint32(ins.JumpIfTrue)}, 250 {JumpFalse, uint32(ins.JumpIfFalse)}, 251 } 252 } 253 return []JumpOffset{{JumpDirect, ins.K}} 254 } 255 256 // ModifiesRegisterA returns true iff this instruction modifies the value 257 // of the "A" register. 258 func (ins Instruction) ModifiesRegisterA() bool { 259 switch ins.OpCode & instructionClassMask { 260 case Ld: 261 return true 262 case Alu: 263 return true 264 case Misc: 265 return ins.OpCode == Misc|Tax 266 default: 267 return false 268 } 269 }