mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-10 21:53:57 +08:00
linux: Support setting execution domain via linux personality
carry #3126 Co-authored-by: Aditya R <arajan@redhat.com> Signed-off-by: Zheao.Li <me@manjusaka.me>
This commit is contained in:
@@ -7,7 +7,6 @@ The following features are not implemented yet:
|
||||
|
||||
Spec version | Feature | PR
|
||||
-------------|------------------------------------------|----------------------------------------------------------
|
||||
v1.0.2 | `.linux.personality` | [#3126](https://github.com/opencontainers/runc/pull/3126)
|
||||
v1.1.0 | `SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV` | [#3862](https://github.com/opencontainers/runc/pull/3862)
|
||||
v1.1.0 | rsvd hugetlb cgroup | TODO ([#3859](https://github.com/opencontainers/runc/issues/3859))
|
||||
v1.1.0 | `.process.ioPriority` | [#3783](https://github.com/opencontainers/runc/pull/3783)
|
||||
|
||||
@@ -219,6 +219,9 @@ type Config struct {
|
||||
|
||||
// Scheduler represents the scheduling attributes for a process.
|
||||
Scheduler *Scheduler `json:"scheduler,omitempty"`
|
||||
|
||||
// Personality contains configuration for the Linux personality syscall.
|
||||
Personality *LinuxPersonality `json:"personality,omitempty"`
|
||||
}
|
||||
|
||||
// Scheduler is based on the Linux sched_setattr(2) syscall.
|
||||
|
||||
@@ -9,6 +9,19 @@ var (
|
||||
errNoGroupMap = errors.New("User namespaces enabled, but no group mapping found.")
|
||||
)
|
||||
|
||||
// Please check https://man7.org/linux/man-pages/man2/personality.2.html for const details.
|
||||
// https://raw.githubusercontent.com/torvalds/linux/master/include/uapi/linux/personality.h
|
||||
const (
|
||||
PerLinux = 0x0000
|
||||
PerLinux32 = 0x0008
|
||||
)
|
||||
|
||||
type LinuxPersonality struct {
|
||||
// Domain for the personality
|
||||
// can only contain values "LINUX" and "LINUX32"
|
||||
Domain int `json:"domain"`
|
||||
}
|
||||
|
||||
// HostUID gets the translated uid for the process on host which could be
|
||||
// different when user namespaces are enabled.
|
||||
func (c Config) HostUID(containerId int) (int, error) {
|
||||
|
||||
@@ -654,6 +654,10 @@ func setupScheduler(config *configs.Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func setupPersonality(config *configs.Config) error {
|
||||
return system.SetLinuxPersonality(config.Personality.Domain)
|
||||
}
|
||||
|
||||
// signalAllProcesses freezes then iterates over all the processes inside the
|
||||
// manager's cgroups sending the signal s to them.
|
||||
func signalAllProcesses(m cgroups.Manager, s unix.Signal) error {
|
||||
|
||||
@@ -93,6 +93,11 @@ func (l *linuxSetnsInit) Init() error {
|
||||
if err := apparmor.ApplyProfile(l.config.AppArmorProfile); err != nil {
|
||||
return err
|
||||
}
|
||||
if l.config.Config.Personality != nil {
|
||||
if err := setupPersonality(l.config.Config); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Check for the arg early to make sure it exists.
|
||||
name, err := exec.LookPath(l.config.Args[0])
|
||||
if err != nil {
|
||||
|
||||
@@ -434,6 +434,18 @@ func CreateLibcontainerConfig(opts *CreateOpts) (*configs.Config, error) {
|
||||
MemBwSchema: spec.Linux.IntelRdt.MemBwSchema,
|
||||
}
|
||||
}
|
||||
if spec.Linux.Personality != nil {
|
||||
if len(spec.Linux.Personality.Flags) > 0 {
|
||||
logrus.Warnf("ignoring unsupported personality flags: %+v because personality flag has not supported at this time", spec.Linux.Personality.Flags)
|
||||
}
|
||||
domain, err := getLinuxPersonalityFromStr(string(spec.Linux.Personality.Domain))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.Personality = &configs.LinuxPersonality{
|
||||
Domain: domain,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the host UID that should own the container's cgroup.
|
||||
@@ -571,6 +583,16 @@ func checkPropertyName(s string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// getLinuxPersonalityFromStr converts the string domain received from spec to equivalent integer.
|
||||
func getLinuxPersonalityFromStr(domain string) (int, error) {
|
||||
if domain == string(specs.PerLinux32) {
|
||||
return configs.PerLinux32, nil
|
||||
} else if domain == string(specs.PerLinux) {
|
||||
return configs.PerLinux, nil
|
||||
}
|
||||
return -1, fmt.Errorf("invalid personality domain %s", domain)
|
||||
}
|
||||
|
||||
// Some systemd properties are documented as having "Sec" suffix
|
||||
// (e.g. TimeoutStopSec) but are expected to have "USec" suffix
|
||||
// here, so let's provide conversion to improve compatibility.
|
||||
|
||||
@@ -233,6 +233,14 @@ func (l *linuxStandardInit) Init() error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Set personality if specified.
|
||||
if l.config.Config.Personality != nil {
|
||||
if err := setupPersonality(l.config.Config); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Close the pipe to signal that we have completed our init.
|
||||
logrus.Debugf("init: closing the pipe to signal completion")
|
||||
_ = l.pipe.Close()
|
||||
|
||||
@@ -214,3 +214,13 @@ func Copy(dst io.Writer, src io.Reader) (copied int64, err error) {
|
||||
fallback:
|
||||
return io.Copy(dst, src)
|
||||
}
|
||||
|
||||
// SetLinuxPersonality sets the Linux execution personality. For more information see the personality syscall documentation.
|
||||
// checkout getLinuxPersonalityFromStr() from libcontainer/specconv/spec_linux.go for type conversion.
|
||||
func SetLinuxPersonality(personality int) error {
|
||||
_, _, errno := unix.Syscall(unix.SYS_PERSONALITY, uintptr(personality), 0, 0)
|
||||
if errno != 0 {
|
||||
return &os.SyscallError{Syscall: "set_personality", Err: errno}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env bats
|
||||
|
||||
load helpers
|
||||
|
||||
function setup() {
|
||||
requires arch_x86_64
|
||||
setup_busybox
|
||||
}
|
||||
|
||||
function teardown() {
|
||||
teardown_bundle
|
||||
}
|
||||
|
||||
@test "runc run personality for i686" {
|
||||
update_config '
|
||||
.process.args = ["/bin/sh", "-c", "uname -a"]
|
||||
| .linux.personality = {
|
||||
"domain": "LINUX32",
|
||||
"flags": []
|
||||
}'
|
||||
|
||||
runc run test_busybox
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"i686"* ]]
|
||||
}
|
||||
|
||||
@test "runc run personality with exec for i686" {
|
||||
update_config '
|
||||
.linux.personality = {
|
||||
"domain": "LINUX32",
|
||||
}'
|
||||
|
||||
runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox
|
||||
[ "$status" -eq 0 ]
|
||||
runc exec test_busybox /bin/sh -c "uname -a"
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"i686"* ]]
|
||||
}
|
||||
|
||||
@test "runc run personality for x86_64" {
|
||||
update_config '
|
||||
.process.args = ["/bin/sh", "-c", "uname -a"]
|
||||
| .linux.personality = {
|
||||
"domain": "LINUX",
|
||||
"flags": []
|
||||
}'
|
||||
|
||||
runc run test_busybox
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"x86_64"* ]]
|
||||
}
|
||||
|
||||
@test "runc run personality with exec for x86_64" {
|
||||
update_config '
|
||||
.linux.personality = {
|
||||
"domain": "LINUX",
|
||||
}'
|
||||
|
||||
runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox
|
||||
[ "$status" -eq 0 ]
|
||||
runc exec test_busybox /bin/sh -c "uname -a"
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"x86_64"* ]]
|
||||
}
|
||||
Reference in New Issue
Block a user