golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/bpf/vm_load_test.go (about) 1 // Copyright 2016 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package bpf_test 6 7 import ( 8 "net" 9 "testing" 10 11 "golang.org/x/net/bpf" 12 "golang.org/x/net/ipv4" 13 ) 14 15 func TestVMLoadAbsoluteOffsetOutOfBounds(t *testing.T) { 16 pkt := []byte{ 17 0xff, 0xff, 0xff, 0xff, 18 0xff, 0xff, 0xff, 0xff, 19 0, 1, 2, 3, 20 } 21 22 vm, done, err := testVM(t, []bpf.Instruction{ 23 bpf.LoadAbsolute{ 24 Off: uint32(len(pkt)), 25 Size: 1, 26 }, 27 // Out of bounds should return 0, return 1 to tell if execution continued 28 bpf.RetConstant{Val: 1}, 29 }) 30 if err != nil { 31 t.Fatalf("failed to load BPF program: %v", err) 32 } 33 defer done() 34 35 out, err := vm.Run(pkt) 36 if err != nil { 37 t.Fatalf("unexpected error while running program: %v", err) 38 } 39 if want, got := 0, out; want != got { 40 t.Fatalf("unexpected result:\n- want: %d\n- got: %d", 41 want, got) 42 } 43 } 44 45 func TestVMLoadAbsoluteOffsetPlusSizeOutOfBounds(t *testing.T) { 46 pkt := []byte{ 47 0xff, 0xff, 0xff, 0xff, 48 0xff, 0xff, 0xff, 0xff, 49 0, 50 } 51 52 vm, done, err := testVM(t, []bpf.Instruction{ 53 bpf.LoadAbsolute{ 54 Off: uint32(len(pkt) - 1), 55 Size: 2, 56 }, 57 // Out of bounds should return 0, return 1 to tell if execution continued 58 bpf.RetConstant{Val: 1}, 59 }) 60 if err != nil { 61 t.Fatalf("failed to load BPF program: %v", err) 62 } 63 defer done() 64 65 out, err := vm.Run(pkt) 66 if err != nil { 67 t.Fatalf("unexpected error while running program: %v", err) 68 } 69 if want, got := 0, out; want != got { 70 t.Fatalf("unexpected result:\n- want: %d\n- got: %d", 71 want, got) 72 } 73 } 74 75 func TestVMLoadAbsoluteBadInstructionSize(t *testing.T) { 76 _, _, err := testVM(t, []bpf.Instruction{ 77 bpf.LoadAbsolute{ 78 Size: 5, 79 }, 80 bpf.RetA{}, 81 }) 82 if errStr(err) != "assembling instruction 1: invalid load byte length 0" { 83 t.Fatalf("unexpected error: %v", err) 84 } 85 } 86 87 func TestVMLoadConstantOK(t *testing.T) { 88 vm, done, err := testVM(t, []bpf.Instruction{ 89 bpf.LoadConstant{ 90 Dst: bpf.RegX, 91 Val: 9, 92 }, 93 bpf.TXA{}, 94 bpf.RetA{}, 95 }) 96 if err != nil { 97 t.Fatalf("failed to load BPF program: %v", err) 98 } 99 defer done() 100 101 out, err := vm.Run([]byte{ 102 0xff, 0xff, 0xff, 0xff, 103 0xff, 0xff, 0xff, 0xff, 104 0, 105 }) 106 if err != nil { 107 t.Fatalf("unexpected error while running program: %v", err) 108 } 109 if want, got := 1, out; want != got { 110 t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d", 111 want, got) 112 } 113 } 114 115 func TestVMLoadIndirectOutOfBounds(t *testing.T) { 116 pkt := []byte{ 117 0xff, 0xff, 0xff, 0xff, 118 0xff, 0xff, 0xff, 0xff, 119 0, 120 } 121 122 vm, done, err := testVM(t, []bpf.Instruction{ 123 bpf.LoadIndirect{ 124 Off: uint32(len(pkt)), 125 Size: 1, 126 }, 127 // Out of bounds should return 0, return 1 to tell if execution continued 128 bpf.RetConstant{Val: 1}, 129 }) 130 if err != nil { 131 t.Fatalf("failed to load BPF program: %v", err) 132 } 133 defer done() 134 135 out, err := vm.Run(pkt) 136 if err != nil { 137 t.Fatalf("unexpected error while running program: %v", err) 138 } 139 if want, got := 0, out; want != got { 140 t.Fatalf("unexpected result:\n- want: %d\n- got: %d", 141 want, got) 142 } 143 } 144 145 func TestVMLoadMemShiftOutOfBounds(t *testing.T) { 146 pkt := []byte{ 147 0xff, 0xff, 0xff, 0xff, 148 0xff, 0xff, 0xff, 0xff, 149 0, 150 } 151 152 vm, done, err := testVM(t, []bpf.Instruction{ 153 bpf.LoadMemShift{ 154 Off: uint32(len(pkt)), 155 }, 156 // Out of bounds should return 0, return 1 to tell if execution continued 157 bpf.RetConstant{Val: 1}, 158 }) 159 if err != nil { 160 t.Fatalf("failed to load BPF program: %v", err) 161 } 162 defer done() 163 164 out, err := vm.Run(pkt) 165 if err != nil { 166 t.Fatalf("unexpected error while running program: %v", err) 167 } 168 if want, got := 0, out; want != got { 169 t.Fatalf("unexpected result:\n- want: %d\n- got: %d", 170 want, got) 171 } 172 } 173 174 const ( 175 dhcp4Port = 53 176 ) 177 178 func TestVMLoadMemShiftLoadIndirectNoResult(t *testing.T) { 179 vm, in, done := testDHCPv4(t) 180 defer done() 181 182 // Append mostly empty UDP header with incorrect DHCPv4 port 183 in = append(in, []byte{ 184 0, 0, 185 0, dhcp4Port + 1, 186 0, 0, 187 0, 0, 188 }...) 189 190 out, err := vm.Run(in) 191 if err != nil { 192 t.Fatalf("unexpected error while running program: %v", err) 193 } 194 if want, got := 0, out; want != got { 195 t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d", 196 want, got) 197 } 198 } 199 200 func TestVMLoadMemShiftLoadIndirectOK(t *testing.T) { 201 vm, in, done := testDHCPv4(t) 202 defer done() 203 204 // Append mostly empty UDP header with correct DHCPv4 port 205 in = append(in, []byte{ 206 0, 0, 207 0, dhcp4Port, 208 0, 0, 209 0, 0, 210 }...) 211 212 out, err := vm.Run(in) 213 if err != nil { 214 t.Fatalf("unexpected error while running program: %v", err) 215 } 216 if want, got := len(in)-8, out; want != got { 217 t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d", 218 want, got) 219 } 220 } 221 222 func testDHCPv4(t *testing.T) (virtualMachine, []byte, func()) { 223 // DHCPv4 test data courtesy of David Anderson: 224 // https://github.com/google/netboot/blob/master/dhcp4/conn_linux.go#L59-L70 225 vm, done, err := testVM(t, []bpf.Instruction{ 226 // Load IPv4 packet length 227 bpf.LoadMemShift{Off: 8}, 228 // Get UDP dport 229 bpf.LoadIndirect{Off: 8 + 2, Size: 2}, 230 // Correct dport? 231 bpf.JumpIf{Cond: bpf.JumpEqual, Val: dhcp4Port, SkipFalse: 1}, 232 // Accept 233 bpf.RetConstant{Val: 1500}, 234 // Ignore 235 bpf.RetConstant{Val: 0}, 236 }) 237 if err != nil { 238 t.Fatalf("failed to load BPF program: %v", err) 239 } 240 241 // Minimal requirements to make a valid IPv4 header 242 h := &ipv4.Header{ 243 Len: ipv4.HeaderLen, 244 Src: net.IPv4(192, 168, 1, 1), 245 Dst: net.IPv4(192, 168, 1, 2), 246 } 247 hb, err := h.Marshal() 248 if err != nil { 249 t.Fatalf("failed to marshal IPv4 header: %v", err) 250 } 251 252 hb = append([]byte{ 253 0xff, 0xff, 0xff, 0xff, 254 0xff, 0xff, 0xff, 0xff, 255 }, hb...) 256 257 return vm, hb, done 258 }