Repository: moby/moby
File: daemon/daemon_unix.go (Go)

Code before:
		var k, v string
		var ok bool
		if strings.Contains(opt, "=") {
			k, v, ok = strings.Cut(opt, "=")
		} else if strings.Contains(opt, ":") {
			k, v, ok = strings.Cut(opt, ":")
			log.G(context.TODO()).Warn("Security options with `:` as a separator are deprecated and will be completely unsupported in 17.04, use `=` instead.")
		}
		if !ok {
			return fmt.Errorf("invalid --security-opt 1: %q", opt)
		}

		switch k {
		case "label":
			labelOpts = append(labelOpts, v)
		case "apparmor":
			securityOptions.AppArmorProfile = v
		case "seccomp":
			securityOptions.SeccompProfile = v
		case "no-new-privileges":
			noNewPrivileges, err := strconv.ParseBool(v)
			if err != nil {
				return fmt.Errorf("invalid --security-opt 2: %q", opt)
			}
			securityOptions.NoNewPrivileges = noNewPrivileges
		case "cgroups":
			if v != "rw" {
				return fmt.Errorf("invalid --security-opt 3: %q", opt)
			}
			securityOptions.Cgroups = v
		default:
			return fmt.Errorf("invalid --security-opt 2: %q", opt)
		}
	}

	securityOptions.ProcessLabel, securityOptions.MountLabel, err = label.InitLabels(labelOpts)
	return err
}

func getBlkioThrottleDevices(devs []*blkiodev.ThrottleDevice) ([]specs.LinuxThrottleDevice, error) {
	var throttleDevices []specs.LinuxThrottleDevice
	var stat unix.Stat_t

	for _, d := range devs {
		if err := unix.Stat(d.Path, &stat); err != nil {
			return nil, errors.WithStack(&os.PathError{Op: "stat", Path: d.Path, Err: err})
		}
		d := specs.LinuxThrottleDevice{Rate: d.Rate}
		// the type is 32bit on mips
		d.Major = int64(unix.Major(uint64(stat.Rdev))) //nolint: unconvert
		d.Minor = int64(unix.Minor(uint64(stat.Rdev))) //nolint: unconvert

Review comment (security):
As this introduces a new option accepted by the API, can you add a bullet to the API version-history for v1.48? https://github.com/moby/moby/blob/20062ef3580a15e53c48e8e0e5aa2c43eb4982f1/docs/api/version-history.md#v148-api-changes

Something like (better suggestions welcome!)

```markdown
* `POST /containers/create` now accepts a `cgroups=rw` option in `HostConfig.SecurityOpt`
  to mount the container's cgroups writable. This provides a more granular
  approach than `HostConfig.Privileged`.
```

We should also include these options in our swagger / OpenAPI, but looks like we currently don't, so that's something we can do in a follow-up (I can create a tracking ticket for that).


Code after:
			continue
		}
		if opt == "disable" {
			labelOpts = append(labelOpts, "disable")
			continue
		}

		var k, v string
		var ok bool
		if strings.Contains(opt, "=") {
			k, v, ok = strings.Cut(opt, "=")
		} else if strings.Contains(opt, ":") {
			k, v, ok = strings.Cut(opt, ":")
			log.G(context.TODO()).Warn("Security options with `:` as a separator are deprecated and will be completely unsupported in 17.04, use `=` instead.")
		}
		if !ok {
			return fmt.Errorf("invalid --security-opt 1: %q", opt)
		}

		switch k {
		case "label":
			labelOpts = append(labelOpts, v)
		case "apparmor":
			securityOptions.AppArmorProfile = v
		case "seccomp":
			securityOptions.SeccompProfile = v
		case "no-new-privileges":
			nnp, err := strconv.ParseBool(v)
			if err != nil {
				return fmt.Errorf("invalid --security-opt 2: %q", opt)
			}
			securityOptions.NoNewPrivileges = nnp
		case "writable-cgroups":
			writableCgroups, err := strconv.ParseBool(v)
			if err != nil {
				return fmt.Errorf("invalid --security-opt 2: %q", opt)
			}
			securityOptions.WritableCgroups = &writableCgroups
		default:
			return fmt.Errorf("invalid --security-opt 2: %q", opt)
		}
	}

	securityOptions.ProcessLabel, securityOptions.MountLabel, err = label.InitLabels(labelOpts)
	return err
}

func getBlkioThrottleDevices(devs []*blkiodev.ThrottleDevice) ([]specs.LinuxThrottleDevice, error) {
	var throttleDevices []specs.LinuxThrottleDevice
	var stat unix.Stat_t