master
go 1,555 lines 49 KB
Raw
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 }