github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/prog/kfuzztest_test.go (about) 1 // Copyright 2025 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 package prog 4 5 import ( 6 "bytes" 7 "encoding/binary" 8 "testing" 9 10 "github.com/stretchr/testify/assert" 11 ) 12 13 type testCase struct { 14 prog string 15 extractArg func(*Prog) Arg 16 regionArray []any 17 relocationTable []any 18 payload []any 19 } 20 21 func TestRoundUpPowerOfTwo(t *testing.T) { 22 if res := roundUpPowerOfTwo(9, 8); res != 16 { 23 t.Fatalf("expected 16, got %d", res) 24 } 25 if res := roundUpPowerOfTwo(21, 4); res != 24 { 26 t.Fatalf("expected 24, got %d", res) 27 } 28 if res := roundUpPowerOfTwo(113, 16); res != 128 { 29 t.Fatalf("expected 24, got %d", res) 30 } 31 } 32 33 func createBuffer(data []any) []byte { 34 var buf bytes.Buffer 35 36 for _, d := range data { 37 switch val := d.(type) { 38 case uint8, uint16, uint32, uint64: 39 binary.Write(&buf, binary.LittleEndian, val) 40 case []byte: 41 buf.Write(val) 42 } 43 } 44 45 return buf.Bytes() 46 } 47 48 func createPrefix() []byte { 49 var prefix bytes.Buffer 50 binary.Write(&prefix, binary.LittleEndian, kFuzzTestMagic) 51 binary.Write(&prefix, binary.LittleEndian, uint32(0)) 52 return prefix.Bytes() 53 } 54 55 //nolint:all 56 func TestMarshallKFuzzTestArg(t *testing.T) { 57 testCases := []testCase{ 58 // This test case validates the encoding of the following structure: 59 // msg: ptr[in, msghdr_netlink[netlink_msg_xfrm]] { 60 // msghdr_netlink[netlink_msg_xfrm] { 61 // addr: nil 62 // addrlen: len = 0x0 (4 bytes) 63 // pad = 0x0 (4 bytes) 64 // vec: ptr[in, iovec[in, netlink_msg_xfrm]] { 65 // iovec[in, netlink_msg_xfrm] { 66 // addr: ptr[inout, array[ANYUNION]] { 67 // array[ANYUNION] { 68 // } 69 // } 70 // len: len = 0x33fe0 (8 bytes) 71 // } 72 // } 73 // vlen: const = 0x1 (8 bytes) 74 // ctrl: const = 0x0 (8 bytes) 75 // ctrllen: const = 0x0 (8 bytes) 76 // f: send_flags = 0x0 (4 bytes) 77 // pad = 0x0 (4 bytes) 78 // } 79 // } 80 { 81 `r0 = openat$cgroup_ro(0xffffffffffffff9c, &(0x7f00000003c0)='cpuacct.stat\x00', 0x26e1, 0x0) 82 sendmsg$nl_xfrm(r0, &(0x7f0000000240)={0x0, 0x0, &(0x7f0000000080)={&(0x7f00000001c0)=ANY=[], 0x33fe0}}, 0x0)`, 83 func(p *Prog) Arg { 84 sendMsgCall := p.Calls[1] 85 msgHdr := sendMsgCall.Args[1].(*PointerArg).Res 86 return msgHdr 87 }, 88 []any{ 89 uint32(3), // Num regions. 90 91 // Region definitions: (offset, size) pairs. 92 uint32(0), uint32(0x38), 93 uint32(0x40), uint32(0x10), 94 uint32(0x58), uint32(0x0), 95 }, 96 []any{ 97 uint32(3), // Num entries. 98 uint32(0x8), // Bytes of padding. 99 100 // Relocation definitions: (source region, offset, dest region) triplets. 101 uint32(0), uint32(0x00), kFuzzTestRegionIDNull, 102 uint32(0), uint32(0x10), uint32(1), 103 uint32(1), uint32(0x00), uint32(2), 104 uint64(0x0), // 8 bytes of padding. 105 }, 106 []any{ 107 // Region 0 data. 108 kFuzzTestPlaceHolderPtr, // `addr` field, placeholder pointer. 109 uint32(0x0), // `addrlen`. 110 uint32(0x0), // `pad[4]`. 111 kFuzzTestPlaceHolderPtr, // `vec` field, placeholder pointer. 112 uint64(0x1), // `vlen`. 113 uint64(0x0), // `ctrl`. 114 uint64(0x0), // `ctrllen`. 115 uint32(0x0), // `f`. 116 uint32(0x0), // `pad[4]`. 117 118 uint64(0x0), // 8 bytes of padding between regions. 119 120 // Region 1 data. 121 kFuzzTestPlaceHolderPtr, // `addr` field, placeholder pointer. 122 uint64(0x033fe0), // `len`. 123 124 make([]byte, kFuzzTestPoisonSize), // Inter-region padding. 125 126 []byte{}, // Region 2 data (empty). 127 128 make([]byte, kFuzzTestPoisonSize), // Tail padding. 129 }, 130 }, 131 // This test case validates the encoding of the following structure: 132 // loop_info64 { 133 // lo_device: const = 0x0 (8 bytes) 134 // lo_inode: const = 0x0 (8 bytes) 135 // lo_rdevice: const = 0x0 (8 bytes) 136 // lo_offset: int64 = 0x1 (8 bytes) 137 // lo_sizelimit: int64 = 0x8005 (8 bytes) 138 // lo_number: const = 0x0 (4 bytes) 139 // lo_enc_type: lo_encrypt_type = 0x0 (4 bytes) 140 // lo_enc_key_size: int32 = 0x19 (4 bytes) 141 // lo_flags: lo_flags = 0x1c (4 bytes) 142 // lo_file_name: buffer: {ef 35 9f 41 3b b9 38 52 f7 d6 a4 ae 6d dd fb 143 // d1 ce 5d 29 c2 ee 5e 5c a9 00 0f f8 ee 09 e7 37 ff 0e df 11 0f f4 11 144 // 76 39 c2 eb 4b 78 c6 60 e6 77 df 70 19 05 b9 aa fa b4 af aa f7 55 a3 145 // f6 a0 04} (length 0x40) lo_crypt_name: buffer: {03 6c 47 c6 78 08 20 146 // d1 cb f7 96 6d 61 fd cf 33 52 63 bd 9b ff bc c2 54 2d ed 71 03 82 59 147 // ca 17 1c e1 a3 11 ef 54 ec 32 d7 1e 14 ef 3d c1 77 e9 b4 8b 00 00 00 148 // 00 00 00 00 00 00 00 00 00 00 00} (length 0x40) lo_enc_key: buffer: 149 // {f2 83 59 73 8e 22 9a 4c 66 81 00 00 00 00 00 d3 00 e6 d6 02 00 00 150 // 00 00 00 00 00 00 00 00 00 01} (length 0x20) lo_init: array[int64] { 151 // int64 = 0x204 (8 bytes) 152 // int64 = 0x0 (8 bytes) 153 // } 154 // } 155 // } 156 // ] 157 { 158 `r0 = open(&(0x7f0000000000)='./bus\x00', 0x0, 0x0) 159 ioctl$LOOP_SET_STATUS64(r0, 0x4c04, &(0x7f0000000540)={0x0, 0x0, 0x0, 0x1, 0x8005, 0x0, 0x0, 0x19, 0x1c, "ef359f413bb93852f7d6a4ae6dddfbd1ce5d29c2ee5e5ca9000ff8ee09e737ff0edf110ff4117639c2eb4b78c660e677df701905b9aafab4afaaf755a3f6a004", "036c47c6780820d1cbf7966d61fdcf335263bd9bffbcc2542ded71038259ca171ce1a311ef54ec32d71e14ef3dc177e9b48b00", "f28359738e229a4c66810000000000d300e6d602000000000000000000000001", [0x204]})`, 160 func(p *Prog) Arg { 161 ioctlCall := p.Calls[1] 162 ptrArg := ioctlCall.Args[2].(*PointerArg) 163 ret := ptrArg.Res 164 return ret 165 }, 166 []any{ 167 uint32(1), // Num regions. 168 169 // Region definitions: (offset, size) pairs. 170 uint32(0), uint32(0xe8), 171 }, 172 []any{ 173 uint32(0), // Num entries. 174 uint32(12), // Number of bytes of padding. 175 make([]byte, 12), // Padding. 176 }, 177 []any{ 178 uint64(0x0), // `lo_device`. 179 uint64(0x0), // `lo_inode`. 180 uint64(0x0), // `lo_rdevice`. 181 uint64(0x1), // `lo_offset`. 182 uint64(0x8005), // `lo_sizelimit`. 183 uint32(0x0), // `lo_number`. 184 uint32(0x0), // `lo_enc_type`. 185 uint32(0x19), // `lo_enc_key_size`. 186 uint32(0x1c), // `lo_flags`. 187 []byte{ 188 0xef, 0x35, 0x9f, 0x41, 0x3b, 0xb9, 0x38, 0x52, 189 0xf7, 0xd6, 0xa4, 0xae, 0x6d, 0xdd, 0xfb, 0xd1, 190 0xce, 0x5d, 0x29, 0xc2, 0xee, 0x5e, 0x5c, 0xa9, 191 0x00, 0x0f, 0xf8, 0xee, 0x09, 0xe7, 0x37, 0xff, 192 0x0e, 0xdf, 0x11, 0x0f, 0xf4, 0x11, 0x76, 0x39, 193 0xc2, 0xeb, 0x4b, 0x78, 0xc6, 0x60, 0xe6, 0x77, 194 0xdf, 0x70, 0x19, 0x05, 0xb9, 0xaa, 0xfa, 0xb4, 195 0xaf, 0xaa, 0xf7, 0x55, 0xa3, 0xf6, 0xa0, 0x04, 196 }, // `lo_file_name`. 197 []byte{ 198 0x03, 0x6c, 0x47, 0xc6, 0x78, 0x08, 0x20, 0xd1, 199 0xcb, 0xf7, 0x96, 0x6d, 0x61, 0xfd, 0xcf, 0x33, 200 0x52, 0x63, 0xbd, 0x9b, 0xff, 0xbc, 0xc2, 0x54, 201 0x2d, 0xed, 0x71, 0x03, 0x82, 0x59, 0xca, 0x17, 202 0x1c, 0xe1, 0xa3, 0x11, 0xef, 0x54, 0xec, 0x32, 203 0xd7, 0x1e, 0x14, 0xef, 0x3d, 0xc1, 0x77, 0xe9, 204 0xb4, 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 205 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 206 }, // `lo_crypt_name`. 207 []byte{ 208 0xf2, 0x83, 0x59, 0x73, 0x8e, 0x22, 0x9a, 0x4c, 209 0x66, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd3, 210 0x00, 0xe6, 0xd6, 0x02, 0x00, 0x00, 0x00, 0x00, 211 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 212 }, // `lo_enc_key`. 213 uint64(0x204), // `lo_init[0]. 214 uint64(0x0), // `lo_init[1]. 215 216 make([]byte, kFuzzTestPoisonSize), // Tail padding. 217 }, 218 }, 219 } 220 221 for _, tc := range testCases { 222 testOne(t, tc) 223 } 224 } 225 226 func testOne(t *testing.T, tc testCase) { 227 target, err := GetTarget("linux", "amd64") 228 if err != nil { 229 t.Fatal(err) 230 } 231 p, err := target.Deserialize([]byte(tc.prog), NonStrict) 232 if err != nil { 233 t.Fatal(err) 234 } 235 236 arg := tc.extractArg(p) 237 encoded := MarshallKFuzztestArg(arg) 238 239 wantPrefix := createPrefix() 240 wantRegionArray := createBuffer(tc.regionArray) 241 wantRelocTable := createBuffer(tc.relocationTable) 242 wantPayload := createBuffer(tc.payload) 243 244 regionArrayLen := len(wantRegionArray) 245 relocTableLen := len(wantRelocTable) 246 payloadLen := len(wantPayload) 247 248 if len(encoded) != kFuzzTestPrefixSize+regionArrayLen+relocTableLen+payloadLen { 249 t.Fatalf("encoded output has wrong total length: got %d, want %d", 250 len(encoded), regionArrayLen+relocTableLen+payloadLen) 251 } 252 253 gotPrefix := encoded[:kFuzzTestPrefixSize] 254 gotRegionArray := encoded[kFuzzTestPrefixSize : kFuzzTestPrefixSize+regionArrayLen] 255 gotRelocTable := encoded[kFuzzTestPrefixSize+regionArrayLen : kFuzzTestPrefixSize+regionArrayLen+relocTableLen] 256 gotPayload := encoded[kFuzzTestPrefixSize+regionArrayLen+relocTableLen:] 257 258 assert.Equal(t, wantPrefix, gotPrefix) 259 assert.Equal(t, wantRegionArray, gotRegionArray) 260 assert.Equal(t, wantRelocTable, gotRelocTable) 261 assert.Equal(t, wantPayload, gotPayload) 262 }