github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/libcontainer/cgroups/devices/devicefilter_test.go (about)

     1  package devices
     2  
     3  import (
     4  	"strings"
     5  	"testing"
     6  
     7  	"github.com/opencontainers/runc/libcontainer/devices"
     8  	"github.com/opencontainers/runc/libcontainer/specconv"
     9  )
    10  
    11  func hash(s, comm string) string {
    12  	var res []string
    13  	for _, l := range strings.Split(s, "\n") {
    14  		trimmed := strings.TrimSpace(l)
    15  		if trimmed == "" || strings.HasPrefix(trimmed, comm) {
    16  			continue
    17  		}
    18  		res = append(res, trimmed)
    19  	}
    20  	return strings.Join(res, "\n")
    21  }
    22  
    23  func testDeviceFilter(t testing.TB, devices []*devices.Rule, expectedStr string) {
    24  	insts, _, err := deviceFilter(devices)
    25  	if err != nil {
    26  		t.Fatalf("%s: %v (devices: %+v)", t.Name(), err, devices)
    27  	}
    28  	s := insts.String()
    29  	if expectedStr != "" {
    30  		hashed := hash(s, "//")
    31  		expectedHashed := hash(expectedStr, "//")
    32  		if expectedHashed != hashed {
    33  			t.Fatalf("expected:\n%q\ngot\n%q", expectedHashed, hashed)
    34  		}
    35  	}
    36  }
    37  
    38  func TestDeviceFilter_Nil(t *testing.T) {
    39  	expected := `
    40  // load parameters into registers
    41          0: LdXMemW dst: r2 src: r1 off: 0 imm: 0
    42          1: AndImm32 dst: r2 imm: 65535
    43          2: LdXMemW dst: r3 src: r1 off: 0 imm: 0
    44          3: RShImm32 dst: r3 imm: 16
    45          4: LdXMemW dst: r4 src: r1 off: 4 imm: 0
    46          5: LdXMemW dst: r5 src: r1 off: 8 imm: 0
    47  block-0:
    48  // return 0 (reject)
    49          6: MovImm32 dst: r0 imm: 0
    50          7: Exit
    51  	`
    52  	testDeviceFilter(t, nil, expected)
    53  }
    54  
    55  func TestDeviceFilter_BuiltInAllowList(t *testing.T) {
    56  	expected := `
    57  // load parameters into registers
    58          0: LdXMemW dst: r2 src: r1 off: 0 imm: 0
    59          1: AndImm32 dst: r2 imm: 65535
    60          2: LdXMemW dst: r3 src: r1 off: 0 imm: 0
    61          3: RShImm32 dst: r3 imm: 16
    62          4: LdXMemW dst: r4 src: r1 off: 4 imm: 0
    63          5: LdXMemW dst: r5 src: r1 off: 8 imm: 0
    64  block-0:
    65  // (b, wildcard, wildcard, m, true)
    66          6: JNEImm dst: r2 off: -1 imm: 1 <block-1>
    67          7: MovReg32 dst: r1 src: r3
    68          8: AndImm32 dst: r1 imm: 1
    69          9: JNEReg dst: r1 off: -1 src: r3 <block-1>
    70          10: MovImm32 dst: r0 imm: 1
    71          11: Exit
    72  block-1:
    73  // (c, wildcard, wildcard, m, true)
    74          12: JNEImm dst: r2 off: -1 imm: 2 <block-2>
    75          13: MovReg32 dst: r1 src: r3
    76          14: AndImm32 dst: r1 imm: 1
    77          15: JNEReg dst: r1 off: -1 src: r3 <block-2>
    78          16: MovImm32 dst: r0 imm: 1
    79          17: Exit
    80  block-2:
    81          18: JNEImm dst: r2 off: -1 imm: 2 <block-3>
    82          19: JNEImm dst: r4 off: -1 imm: 1 <block-3>
    83          20: JNEImm dst: r5 off: -1 imm: 3 <block-3>
    84          21: MovImm32 dst: r0 imm: 1
    85          22: Exit
    86  block-3:
    87          23: JNEImm dst: r2 off: -1 imm: 2 <block-4>
    88          24: JNEImm dst: r4 off: -1 imm: 1 <block-4>
    89          25: JNEImm dst: r5 off: -1 imm: 5 <block-4>
    90          26: MovImm32 dst: r0 imm: 1
    91          27: Exit
    92  block-4:
    93          28: JNEImm dst: r2 off: -1 imm: 2 <block-5>
    94          29: JNEImm dst: r4 off: -1 imm: 1 <block-5>
    95          30: JNEImm dst: r5 off: -1 imm: 7 <block-5>
    96          31: MovImm32 dst: r0 imm: 1
    97          32: Exit
    98  block-5:
    99          33: JNEImm dst: r2 off: -1 imm: 2 <block-6>
   100          34: JNEImm dst: r4 off: -1 imm: 1 <block-6>
   101          35: JNEImm dst: r5 off: -1 imm: 8 <block-6>
   102          36: MovImm32 dst: r0 imm: 1
   103          37: Exit
   104  block-6:
   105          38: JNEImm dst: r2 off: -1 imm: 2 <block-7>
   106          39: JNEImm dst: r4 off: -1 imm: 1 <block-7>
   107          40: JNEImm dst: r5 off: -1 imm: 9 <block-7>
   108          41: MovImm32 dst: r0 imm: 1
   109          42: Exit
   110  block-7:
   111          43: JNEImm dst: r2 off: -1 imm: 2 <block-8>
   112          44: JNEImm dst: r4 off: -1 imm: 5 <block-8>
   113          45: JNEImm dst: r5 off: -1 imm: 0 <block-8>
   114          46: MovImm32 dst: r0 imm: 1
   115          47: Exit
   116  block-8:
   117          48: JNEImm dst: r2 off: -1 imm: 2 <block-9>
   118          49: JNEImm dst: r4 off: -1 imm: 5 <block-9>
   119          50: JNEImm dst: r5 off: -1 imm: 2 <block-9>
   120          51: MovImm32 dst: r0 imm: 1
   121          52: Exit
   122  block-9:
   123  // /dev/pts (c, 136, wildcard, rwm, true)
   124          53: JNEImm dst: r2 off: -1 imm: 2 <block-10>
   125          54: JNEImm dst: r4 off: -1 imm: 136 <block-10>
   126          55: MovImm32 dst: r0 imm: 1
   127          56: Exit
   128  block-10:
   129          57: MovImm32 dst: r0 imm: 0
   130          58: Exit
   131  `
   132  	var devices []*devices.Rule
   133  	for _, device := range specconv.AllowedDevices {
   134  		devices = append(devices, &device.Rule)
   135  	}
   136  	testDeviceFilter(t, devices, expected)
   137  }
   138  
   139  func TestDeviceFilter_Privileged(t *testing.T) {
   140  	devices := []*devices.Rule{
   141  		{
   142  			Type:        'a',
   143  			Major:       -1,
   144  			Minor:       -1,
   145  			Permissions: "rwm",
   146  			Allow:       true,
   147  		},
   148  	}
   149  	expected := `
   150  // load parameters into registers
   151          0: LdXMemW dst: r2 src: r1 off: 0 imm: 0
   152          1: AndImm32 dst: r2 imm: 65535
   153          2: LdXMemW dst: r3 src: r1 off: 0 imm: 0
   154          3: RShImm32 dst: r3 imm: 16
   155          4: LdXMemW dst: r4 src: r1 off: 4 imm: 0
   156          5: LdXMemW dst: r5 src: r1 off: 8 imm: 0
   157  block-0:
   158  // return 1 (accept)
   159          6: MovImm32 dst: r0 imm: 1
   160          7: Exit
   161  	`
   162  	testDeviceFilter(t, devices, expected)
   163  }
   164  
   165  func TestDeviceFilter_PrivilegedExceptSingleDevice(t *testing.T) {
   166  	devices := []*devices.Rule{
   167  		{
   168  			Type:        'a',
   169  			Major:       -1,
   170  			Minor:       -1,
   171  			Permissions: "rwm",
   172  			Allow:       true,
   173  		},
   174  		{
   175  			Type:        'b',
   176  			Major:       8,
   177  			Minor:       0,
   178  			Permissions: "rwm",
   179  			Allow:       false,
   180  		},
   181  	}
   182  	expected := `
   183  // load parameters into registers
   184           0: LdXMemW dst: r2 src: r1 off: 0 imm: 0
   185           1: AndImm32 dst: r2 imm: 65535
   186           2: LdXMemW dst: r3 src: r1 off: 0 imm: 0
   187           3: RShImm32 dst: r3 imm: 16
   188           4: LdXMemW dst: r4 src: r1 off: 4 imm: 0
   189           5: LdXMemW dst: r5 src: r1 off: 8 imm: 0
   190  block-0:
   191  // return 0 (reject) if type==b && major == 8 && minor == 0
   192           6: JNEImm dst: r2 off: -1 imm: 1 <block-1>
   193           7: JNEImm dst: r4 off: -1 imm: 8 <block-1>
   194           8: JNEImm dst: r5 off: -1 imm: 0 <block-1>
   195           9: MovImm32 dst: r0 imm: 0
   196          10: Exit
   197  block-1:
   198  // return 1 (accept)
   199          11: MovImm32 dst: r0 imm: 1
   200          12: Exit
   201  `
   202  	testDeviceFilter(t, devices, expected)
   203  }
   204  
   205  func TestDeviceFilter_Weird(t *testing.T) {
   206  	devices := []*devices.Rule{
   207  		{
   208  			Type:        'b',
   209  			Major:       8,
   210  			Minor:       1,
   211  			Permissions: "rwm",
   212  			Allow:       false,
   213  		},
   214  		{
   215  			Type:        'a',
   216  			Major:       -1,
   217  			Minor:       -1,
   218  			Permissions: "rwm",
   219  			Allow:       true,
   220  		},
   221  		{
   222  			Type:        'b',
   223  			Major:       8,
   224  			Minor:       2,
   225  			Permissions: "rwm",
   226  			Allow:       false,
   227  		},
   228  	}
   229  	// 8/1 is allowed, 8/2 is not allowed.
   230  	// This conforms to runc v1.0.0-rc.9 (cgroup1) behavior.
   231  	expected := `
   232  // load parameters into registers
   233           0: LdXMemW dst: r2 src: r1 off: 0 imm: 0
   234           1: AndImm32 dst: r2 imm: 65535
   235           2: LdXMemW dst: r3 src: r1 off: 0 imm: 0
   236           3: RShImm32 dst: r3 imm: 16
   237           4: LdXMemW dst: r4 src: r1 off: 4 imm: 0
   238           5: LdXMemW dst: r5 src: r1 off: 8 imm: 0
   239  block-0:
   240  // return 0 (reject) if type==b && major == 8 && minor == 2
   241           6: JNEImm dst: r2 off: -1 imm: 1 <block-1>
   242           7: JNEImm dst: r4 off: -1 imm: 8 <block-1>
   243           8: JNEImm dst: r5 off: -1 imm: 2 <block-1>
   244           9: MovImm32 dst: r0 imm: 0
   245          10: Exit
   246  block-1:
   247  // return 1 (accept)
   248          11: MovImm32 dst: r0 imm: 1
   249          12: Exit
   250  `
   251  	testDeviceFilter(t, devices, expected)
   252  }