Skip to content

Commit e7dd7e5

Browse files
authored
Merge pull request #446 from q384566678/add-linux-resources-device
generate: add --linux-device-cgroup-add and --linux-device-cgroup-remove
2 parents 66b64a9 + fa9842c commit e7dd7e5

File tree

4 files changed

+146
-0
lines changed

4 files changed

+146
-0
lines changed

Diff for: cmd/oci-runtime-tool/generate.go

+100
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ var generateFlags = []cli.Flag{
4040
cli.StringSliceFlag{Name: "linux-device-add", Usage: "add a device which must be made available in the container"},
4141
cli.StringSliceFlag{Name: "linux-device-remove", Usage: "remove a device which must be made available in the container"},
4242
cli.BoolFlag{Name: "linux-device-remove-all", Usage: "remove all devices which must be made available in the container"},
43+
cli.StringSliceFlag{Name: "linux-device-cgroup-add", Usage: "add a device access rule"},
44+
cli.StringSliceFlag{Name: "linux-device-cgroup-remove", Usage: "remove a device access rule"},
4345
cli.BoolFlag{Name: "linux-disable-oom-kill", Usage: "disable OOM Killer"},
4446
cli.StringSliceFlag{Name: "linux-gidmappings", Usage: "add GIDMappings e.g HostID:ContainerID:Size"},
4547
cli.StringSliceFlag{Name: "linux-hugepage-limits-add", Usage: "add hugepage resource limits"},
@@ -249,6 +251,28 @@ func setupSpec(g *generate.Generator, context *cli.Context) error {
249251
}
250252
}
251253

