Skip to content

Commit

Permalink
linux: Support setting execution domain via linux personality
Browse files Browse the repository at this point in the history
carry opencontainers#3126

Co-authored-by: Aditya R <arajan@redhat.com>
Signed-off-by: Zheao.Li <me@manjusaka.me>
  • Loading branch information
Zheaoli and flouthoc committed Oct 26, 2023
1 parent edd00eb commit 6220747
Show file tree
Hide file tree
Showing 9 changed files with 129 additions and 1 deletion.
1 change: 0 additions & 1 deletion docs/spec-conformance.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions libcontainer/configs/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
13 changes: 13 additions & 0 deletions libcontainer/configs/config_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
4 changes: 4 additions & 0 deletions libcontainer/init_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
5 changes: 5 additions & 0 deletions libcontainer/setns_init_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
22 changes: 22 additions & 0 deletions libcontainer/specconv/spec_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down
8 changes: 8 additions & 0 deletions libcontainer/standard_init_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
10 changes: 10 additions & 0 deletions libcontainer/system/linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 := syscall.Syscall(syscall.SYS_PERSONALITY, uintptr(personality), 0, 0)
if errno != 0 {
return &os.SyscallError{Syscall: "set_personality", Err: errno}
}
return nil
}
64 changes: 64 additions & 0 deletions tests/integration/personality.bats
Original file line number Diff line number Diff line change
@@ -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"* ]]
}

0 comments on commit 6220747

Please sign in to comment.