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:
Zheao.Li
2023-10-20 20:25:10 +08:00
parent edd00eb3cb
commit 98511bb40e
9 changed files with 129 additions and 1 deletions
-1
View File
@@ -7,7 +7,6 @@ The following features are not implemented yet:
Spec version | Feature | PR 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 | `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 | 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) v1.1.0 | `.process.ioPriority` | [#3783](https://github.com/opencontainers/runc/pull/3783)
+3
View File
@@ -219,6 +219,9 @@ type Config struct {
// Scheduler represents the scheduling attributes for a process. // Scheduler represents the scheduling attributes for a process.
Scheduler *Scheduler `json:"scheduler,omitempty"` 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. // Scheduler is based on the Linux sched_setattr(2) syscall.
+13
View File
@@ -9,6 +9,19 @@ var (
errNoGroupMap = errors.New("User namespaces enabled, but no group mapping found.") 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 // HostUID gets the translated uid for the process on host which could be
// different when user namespaces are enabled. // different when user namespaces are enabled.
func (c Config) HostUID(containerId int) (int, error) { func (c Config) HostUID(containerId int) (int, error) {
+4
View File
@@ -654,6 +654,10 @@ func setupScheduler(config *configs.Config) error {
return nil return nil
} }
func setupPersonality(config *configs.Config) error {
return system.SetLinuxPersonality(config.Personality.Domain)
}
// signalAllProcesses freezes then iterates over all the processes inside the // signalAllProcesses freezes then iterates over all the processes inside the
// manager's cgroups sending the signal s to them. // manager's cgroups sending the signal s to them.
func signalAllProcesses(m cgroups.Manager, s unix.Signal) error { func signalAllProcesses(m cgroups.Manager, s unix.Signal) error {
+5
View File
@@ -93,6 +93,11 @@ func (l *linuxSetnsInit) Init() error {
if err := apparmor.ApplyProfile(l.config.AppArmorProfile); err != nil { if err := apparmor.ApplyProfile(l.config.AppArmorProfile); err != nil {
return err 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. // Check for the arg early to make sure it exists.
name, err := exec.LookPath(l.config.Args[0]) name, err := exec.LookPath(l.config.Args[0])
if err != nil { if err != nil {
+22
View File
@@ -434,6 +434,18 @@ func CreateLibcontainerConfig(opts *CreateOpts) (*configs.Config, error) {
MemBwSchema: spec.Linux.IntelRdt.MemBwSchema, 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. // Set the host UID that should own the container's cgroup.
@@ -571,6 +583,16 @@ func checkPropertyName(s string) error {
return nil 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 // Some systemd properties are documented as having "Sec" suffix
// (e.g. TimeoutStopSec) but are expected to have "USec" suffix // (e.g. TimeoutStopSec) but are expected to have "USec" suffix
// here, so let's provide conversion to improve compatibility. // here, so let's provide conversion to improve compatibility.
+8
View File
@@ -233,6 +233,14 @@ func (l *linuxStandardInit) Init() error {
return err 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. // Close the pipe to signal that we have completed our init.
logrus.Debugf("init: closing the pipe to signal completion") logrus.Debugf("init: closing the pipe to signal completion")
_ = l.pipe.Close() _ = l.pipe.Close()
+10
View File
@@ -214,3 +214,13 @@ func Copy(dst io.Writer, src io.Reader) (copied int64, err error) {
fallback: fallback:
return io.Copy(dst, src) 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
}
+64
View File
@@ -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"* ]]
}