254+
if context.IsSet("linux-device-cgroup-add") {
255+
devices := context.StringSlice("linux-device-cgroup-add")
256+
for _, device := range devices {
257+
dev, err := parseLinuxResourcesDeviceAccess(device, g)
258+
if err != nil {
259+
return err
260+
}
261+
g.AddLinuxResourcesDevice(dev.Allow, dev.Type, dev.Major, dev.Minor, dev.Access)
262+
}
263+
}
264+
265+
if context.IsSet("linux-device-cgroup-remove") {
266+
devices := context.StringSlice("linux-device-cgroup-remove")
267+
for _, device := range devices {
268+
dev, err := parseLinuxResourcesDeviceAccess(device, g)
269+
if err != nil {
270+
return err
271+
}
272+
g.RemoveLinuxResourcesDevice(dev.Allow, dev.Type, dev.Major, dev.Minor, dev.Access)
273+
}
274+
}
275+
252276
if context.IsSet("linux-readonly-paths") {
253277
paths := context.StringSlice("linux-readonly-paths")
254278
for _, path := range paths {
@@ -986,6 +1010,82 @@ func parseDevice(device string, g *generate.Generator) (rspec.LinuxDevice, error
9861010
return dev, nil
9871011
}
9881012

1013+
var cgroupDeviceType = map[string]bool{
1014+
"a": true, // all
1015+
"b": true, // block device
1016+
"c": true, // character device
1017+
}
1018+
var cgroupDeviceAccess = map[string]bool{
1019+
"r": true, //read
1020+
"w": true, //write
1021+
"m": true, //mknod
1022+
}
1023+
1024+
// parseLinuxResourcesDeviceAccess parses the raw string passed with the --device-access-add flag
1025+
func parseLinuxResourcesDeviceAccess(device string, g *generate.Generator) (rspec.LinuxDeviceCgroup, error) {
1026+
var allow bool
1027+
var devType, access string
1028+
var major, minor *int64
1029+
1030+
argsParts := strings.Split(device, ",")
1031+
1032+
switch argsParts[0] {
1033+
case "allow":
1034+
allow = true
1035+
case "deny":
1036+
allow = false
1037+
default:
1038+
return rspec.LinuxDeviceCgroup{},
1039+
fmt.Errorf("Only 'allow' and 'deny' are allowed in the first field of device-access-add: %s", device)
1040+
}
1041+
1042+
for _, s := range argsParts[1:] {
1043+
s = strings.TrimSpace(s)
1044+
if s == "" {
1045+
continue
1046+
}
1047+
parts := strings.SplitN(s, "=", 2)
1048+
if len(parts) != 2 {
1049+
return rspec.LinuxDeviceCgroup{}, fmt.Errorf("Incomplete device-access-add arguments: %s", s)
1050+
}
1051+
name, value := parts[0], parts[1]
1052+
1053+
switch name {
1054+
case "type":
1055+
if !cgroupDeviceType[value] {
1056+
return rspec.LinuxDeviceCgroup{}, fmt.Errorf("Invalid device type in device-access-add: %s", value)
1057+
}
1058+
devType = value
1059+
case "major":
1060+
i, err := strconv.ParseInt(value, 10, 64)
1061+
if err != nil {
1062+
return rspec.LinuxDeviceCgroup{}, err
1063+
}
1064+
major = &i
1065+
case "minor":
1066+
i, err := strconv.ParseInt(value, 10, 64)
1067+
if err != nil {
1068+
return rspec.LinuxDeviceCgroup{}, err
1069+
}
1070+
minor = &i
1071+
case "access":
1072+
for _, c := range strings.Split(value, "") {
1073+
if !cgroupDeviceAccess[c] {
1074+
return rspec.LinuxDeviceCgroup{}, fmt.Errorf("Invalid device access in device-access-add: %s", c)
1075+
}
1076+
}
1077+
access = value
1078+
}
1079+
}
1080+
return rspec.LinuxDeviceCgroup{
1081+
Allow: allow,
1082+
Type: devType,
1083+
Major: major,
1084+
Minor: minor,
1085+
Access: access,
1086+
}, nil
1087+
}
1088+
9891089
func addSeccomp(context *cli.Context, g *generate.Generator) error {
9901090

9911091
// Set the DefaultAction of seccomp

Diff for: completions/bash/oci-runtime-tool

+2
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,8 @@ _oci-runtime-tool_generate() {
326326
--linux-cpu-shares
327327
--linux-device-add
328328
--linux-device-remove
329+
--linux-device-cgroup-add
330+
--linux-device-cgroup-remove
329331
--linux-gidmappings
330332
--linux-hugepage-limits-add
331333
--linux-hugepage-limits-drop

Diff for: generate/generate.go

+33
Original file line numberDiff line numberDiff line change
@@ -1279,6 +1279,39 @@ func (g *Generator) ClearLinuxDevices() {
12791279
g.spec.Linux.Devices = []rspec.LinuxDevice{}
12801280
}
12811281

1282+
// AddLinuxResourcesDevice - add a device into g.spec.Linux.Resources.Devices
1283+
func (g *Generator) AddLinuxResourcesDevice(allow bool, devType string, major, minor *int64, access string) {
1284+
g.initSpecLinuxResources()
1285+
1286+
device := rspec.LinuxDeviceCgroup{
1287+
Allow: allow,
1288+
Type: devType,
1289+
Access: access,
1290+
Major: major,
1291+
Minor: minor,
1292+
}
1293+
g.spec.Linux.Resources.Devices = append(g.spec.Linux.Resources.Devices, device)
1294+
}
1295+
1296+
// RemoveLinuxResourcesDevice - remove a device from g.spec.Linux.Resources.Devices
1297+
func (g *Generator) RemoveLinuxResourcesDevice(allow bool, devType string, major, minor *int64, access string) {
1298+
if g.spec == nil || g.spec.Linux == nil || g.spec.Linux.Resources == nil {
1299+
return
1300+
}
1301+
for i, device := range g.spec.Linux.Resources.Devices {
1302+
if device.Allow == allow &&
1303+
(devType == device.Type || (devType != "" && device.Type != "" && devType == device.Type)) &&
1304+
(access == device.Access || (access != "" && device.Access != "" && access == device.Access)) &&
1305+
(major == device.Major || (major != nil && device.Major != nil && *major == *device.Major)) &&
1306+
(minor == device.Minor || (minor != nil && device.Minor != nil && *minor == *device.Minor)) {
1307+
1308+
g.spec.Linux.Resources.Devices = append(g.spec.Linux.Resources.Devices[:i], g.spec.Linux.Resources.Devices[i+1:]...)
1309+
return
1310+
}
1311+
}
1312+
return
1313+
}
1314+
12821315
// strPtr returns the pointer pointing to the string s.
12831316
func strPtr(s string) *string { return &s }
12841317

Diff for: man/oci-runtime-tool-generate.1.md

+11
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,17 @@ read the configuration from `config.json`.
121121
**--linux-device-remove-all**=true|false
122122
Remove all devices for linux inside the container. The default is *false*.
123123

124+
**--linux-device-cgroup-add**=allow|deny[,type=TYPE][,major=MAJOR][,minor=MINOR][,access=ACCESS]
125+
Add a device control rule.
126+
allow|deny: whether the entry is allowed or denied.
127+
TYPE: the device type. The value could be one of 'a' (all), 'b' (block), 'c' (character).
128+
MAJOR/MINOR: the major/minor id of device.
129+
ACCESS: cgroup permissions for device. A composition of r (read), w (write), and m (mknod).
130+
131+
**--linux-device-cgroup-remove**=allow|deny[,type=TYPE][,major=MAJOR][,minor=MINOR][,access=ACCESS]
132+
Remove a device control rule.
133+
The arguments is same as *--linux-device-cgroup-add*.
134+
124135
**--linux-disable-oom-kill**=true|false
125136
Whether to disable OOM Killer for the container or not.
126137

0 commit comments

Comments
 (0)