Skip to content

Commit

Permalink
linux: Support setting execution domain via linux personality.
Browse files Browse the repository at this point in the history
Signed-off-by: Aditya Rajan <flouthoc.git@gmail.com>
  • Loading branch information
flouthoc committed Aug 11, 2021
1 parent 16027b8 commit 4600cdd
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 2 deletions.
3 changes: 3 additions & 0 deletions libcontainer/configs/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,9 @@ type Config struct {
// RootlessCgroups is set when unlikely to have the full access to cgroups.
// When RootlessCgroups is set, cgroups errors are ignored.
RootlessCgroups bool `json:"rootless_cgroups,omitempty"`

// Personality contains configuration for the Linux personality syscall.
Personality *LinuxPersonality `json:"personality,omitempty"`
}

type (
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 (
PER_LINUX = 0x0000
PER_LINUX32 = 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
8 changes: 8 additions & 0 deletions libcontainer/container_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,14 @@ func (c *linuxContainer) Set(config configs.Config) error {
}

func (c *linuxContainer) Start(process *Process) error {
// configure linux personality before starting the process
if c.Config().Personality != nil {
err := system.SetLinuxPersonality(c.Config().Personality.Domain)
if err != nil {
return err
}
}

c.m.Lock()
defer c.m.Unlock()
if c.config.Cgroups.Resources.SkipDevices {
Expand Down
15 changes: 15 additions & 0 deletions libcontainer/integration/exec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,21 @@ func TestIPCBadPath(t *testing.T) {
}
}

func TestPersonality(t *testing.T) {
if testing.Short() {
return
}

config := newTemplateConfig(t, &tParam{personality: configs.PER_LINUX32})

out, _, err := runContainer(t, config, "", "/bin/sh", "-c", "uname -a")
ok(t, err)
// output must contain kernel architecture configured as i686
if !strings.Contains(out.Stdout.String(), "i686") {
t.Fatalf("expected kernel architecture i686 configured via personality")
}
}

func TestRlimit(t *testing.T) {
testRlimit(t, false)
}
Expand Down
11 changes: 9 additions & 2 deletions libcontainer/integration/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ var standardEnvironment = []string{
const defaultMountFlags = unix.MS_NOEXEC | unix.MS_NOSUID | unix.MS_NODEV

type tParam struct {
userns bool
systemd bool
userns bool
systemd bool
personality int
}

// newTemplateConfig returns a base template for running a container.
Expand Down Expand Up @@ -218,6 +219,12 @@ func newTemplateConfig(t *testing.T, p *tParam) *configs.Config {
})
}

if p.personality != 0 {
config.Personality = &configs.LinuxPersonality{
Domain: p.personality,
}
}

if p.systemd {
id := strconv.FormatInt(-int64(time.Now().Nanosecond()), 36)
config.Cgroups.Name = strings.ReplaceAll(t.Name(), "/", "_") + id
Expand Down
20 changes: 20 additions & 0 deletions libcontainer/specconv/spec_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,11 @@ func CreateLibcontainerConfig(opts *CreateOpts) (*configs.Config, error) {
MemBwSchema: spec.Linux.IntelRdt.MemBwSchema,
}
}
if spec.Linux.Personality != nil {
config.Personality = &configs.LinuxPersonality{
Domain: getLinuxPersonalityFromStr(string(spec.Linux.Personality.Domain)),
}
}
}
if spec.Process != nil {
config.OomScoreAdj = spec.Process.OOMScoreAdj
Expand Down Expand Up @@ -391,6 +396,21 @@ func convertSecToUSec(value dbus.Variant) (dbus.Variant, error) {
return dbus.MakeVariant(sec), nil
}

// getLinuxPersonalityFromStr converts the string domain received from spec to equivalent integer.
// check libcontainer/configs/config_linux.go
// check https://raw.githubusercontent.com/torvalds/linux/master/include/uapi/linux/personality.h
// valid arguments
// LINUX i.e PER_LINUX (since Linux 1.2.0).
// LINUX32 i.e PER_LINUX32 (since Linux 2.2) LINUX32 will set the uname system call to show a 32 bit CPU type, such as i686.
// everything unknown default to PER_LINUX.
func getLinuxPersonalityFromStr(domain string) int {
// defaults to PER_LINUX
if domain == "LINUX32" {
return configs.PER_LINUX32
}
return configs.PER_LINUX
}

func initSystemdProps(spec *specs.Spec) ([]systemdDbus.Property, error) {
const keyPrefix = "org.systemd.property."
var sp []systemdDbus.Property
Expand Down
12 changes: 12 additions & 0 deletions libcontainer/system/linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
package system

import (
"fmt"
"os/exec"
"syscall"
"unsafe"

"golang.org/x/sys/unix"
Expand Down Expand Up @@ -108,3 +110,13 @@ func GetSubreaper() (int, error) {

return int(i), nil
}

// 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(persona int) error {
_, _, errno := syscall.Syscall(syscall.SYS_PERSONALITY, uintptr(persona), 0, 0)
if errno != 0 {
return fmt.Errorf("syscall: SYS_PERSONALITY failed with error code: %w", errno)
}
return nil
}

0 comments on commit 4600cdd

Please sign in to comment.