1
2
18
19 package devices
20
21 import (
22 "bufio"
23 "bytes"
24 "reflect"
25 "strings"
26 "testing"
27
28 "github.com/opencontainers/runc/libcontainer/devices"
29 )
30
31 func TestDeviceEmulatorLoad(t *testing.T) {
32 tests := []struct {
33 name, list string
34 expected *Emulator
35 }{
36 {
37 name: "BlacklistMode",
38 list: `a *:* rwm`,
39 expected: &Emulator{
40 defaultAllow: true,
41 },
42 },
43 {
44 name: "WhitelistBasic",
45 list: `c 4:2 rw`,
46 expected: &Emulator{
47 defaultAllow: false,
48 rules: deviceRules{
49 {
50 node: devices.CharDevice,
51 major: 4,
52 minor: 2,
53 }: devices.Permissions("rw"),
54 },
55 },
56 },
57 {
58 name: "WhitelistWildcard",
59 list: `b 0:* m`,
60 expected: &Emulator{
61 defaultAllow: false,
62 rules: deviceRules{
63 {
64 node: devices.BlockDevice,
65 major: 0,
66 minor: devices.Wildcard,
67 }: devices.Permissions("m"),
68 },
69 },
70 },
71 {
72 name: "WhitelistDuplicate",
73 list: `c *:* rwm
74 c 1:1 r`,
75 expected: &Emulator{
76 defaultAllow: false,
77 rules: deviceRules{
78 {
79 node: devices.CharDevice,
80 major: devices.Wildcard,
81 minor: devices.Wildcard,
82 }: devices.Permissions("rwm"),
83
84 {
85 node: devices.CharDevice,
86 major: 1,
87 minor: 1,
88 }: devices.Permissions("r"),
89 },
90 },
91 },
92 {
93 name: "WhitelistComplicated",
94 list: `c *:* m
95 b *:* m
96 c 1:3 rwm
97 c 1:5 rwm
98 c 1:7 rwm
99 c 1:8 rwm
100 c 1:9 rwm
101 c 5:0 rwm
102 c 5:2 rwm
103 c 136:* rwm
104 c 10:200 rwm`,
105 expected: &Emulator{
106 defaultAllow: false,
107 rules: deviceRules{
108 {
109 node: devices.CharDevice,
110 major: devices.Wildcard,
111 minor: devices.Wildcard,
112 }: devices.Permissions("m"),
113 {
114 node: devices.BlockDevice,
115 major: devices.Wildcard,
116 minor: devices.Wildcard,
117 }: devices.Permissions("m"),
118 {
119 node: devices.CharDevice,
120 major: 1,
121 minor: 3,
122 }: devices.Permissions("rwm"),
123 {
124 node: devices.CharDevice,
125 major: 1,
126 minor: 5,
127 }: devices.Permissions("rwm"),
128 {
129 node: devices.CharDevice,
130 major: 1,
131 minor: 7,
132 }: devices.Permissions("rwm"),
133 {
134 node: devices.CharDevice,
135 major: 1,
136 minor: 8,
137 }: devices.Permissions("rwm"),
138 {
139 node: devices.CharDevice,
140 major: 1,
141 minor: 9,
142 }: devices.Permissions("rwm"),
143 {
144 node: devices.CharDevice,
145 major: 5,
146 minor: 0,
147 }: devices.Permissions("rwm"),
148 {
149 node: devices.CharDevice,
150 major: 5,
151 minor: 2,
152 }: devices.Permissions("rwm"),
153 {
154 node: devices.CharDevice,
155 major: 136,
156 minor: devices.Wildcard,
157 }: devices.Permissions("rwm"),
158 {
159 node: devices.CharDevice,
160 major: 10,
161 minor: 200,
162 }: devices.Permissions("rwm"),
163 },
164 },
165 },
166
167 {
168 name: "InvalidFieldNumber",
169 list: `b 1:0`,
170 expected: nil,
171 },
172 {
173 name: "InvalidDeviceType",
174 list: `p *:* rwm`,
175 expected: nil,
176 },
177 {
178 name: "InvalidMajorNumber1",
179 list: `p -1:3 rwm`,
180 expected: nil,
181 },
182 {
183 name: "InvalidMajorNumber2",
184 list: `c foo:27 rwm`,
185 expected: nil,
186 },
187 {
188 name: "InvalidMinorNumber1",
189 list: `b 1:-4 rwm`,
190 expected: nil,
191 },
192 {
193 name: "InvalidMinorNumber2",
194 list: `b 1:foo rwm`,
195 expected: nil,
196 },
197 {
198 name: "InvalidPermissions",
199 list: `b 1:7 rwk`,
200 expected: nil,
201 },
202 }
203
204 for _, test := range tests {
205 test := test
206 t.Run(test.name, func(t *testing.T) {
207 list := bytes.NewBufferString(test.list)
208 emu, err := EmulatorFromList(list)
209 if err != nil && test.expected != nil {
210 t.Fatalf("unexpected failure when creating emulator: %v", err)
211 } else if err == nil && test.expected == nil {
212 t.Fatalf("unexpected success when creating emulator: %#v", emu)
213 }
214
215 if !reflect.DeepEqual(emu, test.expected) {
216 t.Errorf("final emulator state mismatch: %#v != %#v", emu, test.expected)
217 }
218 })
219 }
220 }
221
222 func testDeviceEmulatorApply(t *testing.T, baseDefaultAllow bool) {
223 tests := []struct {
224 name string
225 rule devices.Rule
226 base, expected *Emulator
227 }{
228
229 {
230 name: "SwitchToOtherMode",
231 rule: devices.Rule{
232 Type: devices.WildcardDevice,
233 Major: devices.Wildcard,
234 Minor: devices.Wildcard,
235 Permissions: devices.Permissions("rwm"),
236 Allow: !baseDefaultAllow,
237 },
238 base: &Emulator{
239 defaultAllow: baseDefaultAllow,
240 rules: deviceRules{
241 {
242 node: devices.CharDevice,
243 major: devices.Wildcard,
244 minor: devices.Wildcard,
245 }: devices.Permissions("rwm"),
246 {
247 node: devices.CharDevice,
248 major: 1,
249 minor: 1,
250 }: devices.Permissions("r"),
251 },
252 },
253 expected: &Emulator{
254 defaultAllow: !baseDefaultAllow,
255 rules: nil,
256 },
257 },
258 {
259 name: "SwitchToSameModeNoop",
260 rule: devices.Rule{
261 Type: devices.WildcardDevice,
262 Major: devices.Wildcard,
263 Minor: devices.Wildcard,
264 Permissions: devices.Permissions("rwm"),
265 Allow: baseDefaultAllow,
266 },
267 base: &Emulator{
268 defaultAllow: baseDefaultAllow,
269 rules: nil,
270 },
271 expected: &Emulator{
272 defaultAllow: baseDefaultAllow,
273 rules: nil,
274 },
275 },
276 {
277 name: "SwitchToSameMode",
278 rule: devices.Rule{
279 Type: devices.WildcardDevice,
280 Major: devices.Wildcard,
281 Minor: devices.Wildcard,
282 Permissions: devices.Permissions("rwm"),
283 Allow: baseDefaultAllow,
284 },
285 base: &Emulator{
286 defaultAllow: baseDefaultAllow,
287 rules: deviceRules{
288 {
289 node: devices.CharDevice,
290 major: devices.Wildcard,
291 minor: devices.Wildcard,
292 }: devices.Permissions("rwm"),
293 {
294 node: devices.CharDevice,
295 major: 1,
296 minor: 1,
297 }: devices.Permissions("r"),
298 },
299 },
300 expected: &Emulator{
301 defaultAllow: baseDefaultAllow,
302 rules: nil,
303 },
304 },
305
306 {
307 name: "RuleAdditionBasic",
308 rule: devices.Rule{
309 Type: devices.CharDevice,
310 Major: 42,
311 Minor: 1337,
312 Permissions: devices.Permissions("rm"),
313 Allow: !baseDefaultAllow,
314 },
315 base: &Emulator{
316 defaultAllow: baseDefaultAllow,
317 rules: deviceRules{
318 {
319 node: devices.CharDevice,
320 major: 2,
321 minor: 1,
322 }: devices.Permissions("rwm"),
323 {
324 node: devices.BlockDevice,
325 major: 1,
326 minor: 5,
327 }: devices.Permissions("r"),
328 },
329 },
330 expected: &Emulator{
331 defaultAllow: baseDefaultAllow,
332 rules: deviceRules{
333 {
334 node: devices.CharDevice,
335 major: 2,
336 minor: 1,
337 }: devices.Permissions("rwm"),
338 {
339 node: devices.BlockDevice,
340 major: 1,
341 minor: 5,
342 }: devices.Permissions("r"),
343 {
344 node: devices.CharDevice,
345 major: 42,
346 minor: 1337,
347 }: devices.Permissions("rm"),
348 },
349 },
350 },
351 {
352 name: "RuleAdditionBasicDuplicate",
353 rule: devices.Rule{
354 Type: devices.CharDevice,
355 Major: 42,
356 Minor: 1337,
357 Permissions: devices.Permissions("rm"),
358 Allow: !baseDefaultAllow,
359 },
360 base: &Emulator{
361 defaultAllow: baseDefaultAllow,
362 rules: deviceRules{
363 {
364 node: devices.CharDevice,
365 major: 42,
366 minor: devices.Wildcard,
367 }: devices.Permissions("rwm"),
368 },
369 },
370 expected: &Emulator{
371 defaultAllow: baseDefaultAllow,
372 rules: deviceRules{
373 {
374 node: devices.CharDevice,
375 major: 42,
376 minor: devices.Wildcard,
377 }: devices.Permissions("rwm"),
378
379 {
380 node: devices.CharDevice,
381 major: 42,
382 minor: 1337,
383 }: devices.Permissions("rm"),
384 },
385 },
386 },
387 {
388 name: "RuleAdditionBasicDuplicateNoop",
389 rule: devices.Rule{
390 Type: devices.CharDevice,
391 Major: 42,
392 Minor: 1337,
393 Permissions: devices.Permissions("rm"),
394 Allow: !baseDefaultAllow,
395 },
396 base: &Emulator{
397 defaultAllow: baseDefaultAllow,
398 rules: deviceRules{
399 {
400 node: devices.CharDevice,
401 major: 42,
402 minor: 1337,
403 }: devices.Permissions("rm"),
404 },
405 },
406 expected: &Emulator{
407 defaultAllow: baseDefaultAllow,
408 rules: deviceRules{
409 {
410 node: devices.CharDevice,
411 major: 42,
412 minor: 1337,
413 }: devices.Permissions("rm"),
414 },
415 },
416 },
417 {
418 name: "RuleAdditionMerge",
419 rule: devices.Rule{
420 Type: devices.BlockDevice,
421 Major: 5,
422 Minor: 12,
423 Permissions: devices.Permissions("rm"),
424 Allow: !baseDefaultAllow,
425 },
426 base: &Emulator{
427 defaultAllow: baseDefaultAllow,
428 rules: deviceRules{
429 {
430 node: devices.CharDevice,
431 major: 2,
432 minor: 1,
433 }: devices.Permissions("rwm"),
434 {
435 node: devices.BlockDevice,
436 major: 5,
437 minor: 12,
438 }: devices.Permissions("rw"),
439 },
440 },
441 expected: &Emulator{
442 defaultAllow: baseDefaultAllow,
443 rules: deviceRules{
444 {
445 node: devices.CharDevice,
446 major: 2,
447 minor: 1,
448 }: devices.Permissions("rwm"),
449 {
450 node: devices.BlockDevice,
451 major: 5,
452 minor: 12,
453 }: devices.Permissions("rwm"),
454 },
455 },
456 },
457 {
458 name: "RuleAdditionMergeWildcard",
459 rule: devices.Rule{
460 Type: devices.BlockDevice,
461 Major: 5,
462 Minor: devices.Wildcard,
463 Permissions: devices.Permissions("rm"),
464 Allow: !baseDefaultAllow,
465 },
466 base: &Emulator{
467 defaultAllow: baseDefaultAllow,
468 rules: deviceRules{
469 {
470 node: devices.CharDevice,
471 major: 2,
472 minor: 1,
473 }: devices.Permissions("rwm"),
474 {
475 node: devices.BlockDevice,
476 major: 5,
477 minor: devices.Wildcard,
478 }: devices.Permissions("rw"),
479 },
480 },
481 expected: &Emulator{
482 defaultAllow: baseDefaultAllow,
483 rules: deviceRules{
484 {
485 node: devices.CharDevice,
486 major: 2,
487 minor: 1,
488 }: devices.Permissions("rwm"),
489 {
490 node: devices.BlockDevice,
491 major: 5,
492 minor: devices.Wildcard,
493 }: devices.Permissions("rwm"),
494 },
495 },
496 },
497 {
498 name: "RuleAdditionMergeNoop",
499 rule: devices.Rule{
500 Type: devices.BlockDevice,
501 Major: 5,
502 Minor: 12,
503 Permissions: devices.Permissions("r"),
504 Allow: !baseDefaultAllow,
505 },
506 base: &Emulator{
507 defaultAllow: baseDefaultAllow,
508 rules: deviceRules{
509 {
510 node: devices.CharDevice,
511 major: 2,
512 minor: 1,
513 }: devices.Permissions("rwm"),
514 {
515 node: devices.BlockDevice,
516 major: 5,
517 minor: 12,
518 }: devices.Permissions("rw"),
519 },
520 },
521 expected: &Emulator{
522 defaultAllow: baseDefaultAllow,
523 rules: deviceRules{
524 {
525 node: devices.CharDevice,
526 major: 2,
527 minor: 1,
528 }: devices.Permissions("rwm"),
529 {
530 node: devices.BlockDevice,
531 major: 5,
532 minor: 12,
533 }: devices.Permissions("rw"),
534 },
535 },
536 },
537
538 {
539 name: "RuleRemovalBasic",
540 rule: devices.Rule{
541 Type: devices.CharDevice,
542 Major: 42,
543 Minor: 1337,
544 Permissions: devices.Permissions("rm"),
545 Allow: baseDefaultAllow,
546 },
547 base: &Emulator{
548 defaultAllow: baseDefaultAllow,
549 rules: deviceRules{
550 {
551 node: devices.CharDevice,
552 major: 42,
553 minor: 1337,
554 }: devices.Permissions("rm"),
555 {
556 node: devices.BlockDevice,
557 major: 1,
558 minor: 5,
559 }: devices.Permissions("r"),
560 },
561 },
562 expected: &Emulator{
563 defaultAllow: baseDefaultAllow,
564 rules: deviceRules{
565 {
566 node: devices.BlockDevice,
567 major: 1,
568 minor: 5,
569 }: devices.Permissions("r"),
570 },
571 },
572 },
573 {
574 name: "RuleRemovalNonexistent",
575 rule: devices.Rule{
576 Type: devices.CharDevice,
577 Major: 4,
578 Minor: 1,
579 Permissions: devices.Permissions("rw"),
580 Allow: baseDefaultAllow,
581 },
582 base: &Emulator{
583 defaultAllow: baseDefaultAllow,
584 rules: deviceRules{
585 {
586 node: devices.BlockDevice,
587 major: 1,
588 minor: 5,
589 }: devices.Permissions("r"),
590 },
591 },
592 expected: &Emulator{
593 defaultAllow: baseDefaultAllow,
594 rules: deviceRules{
595 {
596 node: devices.BlockDevice,
597 major: 1,
598 minor: 5,
599 }: devices.Permissions("r"),
600 },
601 },
602 },
603 {
604 name: "RuleRemovalFull",
605 rule: devices.Rule{
606 Type: devices.CharDevice,
607 Major: 42,
608 Minor: 1337,
609 Permissions: devices.Permissions("rw"),
610 Allow: baseDefaultAllow,
611 },
612 base: &Emulator{
613 defaultAllow: baseDefaultAllow,
614 rules: deviceRules{
615 {
616 node: devices.CharDevice,
617 major: 42,
618 minor: 1337,
619 }: devices.Permissions("w"),
620 {
621 node: devices.BlockDevice,
622 major: 1,
623 minor: 5,
624 }: devices.Permissions("r"),
625 },
626 },
627 expected: &Emulator{
628 defaultAllow: baseDefaultAllow,
629 rules: deviceRules{
630 {
631 node: devices.BlockDevice,
632 major: 1,
633 minor: 5,
634 }: devices.Permissions("r"),
635 },
636 },
637 },
638 {
639 name: "RuleRemovalPartial",
640 rule: devices.Rule{
641 Type: devices.CharDevice,
642 Major: 42,
643 Minor: 1337,
644 Permissions: devices.Permissions("r"),
645 Allow: baseDefaultAllow,
646 },
647 base: &Emulator{
648 defaultAllow: baseDefaultAllow,
649 rules: deviceRules{
650 {
651 node: devices.CharDevice,
652 major: 42,
653 minor: 1337,
654 }: devices.Permissions("rm"),
655 {
656 node: devices.BlockDevice,
657 major: 1,
658 minor: 5,
659 }: devices.Permissions("r"),
660 },
661 },
662 expected: &Emulator{
663 defaultAllow: baseDefaultAllow,
664 rules: deviceRules{
665 {
666 node: devices.CharDevice,
667 major: 42,
668 minor: 1337,
669 }: devices.Permissions("m"),
670 {
671 node: devices.BlockDevice,
672 major: 1,
673 minor: 5,
674 }: devices.Permissions("r"),
675 },
676 },
677 },
678
679
680 {
681 name: "RuleRemovalWildcardPunchoutImpossible",
682 rule: devices.Rule{
683 Type: devices.CharDevice,
684 Major: 42,
685 Minor: 1337,
686 Permissions: devices.Permissions("r"),
687 Allow: baseDefaultAllow,
688 },
689 base: &Emulator{
690 defaultAllow: baseDefaultAllow,
691 rules: deviceRules{
692 {
693 node: devices.CharDevice,
694 major: 42,
695 minor: devices.Wildcard,
696 }: devices.Permissions("rm"),
697 {
698 node: devices.CharDevice,
699 major: 42,
700 minor: 1337,
701 }: devices.Permissions("r"),
702 },
703 },
704 expected: nil,
705 },
706 {
707 name: "RuleRemovalWildcardPunchoutPossible",
708 rule: devices.Rule{
709 Type: devices.CharDevice,
710 Major: 42,
711 Minor: 1337,
712 Permissions: devices.Permissions("r"),
713 Allow: baseDefaultAllow,
714 },
715 base: &Emulator{
716 defaultAllow: baseDefaultAllow,
717 rules: deviceRules{
718 {
719 node: devices.CharDevice,
720 major: 42,
721 minor: devices.Wildcard,
722 }: devices.Permissions("wm"),
723 {
724 node: devices.CharDevice,
725 major: 42,
726 minor: 1337,
727 }: devices.Permissions("r"),
728 },
729 },
730 expected: &Emulator{
731 defaultAllow: baseDefaultAllow,
732 rules: deviceRules{
733 {
734 node: devices.CharDevice,
735 major: 42,
736 minor: devices.Wildcard,
737 }: devices.Permissions("wm"),
738 },
739 },
740 },
741 }
742
743 for _, test := range tests {
744 test := test
745 t.Run(test.name, func(t *testing.T) {
746 err := test.base.Apply(test.rule)
747 if err != nil && test.expected != nil {
748 t.Fatalf("unexpected failure when applying apply rule: %v", err)
749 } else if err == nil && test.expected == nil {
750 t.Fatalf("unexpected success when applying apply rule: %#v", test.base)
751 }
752
753 if test.expected != nil && !reflect.DeepEqual(test.base, test.expected) {
754 t.Errorf("final emulator state mismatch: %#v != %#v", test.base, test.expected)
755 }
756 })
757 }
758 }
759
760 func TestDeviceEmulatorWhitelistApply(t *testing.T) {
761 testDeviceEmulatorApply(t, false)
762 }
763
764 func TestDeviceEmulatorBlacklistApply(t *testing.T) {
765 testDeviceEmulatorApply(t, true)
766 }
767
768 func testDeviceEmulatorTransition(t *testing.T, sourceDefaultAllow bool) {
769 tests := []struct {
770 name string
771 source, target *Emulator
772 expected []*devices.Rule
773 }{
774
775 {
776 name: "Noop",
777 source: &Emulator{
778 defaultAllow: sourceDefaultAllow,
779 rules: deviceRules{
780 {
781 node: devices.CharDevice,
782 major: 42,
783 minor: devices.Wildcard,
784 }: devices.Permissions("wm"),
785 },
786 },
787 target: &Emulator{
788 defaultAllow: sourceDefaultAllow,
789 rules: deviceRules{
790 {
791 node: devices.CharDevice,
792 major: 42,
793 minor: devices.Wildcard,
794 }: devices.Permissions("wm"),
795 },
796 },
797
798 expected: nil,
799 },
800
801 {
802 name: "SwitchToOtherMode",
803 source: &Emulator{
804 defaultAllow: sourceDefaultAllow,
805 rules: deviceRules{
806 {
807 node: devices.CharDevice,
808 major: 1,
809 minor: 2,
810 }: devices.Permissions("rwm"),
811 },
812 },
813 target: &Emulator{
814 defaultAllow: !sourceDefaultAllow,
815 rules: deviceRules{
816 {
817 node: devices.BlockDevice,
818 major: 42,
819 minor: devices.Wildcard,
820 }: devices.Permissions("wm"),
821 },
822 },
823 expected: []*devices.Rule{
824
825 {
826 Type: devices.WildcardDevice,
827 Major: devices.Wildcard,
828 Minor: devices.Wildcard,
829 Permissions: devices.Permissions("rwm"),
830 Allow: !sourceDefaultAllow,
831 },
832
833 {
834 Type: devices.BlockDevice,
835 Major: 42,
836 Minor: devices.Wildcard,
837 Permissions: devices.Permissions("wm"),
838 Allow: sourceDefaultAllow,
839 },
840 },
841 },
842
843 {
844 name: "RuleAddition",
845 source: &Emulator{
846 defaultAllow: sourceDefaultAllow,
847 rules: deviceRules{
848 {
849 node: devices.CharDevice,
850 major: 1,
851 minor: 2,
852 }: devices.Permissions("rwm"),
853 },
854 },
855 target: &Emulator{
856 defaultAllow: sourceDefaultAllow,
857 rules: deviceRules{
858 {
859 node: devices.CharDevice,
860 major: 1,
861 minor: 2,
862 }: devices.Permissions("rwm"),
863 {
864 node: devices.BlockDevice,
865 major: 42,
866 minor: 1337,
867 }: devices.Permissions("rwm"),
868 },
869 },
870 expected: []*devices.Rule{
871 {
872 Type: devices.BlockDevice,
873 Major: 42,
874 Minor: 1337,
875 Permissions: devices.Permissions("rwm"),
876 Allow: !sourceDefaultAllow,
877 },
878 },
879 },
880 {
881 name: "RuleRemoval",
882 source: &Emulator{
883 defaultAllow: sourceDefaultAllow,
884 rules: deviceRules{
885 {
886 node: devices.CharDevice,
887 major: 1,
888 minor: 2,
889 }: devices.Permissions("rwm"),
890 {
891 node: devices.BlockDevice,
892 major: 42,
893 minor: 1337,
894 }: devices.Permissions("rwm"),
895 },
896 },
897 target: &Emulator{
898 defaultAllow: sourceDefaultAllow,
899 rules: deviceRules{
900 {
901 node: devices.CharDevice,
902 major: 1,
903 minor: 2,
904 }: devices.Permissions("rwm"),
905 },
906 },
907 expected: []*devices.Rule{
908 {
909 Type: devices.BlockDevice,
910 Major: 42,
911 Minor: 1337,
912 Permissions: devices.Permissions("rwm"),
913 Allow: sourceDefaultAllow,
914 },
915 },
916 },
917 {
918 name: "RuleMultipleAdditionRemoval",
919 source: &Emulator{
920 defaultAllow: sourceDefaultAllow,
921 rules: deviceRules{
922 {
923 node: devices.CharDevice,
924 major: 1,
925 minor: 2,
926 }: devices.Permissions("rwm"),
927 {
928 node: devices.BlockDevice,
929 major: 3,
930 minor: 9,
931 }: devices.Permissions("rw"),
932 },
933 },
934 target: &Emulator{
935 defaultAllow: sourceDefaultAllow,
936 rules: deviceRules{
937 {
938 node: devices.CharDevice,
939 major: 1,
940 minor: 2,
941 }: devices.Permissions("rwm"),
942 },
943 },
944 expected: []*devices.Rule{
945 {
946 Type: devices.BlockDevice,
947 Major: 3,
948 Minor: 9,
949 Permissions: devices.Permissions("rw"),
950 Allow: sourceDefaultAllow,
951 },
952 },
953 },
954
955 {
956 name: "RulePartialAddition",
957 source: &Emulator{
958 defaultAllow: sourceDefaultAllow,
959 rules: deviceRules{
960 {
961 node: devices.CharDevice,
962 major: 1,
963 minor: 2,
964 }: devices.Permissions("r"),
965 },
966 },
967 target: &Emulator{
968 defaultAllow: sourceDefaultAllow,
969 rules: deviceRules{
970 {
971 node: devices.CharDevice,
972 major: 1,
973 minor: 2,
974 }: devices.Permissions("rwm"),
975 },
976 },
977 expected: []*devices.Rule{
978 {
979 Type: devices.CharDevice,
980 Major: 1,
981 Minor: 2,
982 Permissions: devices.Permissions("wm"),
983 Allow: !sourceDefaultAllow,
984 },
985 },
986 },
987 {
988 name: "RulePartialRemoval",
989 source: &Emulator{
990 defaultAllow: sourceDefaultAllow,
991 rules: deviceRules{
992 {
993 node: devices.CharDevice,
994 major: 1,
995 minor: 2,
996 }: devices.Permissions("rw"),
997 },
998 },
999 target: &Emulator{
1000 defaultAllow: sourceDefaultAllow,
1001 rules: deviceRules{
1002 {
1003 node: devices.CharDevice,
1004 major: 1,
1005 minor: 2,
1006 }: devices.Permissions("w"),
1007 },
1008 },
1009 expected: []*devices.Rule{
1010 {
1011 Type: devices.CharDevice,
1012 Major: 1,
1013 Minor: 2,
1014 Permissions: devices.Permissions("r"),
1015 Allow: sourceDefaultAllow,
1016 },
1017 },
1018 },
1019 {
1020 name: "RulePartialBoth",
1021 source: &Emulator{
1022 defaultAllow: sourceDefaultAllow,
1023 rules: deviceRules{
1024 {
1025 node: devices.CharDevice,
1026 major: 1,
1027 minor: 2,
1028 }: devices.Permissions("rw"),
1029 },
1030 },
1031 target: &Emulator{
1032 defaultAllow: sourceDefaultAllow,
1033 rules: deviceRules{
1034 {
1035 node: devices.CharDevice,
1036 major: 1,
1037 minor: 2,
1038 }: devices.Permissions("rm"),
1039 },
1040 },
1041 expected: []*devices.Rule{
1042 {
1043 Type: devices.CharDevice,
1044 Major: 1,
1045 Minor: 2,
1046 Permissions: devices.Permissions("w"),
1047 Allow: sourceDefaultAllow,
1048 },
1049 {
1050 Type: devices.CharDevice,
1051 Major: 1,
1052 Minor: 2,
1053 Permissions: devices.Permissions("m"),
1054 Allow: !sourceDefaultAllow,
1055 },
1056 },
1057 },
1058 }
1059
1060 for _, test := range tests {
1061 test := test
1062 t.Run(test.name, func(t *testing.T) {
1063
1064
1065
1066
1067 if sourceDefaultAllow && test.source.defaultAllow == test.target.defaultAllow {
1068 test.expected = []*devices.Rule{{
1069 Type: devices.WildcardDevice,
1070 Major: devices.Wildcard,
1071 Minor: devices.Wildcard,
1072 Permissions: devices.Permissions("rwm"),
1073 Allow: test.target.defaultAllow,
1074 }}
1075 for _, rule := range test.target.rules.orderedEntries() {
1076 test.expected = append(test.expected, &devices.Rule{
1077 Type: rule.meta.node,
1078 Major: rule.meta.major,
1079 Minor: rule.meta.minor,
1080 Permissions: rule.perms,
1081 Allow: !test.target.defaultAllow,
1082 })
1083 }
1084 }
1085
1086 rules, err := test.source.Transition(test.target)
1087 if err != nil {
1088 t.Fatalf("unexpected error while calculating transition rules: %#v", err)
1089 }
1090
1091 if !reflect.DeepEqual(rules, test.expected) {
1092 t.Errorf("rules don't match expected set: %#v != %#v", rules, test.expected)
1093 }
1094
1095
1096
1097
1098 for _, rule := range rules {
1099 if err := test.source.Apply(*rule); err != nil {
1100 t.Fatalf("error while applying transition rule [%#v]: %v", rule, err)
1101 }
1102 }
1103 if !reflect.DeepEqual(test.source, test.target) {
1104 t.Errorf("transition incomplete after applying all rules: %#v != %#v", test.source, test.target)
1105 }
1106 })
1107 }
1108 }
1109
1110 func TestDeviceEmulatorTransitionFromBlacklist(t *testing.T) {
1111 testDeviceEmulatorTransition(t, true)
1112 }
1113
1114 func TestDeviceEmulatorTransitionFromWhitelist(t *testing.T) {
1115 testDeviceEmulatorTransition(t, false)
1116 }
1117
1118 func BenchmarkParseLine(b *testing.B) {
1119 list := `c *:* m
1120 b *:* m
1121 c 1:3 rwm
1122 c 1:5 rwm
1123 c 1:7 rwm
1124 c 1:8 rwm
1125 c 1:9 rwm
1126 c 5:0 rwm
1127 c 5:2 rwm
1128 c 136:* rwm
1129 c 10:200 rwm`
1130
1131 var r *deviceRule
1132 var err error
1133 for i := 0; i < b.N; i++ {
1134 s := bufio.NewScanner(strings.NewReader(list))
1135 for s.Scan() {
1136 line := s.Text()
1137 r, err = parseLine(line)
1138 }
1139 if err := s.Err(); err != nil {
1140 b.Fatal(err)
1141 }
1142 }
1143 b.Logf("rule: %v, err: %v", r, err)
1144 }
1145
View as plain text