// parseSeccompArgs parses seccomp mode and set CLI flags, preparing an // appropriate seccomp isolator. func parseSeccompArgs(patchSeccompMode string, patchSeccompSet string) (*types.Isolator, error) { // Parse mode flag and additional keyed arguments. var errno, mode string args := strings.Split(patchSeccompMode, ",") for _, a := range args { kv := strings.Split(a, "=") switch len(kv) { case 1: // mode, either "remove" or "retain" mode = kv[0] case 2: // k=v argument, only "errno" allowed for now if kv[0] == "errno" { errno = kv[1] } else { return nil, fmt.Errorf("invalid seccomp-mode optional argument: %s", a) } default: return nil, fmt.Errorf("cannot parse seccomp-mode argument: %s", a) } } // Instantiate an Isolator with the content specified by the --seccomp-set parameter. var err error var seccomp types.AsIsolator switch mode { case "remove": seccomp, err = types.NewLinuxSeccompRemoveSet(errno, strings.Split(patchSeccompSet, ",")...) case "retain": seccomp, err = types.NewLinuxSeccompRetainSet(errno, strings.Split(patchSeccompSet, ",")...) default: err = fmt.Errorf("unknown seccomp mode %s", mode) } if err != nil { return nil, fmt.Errorf("cannot parse seccomp isolator: %s", err) } seccompIsolator, err := seccomp.AsIsolator() if err != nil { return nil, err } return seccompIsolator, nil }
func patchManifest(im *schema.ImageManifest) error { if patchName != "" { name, err := types.NewACIdentifier(patchName) if err != nil { return err } im.Name = *name } var app *types.App = im.App if patchExec != "" { if app == nil { // if the original manifest was missing an app and // patchExec is set let's assume the user is trying to // inject one... im.App = &types.App{} app = im.App } app.Exec = strings.Split(patchExec, " ") } if patchUser != "" || patchGroup != "" || patchSupplementaryGIDs != "" || patchCaps != "" || patchRevokeCaps != "" || patchMounts != "" || patchPorts != "" || patchIsolators != "" { // ...but if we still don't have an app and the user is trying // to patch one of its other parameters, it's an error if app == nil { return fmt.Errorf("no app in the supplied manifest and no exec command provided") } } if patchUser != "" { app.User = patchUser } if patchGroup != "" { app.Group = patchGroup } if patchSupplementaryGIDs != "" { app.SupplementaryGIDs = []int{} gids := strings.Split(patchSupplementaryGIDs, ",") for _, g := range gids { gid, err := strconv.Atoi(g) if err != nil { return fmt.Errorf("invalid supplementary group %q: %v", g, err) } app.SupplementaryGIDs = append(app.SupplementaryGIDs, gid) } } if patchCaps != "" && patchRevokeCaps != "" { return errors.New("conflicting capabilities isolators provided") } if patchCaps != "" || patchRevokeCaps != "" { var capsAsIsolator types.AsIsolator var err error if patchCaps != "" { // Instantiate Isolator with content specified by --capability capsAsIsolator, err = types.NewLinuxCapabilitiesRetainSet(strings.Split(patchCaps, ",")...) if err != nil { return fmt.Errorf("cannot parse capability retain set %q: %v", patchCaps, err) } } if patchRevokeCaps != "" { // Instantiate Isolator with content specified by --revoke-capability capsAsIsolator, err = types.NewLinuxCapabilitiesRevokeSet(strings.Split(patchRevokeCaps, ",")...) if err != nil { return fmt.Errorf("cannot parse capability remove set %q: %v", patchRevokeCaps, err) } } capsIsolator, err := capsAsIsolator.AsIsolator() if err != nil { return err } capsKeys := []types.ACIdentifier{types.LinuxCapabilitiesRevokeSetName, types.LinuxCapabilitiesRetainSetName} app.Isolators.ReplaceIsolatorsByName(*capsIsolator, capsKeys) } if patchMounts != "" { mounts := strings.Split(patchMounts, ":") for _, m := range mounts { mountPoint, err := types.MountPointFromString(m) if err != nil { return fmt.Errorf("cannot parse mount point %q: %v", m, err) } app.MountPoints = append(app.MountPoints, *mountPoint) } } if patchPorts != "" { ports := strings.Split(patchPorts, ":") for _, p := range ports { port, err := types.PortFromString(p) if err != nil { return fmt.Errorf("cannot parse port %q: %v", p, err) } app.Ports = append(app.Ports, *port) } } // Parse seccomp args and override existing seccomp isolators if patchSeccompMode != "" { seccompIsolator, err := parseSeccompArgs(patchSeccompMode, patchSeccompSet) if err != nil { return err } seccompReps := []types.ACIdentifier{types.LinuxSeccompRemoveSetName, types.LinuxSeccompRetainSetName} app.Isolators.ReplaceIsolatorsByName(*seccompIsolator, seccompReps) } else if patchSeccompSet != "" { return fmt.Errorf("--seccomp-set specified without --seccomp-mode") } if patchIsolators != "" { isolators := strings.Split(patchIsolators, ":") for _, is := range isolators { name, isolatorStr, err := isolatorStrFromString(is) if err != nil { return fmt.Errorf("cannot parse isolator %q: %v", is, err) } _, ok := types.ResourceIsolatorNames[name] switch name { case types.LinuxNoNewPrivilegesName, types.LinuxOOMScoreAdjName: ok = true kv := strings.Split(is, ",") if len(kv) != 2 { return fmt.Errorf("isolator %s: invalid format", name) } isolatorStr = fmt.Sprintf(`{ "name": "%s", "value": %s }`, name, kv[1]) case types.LinuxSeccompRemoveSetName, types.LinuxSeccompRetainSetName: ok = false } if !ok { return fmt.Errorf("isolator %s is not supported for patching", name) } isolator := &types.Isolator{} if err := isolator.UnmarshalJSON([]byte(isolatorStr)); err != nil { return fmt.Errorf("cannot unmarshal isolator %v: %v", isolatorStr, err) } app.Isolators = append(app.Isolators, *isolator) } } return nil }