| 1 | package protocol |
| 2 | |
| 3 | import "testing" |
| 4 | |
| 5 | func labels(items ...struct{ Key, Value []byte }) []struct{ Key, Value []byte } { |
| 6 | return items |
| 7 | } |
| 8 | |
| 9 | func TestCgroupsLookupRoundTrip(t *testing.T) { |
| 10 | var req [256]byte |
| 11 | n, err := EncodeCgroupsLookupRequest([][]byte{ |
| 12 | []byte("/sys/fs/cgroup/a"), |
| 13 | []byte("/system.slice/docker-abc.scope"), |
| 14 | }, req[:]) |
| 15 | if err != nil { |
| 16 | t.Fatalf("encode request: %v", err) |
| 17 | } |
| 18 | reqView, err := DecodeCgroupsLookupRequest(req[:n]) |
| 19 | if err != nil { |
| 20 | t.Fatalf("decode request: %v", err) |
| 21 | } |
| 22 | if reqView.ItemCount != 2 { |
| 23 | t.Fatalf("item count = %d, want 2", reqView.ItemCount) |
| 24 | } |
| 25 | item0, err := reqView.Item(0) |
| 26 | if err != nil || item0.String() != "/sys/fs/cgroup/a" { |
| 27 | t.Fatalf("item 0 = %q, err=%v", item0.String(), err) |
| 28 | } |
| 29 | |
| 30 | var resp [1024]byte |
| 31 | builder := NewCgroupsLookupBuilder(resp[:], 2, 123) |
| 32 | if err := builder.Add( |
| 33 | CgroupLookupKnown, |
| 34 | OrchestratorK8s, |
| 35 | []byte("/sys/fs/cgroup/a"), |
| 36 | []byte("pod-a"), |
| 37 | labels(struct{ Key, Value []byte }{[]byte("namespace"), []byte("default")}), |
| 38 | ); err != nil { |
| 39 | t.Fatalf("add known: %v", err) |
| 40 | } |
| 41 | if err := builder.Add( |
| 42 | CgroupLookupUnknownPermanent, |
| 43 | 0, |
| 44 | []byte("/system.slice/docker-abc.scope"), |
| 45 | nil, |
| 46 | nil, |
| 47 | ); err != nil { |
| 48 | t.Fatalf("add unknown: %v", err) |
| 49 | } |
| 50 | total := builder.Finish() |
| 51 | view, err := DecodeCgroupsLookupResponse(resp[:total]) |
| 52 | if err != nil { |
| 53 | t.Fatalf("decode response: %v", err) |
| 54 | } |
| 55 | if view.ItemCount != 2 || view.Generation != 123 { |
| 56 | t.Fatalf("header = count %d generation %d", view.ItemCount, view.Generation) |
| 57 | } |
| 58 | got, err := view.Item(0) |
| 59 | if err != nil { |
| 60 | t.Fatalf("response item 0: %v", err) |
| 61 | } |
| 62 | if got.Status != CgroupLookupKnown || got.Orchestrator != OrchestratorK8s || |
| 63 | got.Path.String() != "/sys/fs/cgroup/a" || got.Name.String() != "pod-a" || |
| 64 | got.LabelCount != 1 { |
| 65 | t.Fatalf("bad known item: %+v", got) |
| 66 | } |
| 67 | label, err := got.Label(0) |
| 68 | if err != nil { |
| 69 | t.Fatalf("label 0: %v", err) |
| 70 | } |
| 71 | if label.Key.String() != "namespace" || label.Value.String() != "default" { |
| 72 | t.Fatalf("bad label: %q=%q", label.Key.String(), label.Value.String()) |
| 73 | } |
| 74 | got, err = view.Item(1) |
| 75 | if err != nil { |
| 76 | t.Fatalf("response item 1: %v", err) |
| 77 | } |
| 78 | if got.Status != CgroupLookupUnknownPermanent || got.Name.Len() != 0 { |
| 79 | t.Fatalf("bad unknown item: %+v", got) |
| 80 | } |
| 81 | } |
| 82 | |
| 83 | func TestAppsLookupRoundTrip(t *testing.T) { |
| 84 | var req [128]byte |
| 85 | n, err := EncodeAppsLookupRequest([]uint32{0, 1234, 9999}, req[:]) |
| 86 | if err != nil { |
| 87 | t.Fatalf("encode request: %v", err) |
| 88 | } |
| 89 | reqView, err := DecodeAppsLookupRequest(req[:n]) |
| 90 | if err != nil { |
| 91 | t.Fatalf("decode request: %v", err) |
| 92 | } |
| 93 | pid, err := reqView.Item(0) |
| 94 | if err != nil || pid != 0 { |
| 95 | t.Fatalf("item 0 pid = %d, err=%v", pid, err) |
| 96 | } |
| 97 | |
| 98 | var resp [2048]byte |
| 99 | builder := NewAppsLookupBuilder(resp[:], 3, 77) |
| 100 | if err := builder.Add( |
| 101 | PidLookupKnown, |
| 102 | AppsCgroupKnown, |
| 103 | OrchestratorDocker, |
| 104 | 1234, |
| 105 | 1, |
| 106 | 1000, |
| 107 | ^uint64(0), |
| 108 | []byte("nginx"), |
| 109 | []byte("/docker/abc"), |
| 110 | []byte("container-a"), |
| 111 | labels(struct{ Key, Value []byte }{[]byte("image"), []byte("nginx:latest")}), |
| 112 | ); err != nil { |
| 113 | t.Fatalf("add known: %v", err) |
| 114 | } |
| 115 | if err := builder.Add( |
| 116 | PidLookupKnown, |
| 117 | AppsCgroupHostRoot, |
| 118 | 0, |
| 119 | 0, |
| 120 | 0, |
| 121 | 0, |
| 122 | 0, |
| 123 | []byte("swapper"), |
| 124 | nil, |
| 125 | nil, |
| 126 | nil, |
| 127 | ); err != nil { |
| 128 | t.Fatalf("add host root: %v", err) |
| 129 | } |
| 130 | if err := builder.Add( |
| 131 | PidLookupUnknown, |
| 132 | AppsCgroupKnown, |
| 133 | 0, |
| 134 | 9999, |
| 135 | 0, |
| 136 | NipcUIDUnset, |
| 137 | 0, |
| 138 | nil, |
| 139 | nil, |
| 140 | nil, |
| 141 | nil, |
| 142 | ); err != nil { |
| 143 | t.Fatalf("add unknown: %v", err) |
| 144 | } |
| 145 | total := builder.Finish() |
| 146 | view, err := DecodeAppsLookupResponse(resp[:total]) |
| 147 | if err != nil { |
| 148 | t.Fatalf("decode response: %v", err) |
| 149 | } |
| 150 | if view.ItemCount != 3 || view.Generation != 77 { |
| 151 | t.Fatalf("header = count %d generation %d", view.ItemCount, view.Generation) |
| 152 | } |
| 153 | item0, err := view.Item(0) |
| 154 | if err != nil { |
| 155 | t.Fatalf("item 0: %v", err) |
| 156 | } |
| 157 | if item0.Pid != 1234 || item0.Status != PidLookupKnown || |
| 158 | item0.CgroupStatus != AppsCgroupKnown || |
| 159 | item0.Comm.String() != "nginx" || |
| 160 | item0.CgroupPath.String() != "/docker/abc" || |
| 161 | item0.Starttime != ^uint64(0) { |
| 162 | t.Fatalf("bad known item: %+v", item0) |
| 163 | } |
| 164 | item1, err := view.Item(1) |
| 165 | if err != nil { |
| 166 | t.Fatalf("item 1: %v", err) |
| 167 | } |
| 168 | if item1.Pid != 0 || item1.CgroupStatus != AppsCgroupHostRoot || item1.CgroupPath.Len() != 0 { |
| 169 | t.Fatalf("bad host-root item: %+v", item1) |
| 170 | } |
| 171 | item2, err := view.Item(2) |
| 172 | if err != nil { |
| 173 | t.Fatalf("item 2: %v", err) |
| 174 | } |
| 175 | if item2.Pid != 9999 || item2.Status != PidLookupUnknown || item2.Uid != NipcUIDUnset { |
| 176 | t.Fatalf("bad unknown item: %+v", item2) |
| 177 | } |
| 178 | } |
| 179 | |
| 180 | func TestLookupValidationEdges(t *testing.T) { |
| 181 | var req [128]byte |
| 182 | if _, err := EncodeCgroupsLookupRequest([][]byte{[]byte("bad\x00path")}, req[:]); err != ErrBadLayout { |
| 183 | t.Fatalf("interior NUL request error = %v, want ErrBadLayout", err) |
| 184 | } |
| 185 | |
| 186 | var resp [256]byte |
| 187 | builder := NewAppsLookupBuilder(resp[:], 1, 0) |
| 188 | if err := builder.Add( |
| 189 | PidLookupKnown, |
| 190 | AppsCgroupHostRoot, |
| 191 | 0, |
| 192 | 1, |
| 193 | 0, |
| 194 | 0, |
| 195 | 1, |
| 196 | []byte("1234567890123456"), |
| 197 | nil, |
| 198 | nil, |
| 199 | nil, |
| 200 | ); err != ErrBadLayout { |
| 201 | t.Fatalf("comm len 16 error = %v, want ErrBadLayout", err) |
| 202 | } |
| 203 | |
| 204 | cg := NewCgroupsLookupBuilder(resp[:], 1, 0) |
| 205 | if err := cg.Add(CgroupLookupKnown, 99, []byte("/x"), nil, nil); err != nil { |
| 206 | t.Fatalf("unknown orchestrator should be accepted: %v", err) |
| 207 | } |
| 208 | total := cg.Finish() |
| 209 | itemStart := CgroupsLookupRespHdr + LookupDirEntrySize + int(ne.Uint32(resp[CgroupsLookupRespHdr:CgroupsLookupRespHdr+4])) |
| 210 | ne.PutUint16(resp[itemStart+2:itemStart+4], 99) |
| 211 | if _, err := DecodeCgroupsLookupResponse(resp[:total]); err != ErrBadLayout { |
| 212 | t.Fatalf("bad status error = %v, want ErrBadLayout", err) |
| 213 | } |
| 214 | } |
| 215 | |
| 216 | func TestLookupDispatchRejectsShortResponseBuffer(t *testing.T) { |
| 217 | var req [128]byte |
| 218 | reqLen, err := EncodeCgroupsLookupRequest([][]byte{[]byte("/x")}, req[:]) |
| 219 | if err != nil { |
| 220 | t.Fatalf("encode cgroups request: %v", err) |
| 221 | } |
| 222 | shortCgroups := make([]byte, CgroupsLookupRespHdr+LookupDirEntrySize-1) |
| 223 | n, err := DispatchCgroupsLookup(req[:reqLen], shortCgroups, func(*CgroupsLookupRequestView, *CgroupsLookupBuilder) bool { |
| 224 | t.Fatal("handler should not run with undersized response buffer") |
| 225 | return false |
| 226 | }) |
| 227 | if err != ErrOverflow || n != 0 { |
| 228 | t.Fatalf("cgroups dispatch = n %d err %v, want 0 ErrOverflow", n, err) |
| 229 | } |
| 230 | |
| 231 | reqLen, err = EncodeAppsLookupRequest([]uint32{1234}, req[:]) |
| 232 | if err != nil { |
| 233 | t.Fatalf("encode apps request: %v", err) |
| 234 | } |
| 235 | shortApps := make([]byte, AppsLookupRespHdr+LookupDirEntrySize-1) |
| 236 | n, err = DispatchAppsLookup(req[:reqLen], shortApps, func(*AppsLookupRequestView, *AppsLookupBuilder) bool { |
| 237 | t.Fatal("handler should not run with undersized response buffer") |
| 238 | return false |
| 239 | }) |
| 240 | if err != ErrOverflow || n != 0 { |
| 241 | t.Fatalf("apps dispatch = n %d err %v, want 0 ErrOverflow", n, err) |
| 242 | } |
| 243 | } |
| 244 | |
| 245 | func TestLookupDecodeRejectsMaxUint32DirectoryOffset(t *testing.T) { |
| 246 | var resp [512]byte |
| 247 | cg := NewCgroupsLookupBuilder(resp[:], 1, 0) |
| 248 | if err := cg.Add(CgroupLookupKnown, OrchestratorDocker, []byte("/x"), nil, nil); err != nil { |
| 249 | t.Fatalf("add cgroups item: %v", err) |
| 250 | } |
| 251 | total := cg.Finish() |
| 252 | ne.PutUint32(resp[CgroupsLookupRespHdr:CgroupsLookupRespHdr+4], ^uint32(0)-7) |
| 253 | if _, err := DecodeCgroupsLookupResponse(resp[:total]); err != ErrOutOfBounds { |
| 254 | t.Fatalf("cgroups response with max offset error = %v, want ErrOutOfBounds", err) |
| 255 | } |
| 256 | |
| 257 | apps := NewAppsLookupBuilder(resp[:], 1, 0) |
| 258 | if err := apps.Add( |
| 259 | PidLookupKnown, |
| 260 | AppsCgroupHostRoot, |
| 261 | 0, |
| 262 | 1234, |
| 263 | 1, |
| 264 | 1000, |
| 265 | 42, |
| 266 | []byte("nginx"), |
| 267 | nil, |
| 268 | nil, |
| 269 | nil, |
| 270 | ); err != nil { |
| 271 | t.Fatalf("add apps item: %v", err) |
| 272 | } |
| 273 | total = apps.Finish() |
| 274 | ne.PutUint32(resp[AppsLookupRespHdr:AppsLookupRespHdr+4], ^uint32(0)-7) |
| 275 | if _, err := DecodeAppsLookupResponse(resp[:total]); err != ErrOutOfBounds { |
| 276 | t.Fatalf("apps response with max offset error = %v, want ErrOutOfBounds", err) |
| 277 | } |
| 278 | } |
| 279 | |
| 280 | func TestLookupLabelLayoutOverflow(t *testing.T) { |
| 281 | sample := labels(struct{ Key, Value []byte }{[]byte("k"), []byte("v")}) |
| 282 | maxInt := int(^uint(0) >> 1) |
| 283 | |
| 284 | if _, _, _, err := labelLayoutGo(maxInt-3, sample); err != ErrOverflow { |
| 285 | t.Fatalf("align overflow error = %v, want ErrOverflow", err) |
| 286 | } |
| 287 | if _, _, _, err := labelLayoutGo(maxInt-15, sample); err != ErrOverflow { |
| 288 | t.Fatalf("label table overflow error = %v, want ErrOverflow", err) |
| 289 | } |
| 290 | } |
| 291 | |
| 292 | func expectPanic(t *testing.T, name string, fn func()) { |
| 293 | t.Helper() |
| 294 | defer func() { |
| 295 | if recover() == nil { |
| 296 | t.Fatalf("%s did not panic", name) |
| 297 | } |
| 298 | }() |
| 299 | fn() |
| 300 | } |
| 301 | |
| 302 | func cgroupsLookupItemStart(t *testing.T, buf []byte) int { |
| 303 | t.Helper() |
| 304 | return CgroupsLookupRespHdr + LookupDirEntrySize + |
| 305 | int(ne.Uint32(buf[CgroupsLookupRespHdr:CgroupsLookupRespHdr+4])) |
| 306 | } |
| 307 | |
| 308 | func appsLookupItemStart(t *testing.T, buf []byte) int { |
| 309 | t.Helper() |
| 310 | return AppsLookupRespHdr + LookupDirEntrySize + |
| 311 | int(ne.Uint32(buf[AppsLookupRespHdr:AppsLookupRespHdr+4])) |
| 312 | } |
| 313 | |
| 314 | func validCgroupsLookupItemBytes(t *testing.T) []byte { |
| 315 | t.Helper() |
| 316 | var resp [512]byte |
| 317 | builder := NewCgroupsLookupBuilder(resp[:], 1, 0) |
| 318 | if err := builder.Add( |
| 319 | CgroupLookupKnown, |
| 320 | OrchestratorDocker, |
| 321 | []byte("/x"), |
| 322 | []byte("name"), |
| 323 | labels(struct{ Key, Value []byte }{[]byte("k"), []byte("v")}), |
| 324 | ); err != nil { |
| 325 | t.Fatalf("add cgroups item: %v", err) |
| 326 | } |
| 327 | total := builder.Finish() |
| 328 | start := cgroupsLookupItemStart(t, resp[:]) |
| 329 | length := int(ne.Uint32(resp[CgroupsLookupRespHdr+4 : CgroupsLookupRespHdr+8])) |
| 330 | return append([]byte(nil), resp[start:start+length]...)[:min(length, total-start)] |
| 331 | } |
| 332 | |
| 333 | func validAppsLookupItemBytes(t *testing.T) []byte { |
| 334 | t.Helper() |
| 335 | var resp [1024]byte |
| 336 | builder := NewAppsLookupBuilder(resp[:], 1, 0) |
| 337 | if err := builder.Add( |
| 338 | PidLookupKnown, |
| 339 | AppsCgroupKnown, |
| 340 | OrchestratorDocker, |
| 341 | 1234, 1, 1000, 42, |
| 342 | []byte("nginx"), |
| 343 | []byte("/docker/abc"), |
| 344 | []byte("container-a"), |
| 345 | labels(struct{ Key, Value []byte }{[]byte("k"), []byte("v")}), |
| 346 | ); err != nil { |
| 347 | t.Fatalf("add apps item: %v", err) |
| 348 | } |
| 349 | total := builder.Finish() |
| 350 | start := appsLookupItemStart(t, resp[:]) |
| 351 | length := int(ne.Uint32(resp[AppsLookupRespHdr+4 : AppsLookupRespHdr+8])) |
| 352 | return append([]byte(nil), resp[start:start+length]...)[:min(length, total-start)] |
| 353 | } |
| 354 | |
| 355 | func TestLookupRequestValidationCoverage(t *testing.T) { |
| 356 | var req [128]byte |
| 357 | |
| 358 | n, err := EncodeCgroupsLookupRequest(nil, req[:]) |
| 359 | if err != nil { |
| 360 | t.Fatalf("encode empty cgroups request: %v", err) |
| 361 | } |
| 362 | cgView, err := DecodeCgroupsLookupRequest(req[:n]) |
| 363 | if err != nil || cgView.ItemCount != 0 { |
| 364 | t.Fatalf("decode empty cgroups request = count %d err %v", cgView.ItemCount, err) |
| 365 | } |
| 366 | if _, err := cgView.Item(0); err != ErrOutOfBounds { |
| 367 | t.Fatalf("empty cgroups item error = %v, want ErrOutOfBounds", err) |
| 368 | } |
| 369 | if _, err := EncodeCgroupsLookupRequest([][]byte{[]byte("/x")}, req[:CgroupsLookupReqHdr]); err != ErrOverflow { |
| 370 | t.Fatalf("short cgroups request buffer error = %v, want ErrOverflow", err) |
| 371 | } |
| 372 | if _, err := EncodeCgroupsLookupRequest([][]byte{[]byte("/xy")}, make([]byte, CgroupsLookupReqHdr+LookupDirEntrySize+1)); err != ErrOverflow { |
| 373 | t.Fatalf("packed cgroups request overflow error = %v, want ErrOverflow", err) |
| 374 | } |
| 375 | |
| 376 | n, err = EncodeCgroupsLookupRequest([][]byte{[]byte("/xy")}, req[:]) |
| 377 | if err != nil { |
| 378 | t.Fatalf("encode cgroups request: %v", err) |
| 379 | } |
| 380 | if _, err := DecodeCgroupsLookupRequest(req[:CgroupsLookupReqHdr]); err != ErrTruncated { |
| 381 | t.Fatalf("cgroups request truncated dir error = %v, want ErrTruncated", err) |
| 382 | } |
| 383 | cgManualReq := make([]byte, CgroupsLookupReqHdr+LookupDirEntrySize) |
| 384 | ne.PutUint32(cgManualReq[CgroupsLookupReqHdr+4:CgroupsLookupReqHdr+8], 8) |
| 385 | if _, err := (&CgroupsLookupRequestView{ItemCount: 1, payload: cgManualReq}).Item(0); err != ErrOutOfBounds { |
| 386 | t.Fatalf("manual cgroups request item error = %v, want ErrOutOfBounds", err) |
| 387 | } |
| 388 | for _, tc := range []struct { |
| 389 | name string |
| 390 | edit func([]byte) |
| 391 | want error |
| 392 | }{ |
| 393 | { |
| 394 | name: "bad layout", |
| 395 | edit: func(b []byte) { |
| 396 | ne.PutUint16(b[0:2], 2) |
| 397 | }, |
| 398 | want: ErrBadLayout, |
| 399 | }, |
| 400 | { |
| 401 | name: "bad flags", |
| 402 | edit: func(b []byte) { |
| 403 | ne.PutUint16(b[2:4], 1) |
| 404 | }, |
| 405 | want: ErrBadLayout, |
| 406 | }, |
| 407 | { |
| 408 | name: "bad reserved", |
| 409 | edit: func(b []byte) { |
| 410 | ne.PutUint32(b[8:12], 1) |
| 411 | }, |
| 412 | want: ErrBadLayout, |
| 413 | }, |
| 414 | { |
| 415 | name: "bad alignment", |
| 416 | edit: func(b []byte) { |
| 417 | ne.PutUint32(b[CgroupsLookupReqHdr:CgroupsLookupReqHdr+4], 1) |
| 418 | }, |
| 419 | want: ErrBadAlignment, |
| 420 | }, |
| 421 | { |
| 422 | name: "too short item", |
| 423 | edit: func(b []byte) { |
| 424 | ne.PutUint32(b[CgroupsLookupReqHdr+4:CgroupsLookupReqHdr+8], 1) |
| 425 | }, |
| 426 | want: ErrBadLayout, |
| 427 | }, |
| 428 | { |
| 429 | name: "missing nul", |
| 430 | edit: func(b []byte) { |
| 431 | dirEnd := CgroupsLookupReqHdr + LookupDirEntrySize |
| 432 | b[dirEnd+3] = '!' |
| 433 | }, |
| 434 | want: ErrMissingNul, |
| 435 | }, |
| 436 | { |
| 437 | name: "interior nul", |
| 438 | edit: func(b []byte) { |
| 439 | dirEnd := CgroupsLookupReqHdr + LookupDirEntrySize |
| 440 | b[dirEnd+1] = 0 |
| 441 | }, |
| 442 | want: ErrBadLayout, |
| 443 | }, |
| 444 | } { |
| 445 | bad := append([]byte(nil), req[:n]...) |
| 446 | tc.edit(bad) |
| 447 | if _, err := DecodeCgroupsLookupRequest(bad); err != tc.want { |
| 448 | t.Fatalf("decode cgroups request %s error = %v, want %v", tc.name, err, tc.want) |
| 449 | } |
| 450 | } |
| 451 | |
| 452 | n, err = EncodeAppsLookupRequest(nil, req[:]) |
| 453 | if err != nil { |
| 454 | t.Fatalf("encode empty apps request: %v", err) |
| 455 | } |
| 456 | appsView, err := DecodeAppsLookupRequest(req[:n]) |
| 457 | if err != nil || appsView.ItemCount != 0 { |
| 458 | t.Fatalf("decode empty apps request = count %d err %v", appsView.ItemCount, err) |
| 459 | } |
| 460 | if _, err := appsView.Item(0); err != ErrOutOfBounds { |
| 461 | t.Fatalf("empty apps item error = %v, want ErrOutOfBounds", err) |
| 462 | } |
| 463 | if _, err := EncodeAppsLookupRequest([]uint32{1234}, req[:AppsLookupReqHdr]); err != ErrOverflow { |
| 464 | t.Fatalf("short apps request buffer error = %v, want ErrOverflow", err) |
| 465 | } |
| 466 | if _, err := EncodeAppsLookupRequest([]uint32{1234}, make([]byte, AppsLookupReqHdr+LookupDirEntrySize+AppsLookupKeySize-1)); err != ErrOverflow { |
| 467 | t.Fatalf("packed apps request overflow error = %v, want ErrOverflow", err) |
| 468 | } |
| 469 | |
| 470 | n, err = EncodeAppsLookupRequest([]uint32{1234}, req[:]) |
| 471 | if err != nil { |
| 472 | t.Fatalf("encode apps request: %v", err) |
| 473 | } |
| 474 | if _, err := DecodeAppsLookupRequest(req[:AppsLookupReqHdr]); err != ErrTruncated { |
| 475 | t.Fatalf("apps request truncated dir error = %v, want ErrTruncated", err) |
| 476 | } |
| 477 | appsManualReq := make([]byte, AppsLookupReqHdr+LookupDirEntrySize) |
| 478 | ne.PutUint32(appsManualReq[AppsLookupReqHdr+4:AppsLookupReqHdr+8], AppsLookupKeySize) |
| 479 | if _, err := (&AppsLookupRequestView{ItemCount: 1, payload: appsManualReq}).Item(0); err != ErrOutOfBounds { |
| 480 | t.Fatalf("manual apps request item error = %v, want ErrOutOfBounds", err) |
| 481 | } |
| 482 | for _, tc := range []struct { |
| 483 | name string |
| 484 | edit func([]byte) |
| 485 | want error |
| 486 | }{ |
| 487 | { |
| 488 | name: "bad layout", |
| 489 | edit: func(b []byte) { |
| 490 | ne.PutUint16(b[0:2], 2) |
| 491 | }, |
| 492 | want: ErrBadLayout, |
| 493 | }, |
| 494 | { |
| 495 | name: "bad item length", |
| 496 | edit: func(b []byte) { |
| 497 | ne.PutUint32(b[AppsLookupReqHdr+4:AppsLookupReqHdr+8], AppsLookupKeySize-1) |
| 498 | }, |
| 499 | want: ErrBadLayout, |
| 500 | }, |
| 501 | { |
| 502 | name: "bad key reserved", |
| 503 | edit: func(b []byte) { |
| 504 | dirEnd := AppsLookupReqHdr + LookupDirEntrySize |
| 505 | ne.PutUint32(b[dirEnd+4:dirEnd+8], 1) |
| 506 | }, |
| 507 | want: ErrBadLayout, |
| 508 | }, |
| 509 | } { |
| 510 | bad := append([]byte(nil), req[:n]...) |
| 511 | tc.edit(bad) |
| 512 | if _, err := DecodeAppsLookupRequest(bad); err != tc.want { |
| 513 | t.Fatalf("decode apps request %s error = %v, want %v", tc.name, err, tc.want) |
| 514 | } |
| 515 | } |
| 516 | } |
| 517 | |
| 518 | func TestCgroupsLookupBuilderGuardCoverage(t *testing.T) { |
| 519 | expectPanic(t, "small cgroups builder", func() { |
| 520 | _ = NewCgroupsLookupBuilder(make([]byte, CgroupsLookupRespHdr+LookupDirEntrySize-1), 1, 0) |
| 521 | }) |
| 522 | |
| 523 | var empty [CgroupsLookupRespHdr]byte |
| 524 | emptyBuilder := NewCgroupsLookupBuilder(empty[:], 0, 1) |
| 525 | emptyBuilder.SetGeneration(2) |
| 526 | if total := emptyBuilder.Finish(); total != CgroupsLookupRespHdr { |
| 527 | t.Fatalf("empty cgroups finish = %d", total) |
| 528 | } |
| 529 | emptyView, err := DecodeCgroupsLookupResponse(empty[:]) |
| 530 | if err != nil || emptyView.Generation != 2 || emptyView.ItemCount != 0 { |
| 531 | t.Fatalf("empty cgroups decode = generation %d count %d err %v", emptyView.Generation, emptyView.ItemCount, err) |
| 532 | } |
| 533 | |
| 534 | var resp [512]byte |
| 535 | builder := NewCgroupsLookupBuilder(resp[:], 1, 10) |
| 536 | builder.SetGeneration(11) |
| 537 | if builder.ItemCount() != 0 || builder.Error() != nil { |
| 538 | t.Fatalf("fresh cgroups builder count/error = %d/%v", builder.ItemCount(), builder.Error()) |
| 539 | } |
| 540 | err = builder.Add( |
| 541 | CgroupLookupKnown, |
| 542 | OrchestratorK8s, |
| 543 | []byte("/x"), |
| 544 | []byte("pod"), |
| 545 | labels(struct{ Key, Value []byte }{[]byte("namespace"), []byte("default")}), |
| 546 | ) |
| 547 | if err != nil { |
| 548 | t.Fatalf("add cgroups known: %v", err) |
| 549 | } |
| 550 | if builder.ItemCount() != 1 || builder.Error() != nil { |
| 551 | t.Fatalf("used cgroups builder count/error = %d/%v", builder.ItemCount(), builder.Error()) |
| 552 | } |
| 553 | if err := builder.Add(CgroupLookupKnown, 0, []byte("/overflow"), nil, nil); err != ErrOverflow { |
| 554 | t.Fatalf("cgroups overflow error = %v, want ErrOverflow", err) |
| 555 | } |
| 556 | if builder.Error() != ErrOverflow { |
| 557 | t.Fatalf("cgroups builder error = %v, want ErrOverflow", builder.Error()) |
| 558 | } |
| 559 | total := builder.Finish() |
| 560 | view, err := DecodeCgroupsLookupResponse(resp[:total]) |
| 561 | if err != nil || view.Generation != 11 { |
| 562 | t.Fatalf("decode cgroups builder response = generation %d err %v", view.Generation, err) |
| 563 | } |
| 564 | item, err := view.Item(0) |
| 565 | if err != nil { |
| 566 | t.Fatalf("cgroups response item: %v", err) |
| 567 | } |
| 568 | if _, err := item.Label(1); err != ErrOutOfBounds { |
| 569 | t.Fatalf("cgroups label out-of-bounds error = %v, want ErrOutOfBounds", err) |
| 570 | } |
| 571 | if _, err := view.Item(1); err != ErrOutOfBounds { |
| 572 | t.Fatalf("cgroups item out-of-bounds error = %v, want ErrOutOfBounds", err) |
| 573 | } |
| 574 | |
| 575 | for _, tc := range []struct { |
| 576 | name string |
| 577 | add func(*CgroupsLookupBuilder) error |
| 578 | want error |
| 579 | }{ |
| 580 | { |
| 581 | name: "bad status", |
| 582 | add: func(b *CgroupsLookupBuilder) error { |
| 583 | return b.Add(99, 0, []byte("/x"), nil, nil) |
| 584 | }, |
| 585 | want: ErrBadLayout, |
| 586 | }, |
| 587 | { |
| 588 | name: "empty path", |
| 589 | add: func(b *CgroupsLookupBuilder) error { |
| 590 | return b.Add(CgroupLookupKnown, 0, nil, nil, nil) |
| 591 | }, |
| 592 | want: ErrBadLayout, |
| 593 | }, |
| 594 | { |
| 595 | name: "bad name", |
| 596 | add: func(b *CgroupsLookupBuilder) error { |
| 597 | return b.Add(CgroupLookupKnown, 0, []byte("/x"), []byte("bad\x00name"), nil) |
| 598 | }, |
| 599 | want: ErrBadLayout, |
| 600 | }, |
| 601 | { |
| 602 | name: "unknown with name", |
| 603 | add: func(b *CgroupsLookupBuilder) error { |
| 604 | return b.Add(CgroupLookupUnknownRetryLater, 0, []byte("/x"), []byte("name"), nil) |
| 605 | }, |
| 606 | want: ErrBadLayout, |
| 607 | }, |
| 608 | { |
| 609 | name: "bad label", |
| 610 | add: func(b *CgroupsLookupBuilder) error { |
| 611 | return b.Add(CgroupLookupKnown, 0, []byte("/x"), nil, |
| 612 | labels(struct{ Key, Value []byte }{[]byte{}, []byte("v")})) |
| 613 | }, |
| 614 | want: ErrBadLayout, |
| 615 | }, |
| 616 | } { |
| 617 | b := NewCgroupsLookupBuilder(resp[:], 1, 0) |
| 618 | if err := tc.add(b); err != tc.want { |
| 619 | t.Fatalf("cgroups builder %s error = %v, want %v", tc.name, err, tc.want) |
| 620 | } |
| 621 | } |
| 622 | tooManyLabels := make([]struct{ Key, Value []byte }, int(^uint16(0))+1) |
| 623 | if err := NewCgroupsLookupBuilder(resp[:], 1, 0).Add(CgroupLookupKnown, 0, []byte("/x"), nil, tooManyLabels); err != ErrOverflow { |
| 624 | t.Fatalf("cgroups too-many-labels error = %v, want ErrOverflow", err) |
| 625 | } |
| 626 | |
| 627 | small := make([]byte, CgroupsLookupRespHdr+LookupDirEntrySize) |
| 628 | smallBuilder := NewCgroupsLookupBuilder(small, 1, 0) |
| 629 | if err := smallBuilder.Add(CgroupLookupKnown, 0, []byte("/x"), nil, nil); err != ErrOverflow { |
| 630 | t.Fatalf("small cgroups builder add error = %v, want ErrOverflow", err) |
| 631 | } |
| 632 | negativeOffsetBuilder := &CgroupsLookupBuilder{buf: make([]byte, 512), maxItems: 1, dataOffset: -1} |
| 633 | if err := negativeOffsetBuilder.Add(CgroupLookupKnown, 0, []byte("/x"), nil, nil); err != ErrOverflow { |
| 634 | t.Fatalf("negative-offset cgroups builder add error = %v, want ErrOverflow", err) |
| 635 | } |
| 636 | overflowOffsetBuilder := &CgroupsLookupBuilder{buf: make([]byte, 512), maxItems: 1, dataOffset: maxIntValue() - 32} |
| 637 | if err := overflowOffsetBuilder.Add(CgroupLookupKnown, 0, []byte("/x"), nil, nil); err != ErrOverflow { |
| 638 | t.Fatalf("overflow-offset cgroups builder add error = %v, want ErrOverflow", err) |
| 639 | } |
| 640 | } |
| 641 | |
| 642 | func TestAppsLookupBuilderGuardCoverage(t *testing.T) { |
| 643 | expectPanic(t, "small apps builder", func() { |
| 644 | _ = NewAppsLookupBuilder(make([]byte, AppsLookupRespHdr+LookupDirEntrySize-1), 1, 0) |
| 645 | }) |
| 646 | |
| 647 | var empty [AppsLookupRespHdr]byte |
| 648 | emptyBuilder := NewAppsLookupBuilder(empty[:], 0, 1) |
| 649 | emptyBuilder.SetGeneration(2) |
| 650 | if total := emptyBuilder.Finish(); total != AppsLookupRespHdr { |
| 651 | t.Fatalf("empty apps finish = %d", total) |
| 652 | } |
| 653 | emptyView, err := DecodeAppsLookupResponse(empty[:]) |
| 654 | if err != nil || emptyView.Generation != 2 || emptyView.ItemCount != 0 { |
| 655 | t.Fatalf("empty apps decode = generation %d count %d err %v", emptyView.Generation, emptyView.ItemCount, err) |
| 656 | } |
| 657 | |
| 658 | var resp [1024]byte |
| 659 | builder := NewAppsLookupBuilder(resp[:], 4, 20) |
| 660 | builder.SetGeneration(21) |
| 661 | if builder.ItemCount() != 0 || builder.Error() != nil { |
| 662 | t.Fatalf("fresh apps builder count/error = %d/%v", builder.ItemCount(), builder.Error()) |
| 663 | } |
| 664 | if err := builder.Add( |
| 665 | PidLookupKnown, |
| 666 | AppsCgroupKnown, |
| 667 | OrchestratorDocker, |
| 668 | 1234, 1, 1000, 42, |
| 669 | []byte("nginx"), |
| 670 | []byte("/docker/abc"), |
| 671 | []byte("container-a"), |
| 672 | labels(struct{ Key, Value []byte }{[]byte("image"), []byte("nginx")}), |
| 673 | ); err != nil { |
| 674 | t.Fatalf("add apps known: %v", err) |
| 675 | } |
| 676 | if err := builder.Add( |
| 677 | PidLookupKnown, |
| 678 | AppsCgroupUnknownRetryLater, |
| 679 | 0, |
| 680 | 1235, 1, 1000, 43, |
| 681 | []byte("worker"), |
| 682 | nil, |
| 683 | nil, |
| 684 | nil, |
| 685 | ); err != nil { |
| 686 | t.Fatalf("add apps retry: %v", err) |
| 687 | } |
| 688 | if err := builder.Add( |
| 689 | PidLookupKnown, |
| 690 | AppsCgroupUnknownPermanent, |
| 691 | 0, |
| 692 | 1236, 1, 1000, 44, |
| 693 | []byte("worker2"), |
| 694 | []byte("/gone"), |
| 695 | nil, |
| 696 | nil, |
| 697 | ); err != nil { |
| 698 | t.Fatalf("add apps permanent: %v", err) |
| 699 | } |
| 700 | if err := builder.Add( |
| 701 | PidLookupUnknown, |
| 702 | 0, |
| 703 | 0, |
| 704 | 9999, 0, NipcUIDUnset, 0, |
| 705 | nil, nil, nil, nil, |
| 706 | ); err != nil { |
| 707 | t.Fatalf("add apps unknown: %v", err) |
| 708 | } |
| 709 | if builder.ItemCount() != 4 || builder.Error() != nil { |
| 710 | t.Fatalf("used apps builder count/error = %d/%v", builder.ItemCount(), builder.Error()) |
| 711 | } |
| 712 | total := builder.Finish() |
| 713 | view, err := DecodeAppsLookupResponse(resp[:total]) |
| 714 | if err != nil || view.Generation != 21 { |
| 715 | t.Fatalf("decode apps builder response = generation %d err %v", view.Generation, err) |
| 716 | } |
| 717 | item, err := view.Item(0) |
| 718 | if err != nil { |
| 719 | t.Fatalf("apps response item: %v", err) |
| 720 | } |
| 721 | if _, err := item.Label(1); err != ErrOutOfBounds { |
| 722 | t.Fatalf("apps label out-of-bounds error = %v, want ErrOutOfBounds", err) |
| 723 | } |
| 724 | if _, err := view.Item(4); err != ErrOutOfBounds { |
| 725 | t.Fatalf("apps item out-of-bounds error = %v, want ErrOutOfBounds", err) |
| 726 | } |
| 727 | item, err = view.Item(1) |
| 728 | if err != nil || item.CgroupStatus != AppsCgroupUnknownRetryLater { |
| 729 | t.Fatalf("apps retry item = %+v err %v", item, err) |
| 730 | } |
| 731 | if len(item.CgroupPath.Bytes()) != 0 { |
| 732 | t.Fatalf("apps retry cgroup path = %q, want empty", item.CgroupPath.Bytes()) |
| 733 | } |
| 734 | item, err = view.Item(2) |
| 735 | if err != nil || item.CgroupStatus != AppsCgroupUnknownPermanent { |
| 736 | t.Fatalf("apps permanent item = %+v err %v", item, err) |
| 737 | } |
| 738 | item, err = view.Item(3) |
| 739 | if err != nil || item.Status != PidLookupUnknown { |
| 740 | t.Fatalf("apps unknown item = %+v err %v", item, err) |
| 741 | } |
| 742 | if err := builder.Add(PidLookupUnknown, 0, 0, 10000, 0, NipcUIDUnset, 0, nil, nil, nil, nil); err != ErrOverflow { |
| 743 | t.Fatalf("apps overflow error = %v, want ErrOverflow", err) |
| 744 | } |
| 745 | if builder.Error() != ErrOverflow { |
| 746 | t.Fatalf("apps builder error = %v, want ErrOverflow", builder.Error()) |
| 747 | } |
| 748 | |
| 749 | for _, tc := range []struct { |
| 750 | name string |
| 751 | add func(*AppsLookupBuilder) error |
| 752 | want error |
| 753 | }{ |
| 754 | { |
| 755 | name: "bad status", |
| 756 | add: func(b *AppsLookupBuilder) error { |
| 757 | return b.Add(99, 0, 0, 1, 0, 0, 0, []byte("x"), nil, nil, nil) |
| 758 | }, |
| 759 | want: ErrBadLayout, |
| 760 | }, |
| 761 | { |
| 762 | name: "bad cgroup status", |
| 763 | add: func(b *AppsLookupBuilder) error { |
| 764 | return b.Add(PidLookupKnown, 99, 0, 1, 0, 0, 0, []byte("x"), nil, nil, nil) |
| 765 | }, |
| 766 | want: ErrBadLayout, |
| 767 | }, |
| 768 | { |
| 769 | name: "bad comm", |
| 770 | add: func(b *AppsLookupBuilder) error { |
| 771 | return b.Add(PidLookupKnown, AppsCgroupHostRoot, 0, 1, 0, 0, 0, []byte("bad\x00comm"), nil, nil, nil) |
| 772 | }, |
| 773 | want: ErrBadLayout, |
| 774 | }, |
| 775 | { |
| 776 | name: "unknown with data", |
| 777 | add: func(b *AppsLookupBuilder) error { |
| 778 | return b.Add(PidLookupUnknown, 0, 0, 1, 2, NipcUIDUnset, 0, nil, nil, nil, nil) |
| 779 | }, |
| 780 | want: ErrBadLayout, |
| 781 | }, |
| 782 | { |
| 783 | name: "known missing path", |
| 784 | add: func(b *AppsLookupBuilder) error { |
| 785 | return b.Add(PidLookupKnown, AppsCgroupKnown, 0, 1, 0, 0, 0, []byte("x"), nil, nil, nil) |
| 786 | }, |
| 787 | want: ErrBadLayout, |
| 788 | }, |
| 789 | { |
| 790 | name: "retry with labels", |
| 791 | add: func(b *AppsLookupBuilder) error { |
| 792 | return b.Add(PidLookupKnown, AppsCgroupUnknownRetryLater, 0, 1, 0, 0, 0, |
| 793 | []byte("x"), []byte("/x"), nil, |
| 794 | labels(struct{ Key, Value []byte }{[]byte("k"), []byte("v")})) |
| 795 | }, |
| 796 | want: ErrBadLayout, |
| 797 | }, |
| 798 | { |
| 799 | name: "permanent missing path", |
| 800 | add: func(b *AppsLookupBuilder) error { |
| 801 | return b.Add(PidLookupKnown, AppsCgroupUnknownPermanent, 0, 1, 0, 0, 0, |
| 802 | []byte("x"), nil, nil, nil) |
| 803 | }, |
| 804 | want: ErrBadLayout, |
| 805 | }, |
| 806 | { |
| 807 | name: "host root with path", |
| 808 | add: func(b *AppsLookupBuilder) error { |
| 809 | return b.Add(PidLookupKnown, AppsCgroupHostRoot, 0, 1, 0, 0, 0, []byte("x"), []byte("/x"), nil, nil) |
| 810 | }, |
| 811 | want: ErrBadLayout, |
| 812 | }, |
| 813 | { |
| 814 | name: "bad label", |
| 815 | add: func(b *AppsLookupBuilder) error { |
| 816 | return b.Add(PidLookupKnown, AppsCgroupKnown, 0, 1, 0, 0, 0, |
| 817 | []byte("x"), []byte("/x"), nil, |
| 818 | labels(struct{ Key, Value []byte }{[]byte("bad\x00key"), []byte("v")})) |
| 819 | }, |
| 820 | want: ErrBadLayout, |
| 821 | }, |
| 822 | } { |
| 823 | b := NewAppsLookupBuilder(resp[:], 1, 0) |
| 824 | if err := tc.add(b); err != tc.want { |
| 825 | t.Fatalf("apps builder %s error = %v, want %v", tc.name, err, tc.want) |
| 826 | } |
| 827 | } |
| 828 | tooManyLabels := make([]struct{ Key, Value []byte }, int(^uint16(0))+1) |
| 829 | if err := NewAppsLookupBuilder(resp[:], 1, 0).Add(PidLookupKnown, AppsCgroupKnown, 0, 1, 0, 0, 0, []byte("x"), []byte("/x"), nil, tooManyLabels); err != ErrOverflow { |
| 830 | t.Fatalf("apps too-many-labels error = %v, want ErrOverflow", err) |
| 831 | } |
| 832 | |
| 833 | small := make([]byte, AppsLookupRespHdr+LookupDirEntrySize) |
| 834 | smallBuilder := NewAppsLookupBuilder(small, 1, 0) |
| 835 | if err := smallBuilder.Add(PidLookupKnown, AppsCgroupHostRoot, 0, 1, 0, 0, 0, []byte("x"), nil, nil, nil); err != ErrOverflow { |
| 836 | t.Fatalf("small apps builder add error = %v, want ErrOverflow", err) |
| 837 | } |
| 838 | negativeOffsetBuilder := &AppsLookupBuilder{buf: make([]byte, 512), maxItems: 1, dataOffset: -1} |
| 839 | if err := negativeOffsetBuilder.Add(PidLookupKnown, AppsCgroupHostRoot, 0, 1, 0, 0, 0, []byte("x"), nil, nil, nil); err != ErrOverflow { |
| 840 | t.Fatalf("negative-offset apps builder add error = %v, want ErrOverflow", err) |
| 841 | } |
| 842 | overflowOffsetBuilder := &AppsLookupBuilder{buf: make([]byte, 512), maxItems: 1, dataOffset: maxIntValue() - 32} |
| 843 | if err := overflowOffsetBuilder.Add(PidLookupKnown, AppsCgroupHostRoot, 0, 1, 0, 0, 0, []byte("x"), nil, nil, nil); err != ErrOverflow { |
| 844 | t.Fatalf("overflow-offset apps builder add error = %v, want ErrOverflow", err) |
| 845 | } |
| 846 | } |
| 847 | |
| 848 | func TestAppsLookupUnknownItemCanonicalLayout(t *testing.T) { |
| 849 | var resp [128]byte |
| 850 | builder := NewAppsLookupBuilder(resp[:], 1, 7) |
| 851 | if err := builder.Add(PidLookupUnknown, AppsCgroupKnown, 0, 4321, 0, NipcUIDUnset, 0, nil, nil, nil, nil); err != nil { |
| 852 | t.Fatalf("add unknown apps item: %v", err) |
| 853 | } |
| 854 | total := builder.Finish() |
| 855 | itemStart := appsLookupItemStart(t, resp[:total]) |
| 856 | item := resp[itemStart:total] |
| 857 | |
| 858 | if got := len(item); got != appsLookupUnknownItemSize { |
| 859 | t.Fatalf("unknown item size = %d, want %d", got, appsLookupUnknownItemSize) |
| 860 | } |
| 861 | if got := ne.Uint32(resp[AppsLookupRespHdr+4 : AppsLookupRespHdr+8]); got != appsLookupUnknownItemSize { |
| 862 | t.Fatalf("directory item length = %d, want %d", got, appsLookupUnknownItemSize) |
| 863 | } |
| 864 | if got := ne.Uint32(item[32:36]); got != AppsLookupItemHdr { |
| 865 | t.Fatalf("comm offset = %d, want %d", got, AppsLookupItemHdr) |
| 866 | } |
| 867 | if got := ne.Uint32(item[40:44]); got != AppsLookupItemHdr+1 { |
| 868 | t.Fatalf("path offset = %d, want %d", got, AppsLookupItemHdr+1) |
| 869 | } |
| 870 | if got := ne.Uint32(item[48:52]); got != AppsLookupItemHdr+2 { |
| 871 | t.Fatalf("name offset = %d, want %d", got, AppsLookupItemHdr+2) |
| 872 | } |
| 873 | if item[AppsLookupItemHdr] != 0 || item[AppsLookupItemHdr+1] != 0 || item[AppsLookupItemHdr+2] != 0 { |
| 874 | t.Fatalf("unknown item NUL bytes = %v, want all zero", item[AppsLookupItemHdr:AppsLookupItemHdr+3]) |
| 875 | } |
| 876 | |
| 877 | view, err := DecodeAppsLookupResponse(resp[:total]) |
| 878 | if err != nil { |
| 879 | t.Fatalf("decode unknown apps item: %v", err) |
| 880 | } |
| 881 | got, err := view.Item(0) |
| 882 | if err != nil { |
| 883 | t.Fatalf("read unknown apps item: %v", err) |
| 884 | } |
| 885 | if got.Status != PidLookupUnknown || got.Pid != 4321 || |
| 886 | len(got.Comm.Bytes()) != 0 || len(got.CgroupPath.Bytes()) != 0 || len(got.CgroupName.Bytes()) != 0 { |
| 887 | t.Fatalf("decoded unknown apps item = %+v", got) |
| 888 | } |
| 889 | |
| 890 | bad := append([]byte(nil), resp[:total]...) |
| 891 | bad[itemStart+AppsLookupItemHdr+1] = 'x' |
| 892 | if _, err := DecodeAppsLookupResponse(bad); err != ErrMissingNul { |
| 893 | t.Fatalf("decode missing unknown path NUL error = %v, want ErrMissingNul", err) |
| 894 | } |
| 895 | } |
| 896 | |
| 897 | func TestCgroupsLookupUnknownItemCanonicalLayout(t *testing.T) { |
| 898 | path := []byte("/sys/fs/cgroup/bench/cg-001") |
| 899 | var resp [128]byte |
| 900 | builder := NewCgroupsLookupBuilder(resp[:], 1, 9) |
| 901 | if err := builder.Add(CgroupLookupUnknownRetryLater, 0, path, nil, nil); err != nil { |
| 902 | t.Fatalf("add unknown cgroups item: %v", err) |
| 903 | } |
| 904 | total := builder.Finish() |
| 905 | itemStart := cgroupsLookupItemStart(t, resp[:total]) |
| 906 | item := resp[itemStart:total] |
| 907 | wantSize := cgroupsLookupUnknownFixedBytes + len(path) + 1 |
| 908 | |
| 909 | if got := len(item); got != wantSize { |
| 910 | t.Fatalf("unknown item size = %d, want %d", got, wantSize) |
| 911 | } |
| 912 | if got := ne.Uint32(resp[CgroupsLookupRespHdr+4 : CgroupsLookupRespHdr+8]); got != uint32(wantSize) { |
| 913 | t.Fatalf("directory item length = %d, want %d", got, wantSize) |
| 914 | } |
| 915 | if got := ne.Uint32(item[8:12]); got != CgroupsLookupItemHdr { |
| 916 | t.Fatalf("path offset = %d, want %d", got, CgroupsLookupItemHdr) |
| 917 | } |
| 918 | wantNameOff := CgroupsLookupItemHdr + len(path) + 1 |
| 919 | if got := ne.Uint32(item[16:20]); got != uint32(wantNameOff) { |
| 920 | t.Fatalf("name offset = %d, want %d", got, wantNameOff) |
| 921 | } |
| 922 | if item[CgroupsLookupItemHdr+len(path)] != 0 || item[wantNameOff] != 0 { |
| 923 | t.Fatalf("unknown item NUL bytes are not canonical") |
| 924 | } |
| 925 | |
| 926 | view, err := DecodeCgroupsLookupResponse(resp[:total]) |
| 927 | if err != nil { |
| 928 | t.Fatalf("decode unknown cgroups item: %v", err) |
| 929 | } |
| 930 | got, err := view.Item(0) |
| 931 | if err != nil { |
| 932 | t.Fatalf("read unknown cgroups item: %v", err) |
| 933 | } |
| 934 | if got.Status != CgroupLookupUnknownRetryLater || got.Path.String() != string(path) || |
| 935 | len(got.Name.Bytes()) != 0 || got.LabelCount != 0 { |
| 936 | t.Fatalf("decoded unknown cgroups item = %+v", got) |
| 937 | } |
| 938 | |
| 939 | bad := append([]byte(nil), resp[:total]...) |
| 940 | bad[itemStart+wantNameOff] = 'x' |
| 941 | if _, err := DecodeCgroupsLookupResponse(bad); err != ErrMissingNul { |
| 942 | t.Fatalf("decode missing unknown name NUL error = %v, want ErrMissingNul", err) |
| 943 | } |
| 944 | } |
| 945 | |
| 946 | func TestLookupInternalGuardCoverage(t *testing.T) { |
| 947 | if _, ok := checkedU32Int(-1); ok { |
| 948 | t.Fatalf("checkedU32Int(-1) succeeded") |
| 949 | } |
| 950 | if _, ok := checkedU32Int(int(uint64(^uint32(0)) + 1)); ok { |
| 951 | t.Fatalf("checkedU32Int(uint32 max + 1) succeeded") |
| 952 | } |
| 953 | if _, ok := checkedU16Int(-1); ok { |
| 954 | t.Fatalf("checkedU16Int(-1) succeeded") |
| 955 | } |
| 956 | if _, ok := checkedU16Int(int(^uint16(0)) + 1); ok { |
| 957 | t.Fatalf("checkedU16Int(uint16 max + 1) succeeded") |
| 958 | } |
| 959 | if _, ok := checkedInt(uint64(maxIntValue()) + 1); ok { |
| 960 | t.Fatalf("checkedInt(max + 1) succeeded") |
| 961 | } |
| 962 | if _, ok := checkedAddInt(-1, 0); ok { |
| 963 | t.Fatalf("checkedAddInt negative succeeded") |
| 964 | } |
| 965 | if _, ok := checkedAddInt(maxIntValue(), 1); ok { |
| 966 | t.Fatalf("checkedAddInt overflow succeeded") |
| 967 | } |
| 968 | if _, ok := checkedMulInt(-1, 1); ok { |
| 969 | t.Fatalf("checkedMulInt negative succeeded") |
| 970 | } |
| 971 | if _, ok := checkedMulInt(maxIntValue(), 2); ok { |
| 972 | t.Fatalf("checkedMulInt overflow succeeded") |
| 973 | } |
| 974 | if _, ok := checkedAlign8(-1); ok { |
| 975 | t.Fatalf("checkedAlign8 negative succeeded") |
| 976 | } |
| 977 | if _, ok := checkedAlign8(maxIntValue() - 6); ok { |
| 978 | t.Fatalf("checkedAlign8 overflow succeeded") |
| 979 | } |
| 980 | if _, err := lookupPayloadSlice([]byte{0}, -1, 0, 0); err != ErrOutOfBounds { |
| 981 | t.Fatalf("lookupPayloadSlice negative error = %v, want ErrOutOfBounds", err) |
| 982 | } |
| 983 | if _, err := lookupPayloadSlice([]byte{0}, 0, 0, 2); err != ErrOutOfBounds { |
| 984 | t.Fatalf("lookupPayloadSlice too long error = %v, want ErrOutOfBounds", err) |
| 985 | } |
| 986 | if err := validateLookupDir(make([]byte, 8), maxIntValue(), 1, 0, 0, -1); err != ErrBadItemCount { |
| 987 | t.Fatalf("validateLookupDir bad item count error = %v, want ErrBadItemCount", err) |
| 988 | } |
| 989 | if err := validateLookupDir(make([]byte, 0), 0, 1, 0, 0, -1); err != ErrTruncated { |
| 990 | t.Fatalf("validateLookupDir truncated error = %v, want ErrTruncated", err) |
| 991 | } |
| 992 | var dir [16]byte |
| 993 | ne.PutUint32(dir[0:4], 8) |
| 994 | ne.PutUint32(dir[4:8], 8) |
| 995 | ne.PutUint32(dir[8:12], 0) |
| 996 | ne.PutUint32(dir[12:16], 8) |
| 997 | if err := validateLookupDir(dir[:], 0, 2, 32, 1, -1); err != ErrBadLayout { |
| 998 | t.Fatalf("validateLookupDir overlap error = %v, want ErrBadLayout", err) |
| 999 | } |
| 1000 | |
| 1001 | item := []byte{'a', 0, 'b', 0} |
| 1002 | if _, _, err := lookupString(item, 1, 0, 1); err != ErrOutOfBounds { |
| 1003 | t.Fatalf("lookupString below header error = %v, want ErrOutOfBounds", err) |
| 1004 | } |
| 1005 | if _, _, err := lookupString(item, 0, 3, 2); err != ErrOutOfBounds { |
| 1006 | t.Fatalf("lookupString oob error = %v, want ErrOutOfBounds", err) |
| 1007 | } |
| 1008 | if _, _, err := lookupString(item, 0, 0, 2); err != ErrMissingNul { |
| 1009 | t.Fatalf("lookupString missing nul error = %v, want ErrMissingNul", err) |
| 1010 | } |
| 1011 | if _, _, err := lookupString([]byte{'a', 0, 0}, 0, 0, 2); err != ErrBadLayout { |
| 1012 | t.Fatalf("lookupString interior nul error = %v, want ErrBadLayout", err) |
| 1013 | } |
| 1014 | |
| 1015 | if _, err := lookupLabelAt(make([]byte, LookupLabelEntrySize), 0, 1, -1, 0); err != ErrOutOfBounds { |
| 1016 | t.Fatalf("lookupLabelAt bad table offset error = %v, want ErrOutOfBounds", err) |
| 1017 | } |
| 1018 | |
| 1019 | labelItem := make([]byte, 52) |
| 1020 | ne.PutUint32(labelItem[32:36], 48) |
| 1021 | ne.PutUint32(labelItem[36:40], 1) |
| 1022 | ne.PutUint32(labelItem[40:44], 50) |
| 1023 | ne.PutUint32(labelItem[44:48], 1) |
| 1024 | labelItem[48] = 'k' |
| 1025 | labelItem[49] = 0 |
| 1026 | labelItem[50] = 'v' |
| 1027 | labelItem[51] = 0 |
| 1028 | if _, err := validateLabels(labelItem, 28, 0, 28); err != ErrBadLayout { |
| 1029 | t.Fatalf("validateLabels zero count wrong fixedEnd error = %v, want ErrBadLayout", err) |
| 1030 | } |
| 1031 | if _, err := validateLabels(labelItem, 28, 1, maxIntValue()-6); err != ErrOutOfBounds { |
| 1032 | t.Fatalf("validateLabels align overflow error = %v, want ErrOutOfBounds", err) |
| 1033 | } |
| 1034 | if _, err := validateLabels(labelItem, 28, 1, 60); err != ErrOutOfBounds { |
| 1035 | t.Fatalf("validateLabels table after end error = %v, want ErrOutOfBounds", err) |
| 1036 | } |
| 1037 | badPadding := append([]byte(nil), labelItem...) |
| 1038 | badPadding[28] = 1 |
| 1039 | if _, err := validateLabels(badPadding, 28, 1, 28); err != ErrBadLayout { |
| 1040 | t.Fatalf("validateLabels bad padding error = %v, want ErrBadLayout", err) |
| 1041 | } |
| 1042 | if _, err := validateLabels(labelItem[:40], 28, 1, 28); err != ErrOutOfBounds { |
| 1043 | t.Fatalf("validateLabels table oob error = %v, want ErrOutOfBounds", err) |
| 1044 | } |
| 1045 | badKeyLen := append([]byte(nil), labelItem...) |
| 1046 | ne.PutUint32(badKeyLen[36:40], 0) |
| 1047 | if _, err := validateLabels(badKeyLen, 28, 1, 28); err != ErrBadLayout { |
| 1048 | t.Fatalf("validateLabels bad key length error = %v, want ErrBadLayout", err) |
| 1049 | } |
| 1050 | badKeyOff := append([]byte(nil), labelItem...) |
| 1051 | ne.PutUint32(badKeyOff[32:36], 49) |
| 1052 | if _, err := validateLabels(badKeyOff, 28, 1, 28); err != ErrBadLayout { |
| 1053 | t.Fatalf("validateLabels bad key offset error = %v, want ErrBadLayout", err) |
| 1054 | } |
| 1055 | badValueOff := append([]byte(nil), labelItem...) |
| 1056 | ne.PutUint32(badValueOff[40:44], 49) |
| 1057 | if _, err := validateLabels(badValueOff, 28, 1, 28); err != ErrBadLayout { |
| 1058 | t.Fatalf("validateLabels bad value offset error = %v, want ErrBadLayout", err) |
| 1059 | } |
| 1060 | badValueNul := append([]byte(nil), labelItem...) |
| 1061 | badValueNul[51] = '!' |
| 1062 | if _, err := validateLabels(badValueNul, 28, 1, 28); err != ErrMissingNul { |
| 1063 | t.Fatalf("validateLabels bad value nul error = %v, want ErrMissingNul", err) |
| 1064 | } |
| 1065 | extra := append([]byte(nil), labelItem...) |
| 1066 | extra = append(extra, 0) |
| 1067 | if _, err := validateLabels(extra, 28, 1, 28); err != ErrBadLayout { |
| 1068 | t.Fatalf("validateLabels extra byte error = %v, want ErrBadLayout", err) |
| 1069 | } |
| 1070 | |
| 1071 | var compact [80]byte |
| 1072 | ne.PutUint32(compact[16:20], 40) |
| 1073 | copy(compact[40:44], []byte{1, 2, 3, 4}) |
| 1074 | if n := finishLookupResponse(compact[:], 16, 1, 44, 7); n != 28 { |
| 1075 | t.Fatalf("finishLookupResponse compact = %d, want 28", n) |
| 1076 | } |
| 1077 | var badFinish [80]byte |
| 1078 | ne.PutUint32(badFinish[16:20], 40) |
| 1079 | ne.PutUint32(badFinish[24:28], 32) |
| 1080 | if n := finishLookupResponse(badFinish[:], 16, 2, 48, 7); n != 0 { |
| 1081 | t.Fatalf("finishLookupResponse bad second offset = %d, want 0", n) |
| 1082 | } |
| 1083 | if n := finishLookupResponse(badFinish[:], maxIntValue(), 1, 0, 7); n != 0 { |
| 1084 | t.Fatalf("finishLookupResponse header overflow = %d, want 0", n) |
| 1085 | } |
| 1086 | } |
| 1087 | |
| 1088 | func TestLookupDecodeAndItemErrorCoverage(t *testing.T) { |
| 1089 | if _, err := DecodeCgroupsLookupResponse(make([]byte, CgroupsLookupRespHdr-1)); err != ErrTruncated { |
| 1090 | t.Fatalf("short cgroups response error = %v, want ErrTruncated", err) |
| 1091 | } |
| 1092 | cgResp := make([]byte, CgroupsLookupRespHdr+LookupDirEntrySize) |
| 1093 | ne.PutUint16(cgResp[0:2], 1) |
| 1094 | ne.PutUint32(cgResp[4:8], 1) |
| 1095 | ne.PutUint32(cgResp[CgroupsLookupRespHdr+4:CgroupsLookupRespHdr+8], CgroupsLookupItemHdr) |
| 1096 | if _, err := DecodeCgroupsLookupResponse(cgResp[:CgroupsLookupRespHdr]); err != ErrTruncated { |
| 1097 | t.Fatalf("cgroups response truncated dir error = %v, want ErrTruncated", err) |
| 1098 | } |
| 1099 | if _, err := DecodeCgroupsLookupResponse(cgResp); err != ErrOutOfBounds { |
| 1100 | t.Fatalf("cgroups response missing item error = %v, want ErrOutOfBounds", err) |
| 1101 | } |
| 1102 | cgShortItem := append([]byte(nil), cgResp...) |
| 1103 | ne.PutUint32(cgShortItem[CgroupsLookupRespHdr+4:CgroupsLookupRespHdr+8], CgroupsLookupItemHdr-1) |
| 1104 | cgShortItem = append(cgShortItem, make([]byte, CgroupsLookupItemHdr-1)...) |
| 1105 | if _, err := DecodeCgroupsLookupResponse(cgShortItem); err != ErrBadLayout { |
| 1106 | t.Fatalf("cgroups response short item error = %v, want ErrBadLayout", err) |
| 1107 | } |
| 1108 | if _, err := (&CgroupsLookupResponseView{ItemCount: 1, payload: cgResp}).Item(0); err != ErrOutOfBounds { |
| 1109 | t.Fatalf("manual cgroups item error = %v, want ErrOutOfBounds", err) |
| 1110 | } |
| 1111 | |
| 1112 | cgItem := validCgroupsLookupItemBytes(t) |
| 1113 | for _, tc := range []struct { |
| 1114 | name string |
| 1115 | edit func([]byte) |
| 1116 | want error |
| 1117 | }{ |
| 1118 | { |
| 1119 | name: "short", |
| 1120 | edit: func(b []byte) { |
| 1121 | b = b[:CgroupsLookupItemHdr-1] |
| 1122 | copy(cgItem, b) |
| 1123 | }, |
| 1124 | want: ErrTruncated, |
| 1125 | }, |
| 1126 | { |
| 1127 | name: "bad reserved", |
| 1128 | edit: func(b []byte) { |
| 1129 | ne.PutUint16(b[6:8], 1) |
| 1130 | }, |
| 1131 | want: ErrBadLayout, |
| 1132 | }, |
| 1133 | { |
| 1134 | name: "path below header", |
| 1135 | edit: func(b []byte) { |
| 1136 | ne.PutUint32(b[8:12], 0) |
| 1137 | }, |
| 1138 | want: ErrOutOfBounds, |
| 1139 | }, |
| 1140 | { |
| 1141 | name: "name below header", |
| 1142 | edit: func(b []byte) { |
| 1143 | ne.PutUint32(b[16:20], 0) |
| 1144 | }, |
| 1145 | want: ErrOutOfBounds, |
| 1146 | }, |
| 1147 | { |
| 1148 | name: "label table missing", |
| 1149 | edit: func(b []byte) { |
| 1150 | ne.PutUint16(b[24:26], 2) |
| 1151 | }, |
| 1152 | want: ErrOutOfBounds, |
| 1153 | }, |
| 1154 | } { |
| 1155 | item := validCgroupsLookupItemBytes(t) |
| 1156 | if tc.name == "short" { |
| 1157 | if _, err := decodeCgroupsLookupItem(item[:CgroupsLookupItemHdr-1]); err != tc.want { |
| 1158 | t.Fatalf("decode cgroups item %s error = %v, want %v", tc.name, err, tc.want) |
| 1159 | } |
| 1160 | continue |
| 1161 | } |
| 1162 | tc.edit(item) |
| 1163 | if _, err := decodeCgroupsLookupItem(item); err != tc.want { |
| 1164 | t.Fatalf("decode cgroups item %s error = %v, want %v", tc.name, err, tc.want) |
| 1165 | } |
| 1166 | } |
| 1167 | |
| 1168 | if _, err := DecodeAppsLookupResponse(make([]byte, AppsLookupRespHdr-1)); err != ErrTruncated { |
| 1169 | t.Fatalf("short apps response error = %v, want ErrTruncated", err) |
| 1170 | } |
| 1171 | appsResp := make([]byte, AppsLookupRespHdr+LookupDirEntrySize) |
| 1172 | ne.PutUint16(appsResp[0:2], 1) |
| 1173 | ne.PutUint32(appsResp[4:8], 1) |
| 1174 | ne.PutUint32(appsResp[AppsLookupRespHdr+4:AppsLookupRespHdr+8], AppsLookupItemHdr) |
| 1175 | if _, err := DecodeAppsLookupResponse(appsResp[:AppsLookupRespHdr]); err != ErrTruncated { |
| 1176 | t.Fatalf("apps response truncated dir error = %v, want ErrTruncated", err) |
| 1177 | } |
| 1178 | if _, err := DecodeAppsLookupResponse(appsResp); err != ErrOutOfBounds { |
| 1179 | t.Fatalf("apps response missing item error = %v, want ErrOutOfBounds", err) |
| 1180 | } |
| 1181 | appsShortItem := append([]byte(nil), appsResp...) |
| 1182 | ne.PutUint32(appsShortItem[AppsLookupRespHdr+4:AppsLookupRespHdr+8], AppsLookupItemHdr-1) |
| 1183 | appsShortItem = append(appsShortItem, make([]byte, AppsLookupItemHdr-1)...) |
| 1184 | if _, err := DecodeAppsLookupResponse(appsShortItem); err != ErrBadLayout { |
| 1185 | t.Fatalf("apps response short item error = %v, want ErrBadLayout", err) |
| 1186 | } |
| 1187 | if _, err := (&AppsLookupResponseView{ItemCount: 1, payload: appsResp}).Item(0); err != ErrOutOfBounds { |
| 1188 | t.Fatalf("manual apps item error = %v, want ErrOutOfBounds", err) |
| 1189 | } |
| 1190 | |
| 1191 | for _, tc := range []struct { |
| 1192 | name string |
| 1193 | edit func([]byte) |
| 1194 | want error |
| 1195 | }{ |
| 1196 | { |
| 1197 | name: "short", |
| 1198 | edit: nil, |
| 1199 | want: ErrTruncated, |
| 1200 | }, |
| 1201 | { |
| 1202 | name: "bad reserved", |
| 1203 | edit: func(b []byte) { |
| 1204 | ne.PutUint32(b[20:24], 1) |
| 1205 | }, |
| 1206 | want: ErrBadLayout, |
| 1207 | }, |
| 1208 | { |
| 1209 | name: "comm below header", |
| 1210 | edit: func(b []byte) { |
| 1211 | ne.PutUint32(b[32:36], 0) |
| 1212 | }, |
| 1213 | want: ErrOutOfBounds, |
| 1214 | }, |
| 1215 | { |
| 1216 | name: "path below header", |
| 1217 | edit: func(b []byte) { |
| 1218 | ne.PutUint32(b[40:44], 0) |
| 1219 | }, |
| 1220 | want: ErrOutOfBounds, |
| 1221 | }, |
| 1222 | { |
| 1223 | name: "name below header", |
| 1224 | edit: func(b []byte) { |
| 1225 | ne.PutUint32(b[48:52], 0) |
| 1226 | }, |
| 1227 | want: ErrOutOfBounds, |
| 1228 | }, |
| 1229 | { |
| 1230 | name: "retry with orchestrator", |
| 1231 | edit: func(b []byte) { |
| 1232 | ne.PutUint16(b[6:8], AppsCgroupUnknownRetryLater) |
| 1233 | }, |
| 1234 | want: ErrBadLayout, |
| 1235 | }, |
| 1236 | { |
| 1237 | name: "permanent missing path", |
| 1238 | edit: func(b []byte) { |
| 1239 | ne.PutUint16(b[4:6], 0) |
| 1240 | ne.PutUint16(b[6:8], AppsCgroupUnknownPermanent) |
| 1241 | ne.PutUint32(b[44:48], 0) |
| 1242 | ne.PutUint32(b[52:56], 0) |
| 1243 | ne.PutUint16(b[56:58], 0) |
| 1244 | }, |
| 1245 | want: ErrBadLayout, |
| 1246 | }, |
| 1247 | { |
| 1248 | name: "label table missing", |
| 1249 | edit: func(b []byte) { |
| 1250 | ne.PutUint16(b[56:58], 2) |
| 1251 | }, |
| 1252 | want: ErrOutOfBounds, |
| 1253 | }, |
| 1254 | } { |
| 1255 | item := validAppsLookupItemBytes(t) |
| 1256 | if tc.name == "short" { |
| 1257 | if _, err := decodeAppsLookupItem(item[:AppsLookupItemHdr-1]); err != tc.want { |
| 1258 | t.Fatalf("decode apps item %s error = %v, want %v", tc.name, err, tc.want) |
| 1259 | } |
| 1260 | continue |
| 1261 | } |
| 1262 | tc.edit(item) |
| 1263 | if _, err := decodeAppsLookupItem(item); err != tc.want { |
| 1264 | t.Fatalf("decode apps item %s error = %v, want %v", tc.name, err, tc.want) |
| 1265 | } |
| 1266 | } |
| 1267 | _ = cgItem |
| 1268 | } |
| 1269 | |
| 1270 | func TestLookupResponseDecodeValidationCoverage(t *testing.T) { |
| 1271 | var resp [1024]byte |
| 1272 | |
| 1273 | cg := NewCgroupsLookupBuilder(resp[:], 1, 0) |
| 1274 | if err := cg.Add(CgroupLookupKnown, OrchestratorDocker, []byte("/x"), []byte("name"), nil); err != nil { |
| 1275 | t.Fatalf("add cgroups response: %v", err) |
| 1276 | } |
| 1277 | cgTotal := cg.Finish() |
| 1278 | cgItem := cgroupsLookupItemStart(t, resp[:]) |
| 1279 | |
| 1280 | for _, tc := range []struct { |
| 1281 | name string |
| 1282 | edit func([]byte) |
| 1283 | want error |
| 1284 | }{ |
| 1285 | { |
| 1286 | name: "bad flags", |
| 1287 | edit: func(b []byte) { |
| 1288 | ne.PutUint16(b[2:4], 1) |
| 1289 | }, |
| 1290 | want: ErrBadLayout, |
| 1291 | }, |
| 1292 | { |
| 1293 | name: "bad item layout", |
| 1294 | edit: func(b []byte) { |
| 1295 | ne.PutUint16(b[cgItem:cgItem+2], 2) |
| 1296 | }, |
| 1297 | want: ErrBadLayout, |
| 1298 | }, |
| 1299 | { |
| 1300 | name: "empty path", |
| 1301 | edit: func(b []byte) { |
| 1302 | ne.PutUint32(b[cgItem+12:cgItem+16], 0) |
| 1303 | }, |
| 1304 | want: ErrBadLayout, |
| 1305 | }, |
| 1306 | { |
| 1307 | name: "unknown with metadata", |
| 1308 | edit: func(b []byte) { |
| 1309 | ne.PutUint16(b[cgItem+2:cgItem+4], CgroupLookupUnknownRetryLater) |
| 1310 | }, |
| 1311 | want: ErrBadLayout, |
| 1312 | }, |
| 1313 | { |
| 1314 | name: "overlap", |
| 1315 | edit: func(b []byte) { |
| 1316 | ne.PutUint32(b[cgItem+16:cgItem+20], uint32(CgroupsLookupItemHdr+1)) |
| 1317 | ne.PutUint32(b[cgItem+20:cgItem+24], 1) |
| 1318 | }, |
| 1319 | want: ErrBadLayout, |
| 1320 | }, |
| 1321 | } { |
| 1322 | bad := append([]byte(nil), resp[:cgTotal]...) |
| 1323 | tc.edit(bad) |
| 1324 | if _, err := DecodeCgroupsLookupResponse(bad); err != tc.want { |
| 1325 | t.Fatalf("decode cgroups response %s error = %v, want %v", tc.name, err, tc.want) |
| 1326 | } |
| 1327 | } |
| 1328 | |
| 1329 | apps := NewAppsLookupBuilder(resp[:], 1, 0) |
| 1330 | if err := apps.Add( |
| 1331 | PidLookupKnown, |
| 1332 | AppsCgroupKnown, |
| 1333 | OrchestratorDocker, |
| 1334 | 1234, 1, 1000, 42, |
| 1335 | []byte("nginx"), |
| 1336 | []byte("/docker/abc"), |
| 1337 | []byte("container-a"), |
| 1338 | nil, |
| 1339 | ); err != nil { |
| 1340 | t.Fatalf("add apps response: %v", err) |
| 1341 | } |
| 1342 | appsTotal := apps.Finish() |
| 1343 | appsItem := appsLookupItemStart(t, resp[:]) |
| 1344 | |
| 1345 | for _, tc := range []struct { |
| 1346 | name string |
| 1347 | edit func([]byte) |
| 1348 | want error |
| 1349 | }{ |
| 1350 | { |
| 1351 | name: "bad flags", |
| 1352 | edit: func(b []byte) { |
| 1353 | ne.PutUint16(b[2:4], 1) |
| 1354 | }, |
| 1355 | want: ErrBadLayout, |
| 1356 | }, |
| 1357 | { |
| 1358 | name: "bad item layout", |
| 1359 | edit: func(b []byte) { |
| 1360 | ne.PutUint16(b[appsItem:appsItem+2], 2) |
| 1361 | }, |
| 1362 | want: ErrBadLayout, |
| 1363 | }, |
| 1364 | { |
| 1365 | name: "bad status", |
| 1366 | edit: func(b []byte) { |
| 1367 | ne.PutUint16(b[appsItem+2:appsItem+4], 99) |
| 1368 | }, |
| 1369 | want: ErrBadLayout, |
| 1370 | }, |
| 1371 | { |
| 1372 | name: "bad cgroup status", |
| 1373 | edit: func(b []byte) { |
| 1374 | ne.PutUint16(b[appsItem+6:appsItem+8], 99) |
| 1375 | }, |
| 1376 | want: ErrBadLayout, |
| 1377 | }, |
| 1378 | { |
| 1379 | name: "comm too long", |
| 1380 | edit: func(b []byte) { |
| 1381 | ne.PutUint32(b[appsItem+36:appsItem+40], 16) |
| 1382 | }, |
| 1383 | want: ErrBadLayout, |
| 1384 | }, |
| 1385 | { |
| 1386 | name: "unknown with data", |
| 1387 | edit: func(b []byte) { |
| 1388 | ne.PutUint16(b[appsItem+2:appsItem+4], PidLookupUnknown) |
| 1389 | }, |
| 1390 | want: ErrBadLayout, |
| 1391 | }, |
| 1392 | { |
| 1393 | name: "known empty comm", |
| 1394 | edit: func(b []byte) { |
| 1395 | ne.PutUint32(b[appsItem+36:appsItem+40], 0) |
| 1396 | }, |
| 1397 | want: ErrBadLayout, |
| 1398 | }, |
| 1399 | { |
| 1400 | name: "known empty path", |
| 1401 | edit: func(b []byte) { |
| 1402 | ne.PutUint32(b[appsItem+44:appsItem+48], 0) |
| 1403 | }, |
| 1404 | want: ErrBadLayout, |
| 1405 | }, |
| 1406 | { |
| 1407 | name: "host root with metadata", |
| 1408 | edit: func(b []byte) { |
| 1409 | ne.PutUint16(b[appsItem+6:appsItem+8], AppsCgroupHostRoot) |
| 1410 | }, |
| 1411 | want: ErrBadLayout, |
| 1412 | }, |
| 1413 | { |
| 1414 | name: "overlap", |
| 1415 | edit: func(b []byte) { |
| 1416 | ne.PutUint32(b[appsItem+40:appsItem+44], uint32(AppsLookupItemHdr+1)) |
| 1417 | ne.PutUint32(b[appsItem+44:appsItem+48], 4) |
| 1418 | }, |
| 1419 | want: ErrBadLayout, |
| 1420 | }, |
| 1421 | } { |
| 1422 | bad := append([]byte(nil), resp[:appsTotal]...) |
| 1423 | tc.edit(bad) |
| 1424 | if _, err := DecodeAppsLookupResponse(bad); err != tc.want { |
| 1425 | t.Fatalf("decode apps response %s error = %v, want %v", tc.name, err, tc.want) |
| 1426 | } |
| 1427 | } |
| 1428 | } |
| 1429 | |
| 1430 | func TestLookupDispatchCoverage(t *testing.T) { |
| 1431 | var req [128]byte |
| 1432 | var resp [512]byte |
| 1433 | |
| 1434 | reqLen, err := EncodeCgroupsLookupRequest([][]byte{[]byte("/x"), []byte("/y")}, req[:]) |
| 1435 | if err != nil { |
| 1436 | t.Fatalf("encode cgroups dispatch request: %v", err) |
| 1437 | } |
| 1438 | n, err := DispatchCgroupsLookup(req[:reqLen], resp[:], func(request *CgroupsLookupRequestView, builder *CgroupsLookupBuilder) bool { |
| 1439 | for i := uint32(0); i < request.ItemCount; i++ { |
| 1440 | path, err := request.Item(i) |
| 1441 | if err != nil { |
| 1442 | return false |
| 1443 | } |
| 1444 | if err := builder.Add(CgroupLookupKnown, OrchestratorDocker, path.Bytes(), []byte("name"), nil); err != nil { |
| 1445 | return false |
| 1446 | } |
| 1447 | } |
| 1448 | return true |
| 1449 | }) |
| 1450 | if err != nil || n == 0 { |
| 1451 | t.Fatalf("dispatch cgroups success = n %d err %v", n, err) |
| 1452 | } |
| 1453 | if _, err := DecodeCgroupsLookupResponse(resp[:n]); err != nil { |
| 1454 | t.Fatalf("decode dispatched cgroups response: %v", err) |
| 1455 | } |
| 1456 | n, err = DispatchCgroupsLookup(req[:reqLen], resp[:], func(*CgroupsLookupRequestView, *CgroupsLookupBuilder) bool { |
| 1457 | return false |
| 1458 | }) |
| 1459 | if err != ErrBadLayout || n != 0 { |
| 1460 | t.Fatalf("dispatch cgroups handler false = n %d err %v", n, err) |
| 1461 | } |
| 1462 | n, err = DispatchCgroupsLookup(req[:reqLen], resp[:], func(*CgroupsLookupRequestView, *CgroupsLookupBuilder) bool { |
| 1463 | return true |
| 1464 | }) |
| 1465 | if err != ErrBadItemCount || n != 0 { |
| 1466 | t.Fatalf("dispatch cgroups bad count = n %d err %v", n, err) |
| 1467 | } |
| 1468 | n, err = DispatchCgroupsLookup(req[:reqLen], resp[:], func(_ *CgroupsLookupRequestView, builder *CgroupsLookupBuilder) bool { |
| 1469 | _ = builder.Add(99, 0, []byte("/x"), nil, nil) |
| 1470 | return false |
| 1471 | }) |
| 1472 | if err != ErrBadLayout || n != 0 { |
| 1473 | t.Fatalf("dispatch cgroups builder error = n %d err %v", n, err) |
| 1474 | } |
| 1475 | n, err = DispatchCgroupsLookup(req[:reqLen], resp[:], func(_ *CgroupsLookupRequestView, builder *CgroupsLookupBuilder) bool { |
| 1476 | _ = builder.Add(99, 0, []byte("/x"), nil, nil) |
| 1477 | return true |
| 1478 | }) |
| 1479 | if err != ErrBadLayout || n != 0 { |
| 1480 | t.Fatalf("dispatch cgroups post-handler builder error = n %d err %v", n, err) |
| 1481 | } |
| 1482 | n, err = DispatchCgroupsLookup(req[:reqLen], resp[:], func(request *CgroupsLookupRequestView, builder *CgroupsLookupBuilder) bool { |
| 1483 | builder.itemCount = request.ItemCount |
| 1484 | builder.dataOffset = 0 |
| 1485 | ne.PutUint32(builder.buf[CgroupsLookupRespHdr:CgroupsLookupRespHdr+4], 8) |
| 1486 | return true |
| 1487 | }) |
| 1488 | if err != ErrOverflow || n != 0 { |
| 1489 | t.Fatalf("dispatch cgroups finish error = n %d err %v", n, err) |
| 1490 | } |
| 1491 | if n, err := DispatchCgroupsLookup(req[:CgroupsLookupReqHdr-1], resp[:], nil); err != ErrTruncated || n != 0 { |
| 1492 | t.Fatalf("dispatch cgroups bad request = n %d err %v", n, err) |
| 1493 | } |
| 1494 | |
| 1495 | reqLen, err = EncodeAppsLookupRequest([]uint32{1, 2}, req[:]) |
| 1496 | if err != nil { |
| 1497 | t.Fatalf("encode apps dispatch request: %v", err) |
| 1498 | } |
| 1499 | n, err = DispatchAppsLookup(req[:reqLen], resp[:], func(request *AppsLookupRequestView, builder *AppsLookupBuilder) bool { |
| 1500 | for i := uint32(0); i < request.ItemCount; i++ { |
| 1501 | pid, err := request.Item(i) |
| 1502 | if err != nil { |
| 1503 | return false |
| 1504 | } |
| 1505 | if err := builder.Add(PidLookupKnown, AppsCgroupHostRoot, 0, pid, 0, 0, 0, []byte("proc"), nil, nil, nil); err != nil { |
| 1506 | return false |
| 1507 | } |
| 1508 | } |
| 1509 | return true |
| 1510 | }) |
| 1511 | if err != nil || n == 0 { |
| 1512 | t.Fatalf("dispatch apps success = n %d err %v", n, err) |
| 1513 | } |
| 1514 | if _, err := DecodeAppsLookupResponse(resp[:n]); err != nil { |
| 1515 | t.Fatalf("decode dispatched apps response: %v", err) |
| 1516 | } |
| 1517 | n, err = DispatchAppsLookup(req[:reqLen], resp[:], func(*AppsLookupRequestView, *AppsLookupBuilder) bool { |
| 1518 | return false |
| 1519 | }) |
| 1520 | if err != ErrBadLayout || n != 0 { |
| 1521 | t.Fatalf("dispatch apps handler false = n %d err %v", n, err) |
| 1522 | } |
| 1523 | n, err = DispatchAppsLookup(req[:reqLen], resp[:], func(*AppsLookupRequestView, *AppsLookupBuilder) bool { |
| 1524 | return true |
| 1525 | }) |
| 1526 | if err != ErrBadItemCount || n != 0 { |
| 1527 | t.Fatalf("dispatch apps bad count = n %d err %v", n, err) |
| 1528 | } |
| 1529 | n, err = DispatchAppsLookup(req[:reqLen], resp[:], func(_ *AppsLookupRequestView, builder *AppsLookupBuilder) bool { |
| 1530 | _ = builder.Add(99, 0, 0, 1, 0, 0, 0, []byte("x"), nil, nil, nil) |
| 1531 | return false |
| 1532 | }) |
| 1533 | if err != ErrBadLayout || n != 0 { |
| 1534 | t.Fatalf("dispatch apps builder error = n %d err %v", n, err) |
| 1535 | } |
| 1536 | n, err = DispatchAppsLookup(req[:reqLen], resp[:], func(_ *AppsLookupRequestView, builder *AppsLookupBuilder) bool { |
| 1537 | _ = builder.Add(99, 0, 0, 1, 0, 0, 0, []byte("x"), nil, nil, nil) |
| 1538 | return true |
| 1539 | }) |
| 1540 | if err != ErrBadLayout || n != 0 { |
| 1541 | t.Fatalf("dispatch apps post-handler builder error = n %d err %v", n, err) |
| 1542 | } |
| 1543 | n, err = DispatchAppsLookup(req[:reqLen], resp[:], func(request *AppsLookupRequestView, builder *AppsLookupBuilder) bool { |
| 1544 | builder.itemCount = request.ItemCount |
| 1545 | builder.dataOffset = 0 |
| 1546 | ne.PutUint32(builder.buf[AppsLookupRespHdr:AppsLookupRespHdr+4], 8) |
| 1547 | return true |
| 1548 | }) |
| 1549 | if err != ErrOverflow || n != 0 { |
| 1550 | t.Fatalf("dispatch apps finish error = n %d err %v", n, err) |
| 1551 | } |
| 1552 | if n, err := DispatchAppsLookup(req[:AppsLookupReqHdr-1], resp[:], nil); err != ErrTruncated || n != 0 { |
| 1553 | t.Fatalf("dispatch apps bad request = n %d err %v", n, err) |
| 1554 | } |
| 1555 | } |