gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/sentry/socket/netlink/nlmsg/message_test.go (about) 1 // Copyright 2020 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 message_test 16 17 import ( 18 "bytes" 19 "reflect" 20 "testing" 21 22 "gvisor.dev/gvisor/pkg/abi/linux" 23 "gvisor.dev/gvisor/pkg/marshal" 24 "gvisor.dev/gvisor/pkg/marshal/primitive" 25 "gvisor.dev/gvisor/pkg/sentry/socket/netlink/nlmsg" 26 ) 27 28 func TestParseMessage(t *testing.T) { 29 dummyNetlinkMsg := primitive.Uint16(0x3130) 30 tests := []struct { 31 desc string 32 input []byte 33 34 header linux.NetlinkMessageHeader 35 dataMsg marshal.Marshallable 36 restLen int 37 ok bool 38 }{ 39 { 40 desc: "valid", 41 input: []byte{ 42 0x14, 0x00, 0x00, 0x00, // Length 43 0x01, 0x00, // Type 44 0x02, 0x00, // Flags 45 0x03, 0x00, 0x00, 0x00, // Seq 46 0x04, 0x00, 0x00, 0x00, // PortID 47 0x30, 0x31, 0x00, 0x00, // Data message with 2 bytes padding 48 }, 49 header: linux.NetlinkMessageHeader{ 50 Length: 20, 51 Type: 1, 52 Flags: 2, 53 Seq: 3, 54 PortID: 4, 55 }, 56 dataMsg: &dummyNetlinkMsg, 57 restLen: 0, 58 ok: true, 59 }, 60 { 61 desc: "valid with next message", 62 input: []byte{ 63 0x14, 0x00, 0x00, 0x00, // Length 64 0x01, 0x00, // Type 65 0x02, 0x00, // Flags 66 0x03, 0x00, 0x00, 0x00, // Seq 67 0x04, 0x00, 0x00, 0x00, // PortID 68 0x30, 0x31, 0x00, 0x00, // Data message with 2 bytes padding 69 0xFF, // Next message (rest) 70 }, 71 header: linux.NetlinkMessageHeader{ 72 Length: 20, 73 Type: 1, 74 Flags: 2, 75 Seq: 3, 76 PortID: 4, 77 }, 78 dataMsg: &dummyNetlinkMsg, 79 restLen: 1, 80 ok: true, 81 }, 82 { 83 desc: "valid for last message without padding", 84 input: []byte{ 85 0x12, 0x00, 0x00, 0x00, // Length 86 0x01, 0x00, // Type 87 0x02, 0x00, // Flags 88 0x03, 0x00, 0x00, 0x00, // Seq 89 0x04, 0x00, 0x00, 0x00, // PortID 90 0x30, 0x31, // Data message 91 }, 92 header: linux.NetlinkMessageHeader{ 93 Length: 18, 94 Type: 1, 95 Flags: 2, 96 Seq: 3, 97 PortID: 4, 98 }, 99 dataMsg: &dummyNetlinkMsg, 100 restLen: 0, 101 ok: true, 102 }, 103 { 104 desc: "valid for last message not to be aligned", 105 input: []byte{ 106 0x13, 0x00, 0x00, 0x00, // Length 107 0x01, 0x00, // Type 108 0x02, 0x00, // Flags 109 0x03, 0x00, 0x00, 0x00, // Seq 110 0x04, 0x00, 0x00, 0x00, // PortID 111 0x30, 0x31, // Data message 112 0x00, // Excessive 1 byte permitted at end 113 }, 114 header: linux.NetlinkMessageHeader{ 115 Length: 19, 116 Type: 1, 117 Flags: 2, 118 Seq: 3, 119 PortID: 4, 120 }, 121 dataMsg: &dummyNetlinkMsg, 122 restLen: 0, 123 ok: true, 124 }, 125 { 126 desc: "header.Length too short", 127 input: []byte{ 128 0x04, 0x00, 0x00, 0x00, // Length 129 0x01, 0x00, // Type 130 0x02, 0x00, // Flags 131 0x03, 0x00, 0x00, 0x00, // Seq 132 0x04, 0x00, 0x00, 0x00, // PortID 133 0x30, 0x31, 0x00, 0x00, // Data message with 2 bytes padding 134 }, 135 ok: false, 136 }, 137 { 138 desc: "header.Length too long", 139 input: []byte{ 140 0xFF, 0xFF, 0x00, 0x00, // Length 141 0x01, 0x00, // Type 142 0x02, 0x00, // Flags 143 0x03, 0x00, 0x00, 0x00, // Seq 144 0x04, 0x00, 0x00, 0x00, // PortID 145 0x30, 0x31, 0x00, 0x00, // Data message with 2 bytes padding 146 }, 147 ok: false, 148 }, 149 { 150 desc: "header incomplete", 151 input: []byte{ 152 0x04, 0x00, 0x00, 0x00, // Length 153 }, 154 ok: false, 155 }, 156 { 157 desc: "empty message", 158 input: []byte{}, 159 ok: false, 160 }, 161 } 162 for _, test := range tests { 163 msg, rest, ok := nlmsg.ParseMessage(test.input) 164 if ok != test.ok { 165 t.Errorf("%v: got ok = %v, want = %v", test.desc, ok, test.ok) 166 continue 167 } 168 if !test.ok { 169 continue 170 } 171 if !reflect.DeepEqual(msg.Header(), test.header) { 172 t.Errorf("%v: got hdr = %+v, want = %+v", test.desc, msg.Header(), test.header) 173 } 174 175 var dataMsg primitive.Uint16 176 _, dataOk := msg.GetData(&dataMsg) 177 if !dataOk { 178 t.Errorf("%v: GetData.ok = %v, want = true", test.desc, dataOk) 179 } else if !reflect.DeepEqual(&dataMsg, test.dataMsg) { 180 t.Errorf("%v: GetData.msg = %+v, want = %+v", test.desc, dataMsg, test.dataMsg) 181 } 182 183 if got, want := rest, test.input[len(test.input)-test.restLen:]; !bytes.Equal(got, want) { 184 t.Errorf("%v: got rest = %v, want = %v", test.desc, got, want) 185 } 186 } 187 } 188 189 func TestAttrView(t *testing.T) { 190 tests := []struct { 191 desc string 192 input []byte 193 194 // Outputs for ParseFirst. 195 hdr linux.NetlinkAttrHeader 196 value []byte 197 restLen int 198 ok bool 199 200 // Outputs for Empty. 201 isEmpty bool 202 }{ 203 { 204 desc: "valid", 205 input: []byte{ 206 0x06, 0x00, // Length 207 0x01, 0x00, // Type 208 0x30, 0x31, 0x00, 0x00, // Data with 2 bytes padding 209 }, 210 hdr: linux.NetlinkAttrHeader{ 211 Length: 6, 212 Type: 1, 213 }, 214 value: []byte{0x30, 0x31}, 215 restLen: 0, 216 ok: true, 217 isEmpty: false, 218 }, 219 { 220 desc: "at alignment", 221 input: []byte{ 222 0x08, 0x00, // Length 223 0x01, 0x00, // Type 224 0x30, 0x31, 0x32, 0x33, // Data 225 }, 226 hdr: linux.NetlinkAttrHeader{ 227 Length: 8, 228 Type: 1, 229 }, 230 value: []byte{0x30, 0x31, 0x32, 0x33}, 231 restLen: 0, 232 ok: true, 233 isEmpty: false, 234 }, 235 { 236 desc: "at alignment with rest data", 237 input: []byte{ 238 0x08, 0x00, // Length 239 0x01, 0x00, // Type 240 0x30, 0x31, 0x32, 0x33, // Data 241 0xFF, 0xFE, // Rest data 242 }, 243 hdr: linux.NetlinkAttrHeader{ 244 Length: 8, 245 Type: 1, 246 }, 247 value: []byte{0x30, 0x31, 0x32, 0x33}, 248 restLen: 2, 249 ok: true, 250 isEmpty: false, 251 }, 252 { 253 desc: "hdr.Length too long", 254 input: []byte{ 255 0xFF, 0x00, // Length 256 0x01, 0x00, // Type 257 0x30, 0x31, 0x32, 0x33, // Data 258 }, 259 ok: false, 260 isEmpty: false, 261 }, 262 { 263 desc: "hdr.Length too short", 264 input: []byte{ 265 0x01, 0x00, // Length 266 0x01, 0x00, // Type 267 0x30, 0x31, 0x32, 0x33, // Data 268 }, 269 ok: false, 270 isEmpty: false, 271 }, 272 { 273 desc: "empty", 274 input: []byte{}, 275 ok: false, 276 isEmpty: true, 277 }, 278 } 279 for _, test := range tests { 280 attrs := nlmsg.AttrsView(test.input) 281 282 // Test ParseFirst(). 283 hdr, value, rest, ok := attrs.ParseFirst() 284 if ok != test.ok { 285 t.Errorf("%v: got ok = %v, want = %v", test.desc, ok, test.ok) 286 } else if test.ok { 287 if !reflect.DeepEqual(hdr, test.hdr) { 288 t.Errorf("%v: got hdr = %+v, want = %+v", test.desc, hdr, test.hdr) 289 } 290 if !bytes.Equal(value, test.value) { 291 t.Errorf("%v: got value = %v, want = %v", test.desc, value, test.value) 292 } 293 if wantRest := test.input[len(test.input)-test.restLen:]; !bytes.Equal(rest, wantRest) { 294 t.Errorf("%v: got rest = %v, want = %v", test.desc, rest, wantRest) 295 } 296 } 297 298 // Test Empty(). 299 if got, want := attrs.Empty(), test.isEmpty; got != want { 300 t.Errorf("%v: got empty = %v, want = %v", test.desc, got, want) 301 } 302 } 303 }