Repository: opencontainers/runc
File: libcontainer/specconv/spec_linux.go (Go)

Code before:
			if start < minValue || end > maxValue {
				return nil, fmt.Errorf("invalid range %s: out of range %d-%d", part, minValue, maxValue)
			}
			for i := start; i <= end; i++ {
				result = append(result, i)
			}
		default:
			num, err := strconv.Atoi(part)
			if err != nil {
				return nil, err
			}
			if num < minValue || num > maxValue {
				return nil, fmt.Errorf("invalid value %d: out of range %d-%d", num, minValue, maxValue)
			}
			result = append(result, num)
		}
	}
	return result, nil
}

// isEmptyMemoryPolicy checks if a LinuxMemoryPolicy is empty (nil or all zero values).
func isEmptyMemoryPolicy(mp *specs.LinuxMemoryPolicy) bool {
	if mp == nil {
		return true
	}
	if mp.Mode != "" {
		return false
	}
	if mp.Nodes != "" {
		return false
	}
	if len(mp.Flags) > 0 {
		return false
	}
	return true
}

func SetupSeccomp(config *specs.LinuxSeccomp) (*configs.Seccomp, error) {
	if config == nil {
		return nil, nil
	}

	// No default action specified, no syscalls listed, assume seccomp disabled
	if config.DefaultAction == "" && len(config.Syscalls) == 0 {
		return nil, nil
	}

	newConfig := new(configs.Seccomp)
	newConfig.Syscalls = []*configs.Syscall{}

	// The list of flags defined in runtime-spec is a subset of the flags

Review comment (bug):
Apologies for the delay—I'm currently in the middle of a routine audit and have been quite busy, so I haven't had a chance to review your code yet.

Regarding the configuration, I believe we should return an error for cases like the following:
```
.linux.memoryPolicy = {
}
```
and
```
.linux.memoryPolicy = {
		"mode": "",
		"nodes": "0"
}
```
We've generally followed the principle of failing fast—validating inputs early rather than deferring error detection until system calls are made during container setup. To enforce this, let's add a dedicated `memoryPolicy` validator in `libcontainer/configs/validate/validator.go`.

Code after:
			newConfig.Architectures = append(newConfig.Architectures, newArch)
		}
	}

	// Convert default action from string representation
	newDefaultAction, err := seccomp.ConvertStringToAction(string(config.DefaultAction))
	if err != nil {
		return nil, err
	}
	newConfig.DefaultAction = newDefaultAction
	newConfig.DefaultErrnoRet = config.DefaultErrnoRet

	newConfig.ListenerPath = config.ListenerPath
	newConfig.ListenerMetadata = config.ListenerMetadata

	// Loop through all syscall blocks and convert them to libcontainer format
	for _, call := range config.Syscalls {
		newAction, err := seccomp.ConvertStringToAction(string(call.Action))
		if err != nil {
			return nil, err
		}

		for _, name := range call.Names {
			newCall := configs.Syscall{
				Name:     name,
				Action:   newAction,
				ErrnoRet: call.ErrnoRet,
				Args:     []*configs.Arg{},
			}
			// Loop through all the arguments of the syscall and convert them
			for _, arg := range call.Args {
				newOp, err := seccomp.ConvertStringToOperator(string(arg.Op))
				if err != nil {
					return nil, err
				}

				newArg := configs.Arg{
					Index:    arg.Index,
					Value:    arg.Value,
					ValueTwo: arg.ValueTwo,
					Op:       newOp,
				}

				newCall.Args = append(newCall.Args, &newArg)
			}
			newConfig.Syscalls = append(newConfig.Syscalls, &newCall)
		}
	}

	return newConfig, nil
}