diff --git a/README.md b/README.md index 3d33d75..c8915ed 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,7 @@ To configure these, [use `ENV`](https://docs.docker.com/engine/reference/builder | `JAIL_DEV` | `null,zero,urandom` | Device files available in `/dev` separated by `,` | | `JAIL_SYSCALLS` | _(none)_ | Additional allowed syscall names separated by `,` | | `JAIL_TMP_SIZE` | `0` | Maximum size of writable `/tmp` directory in each jail. If set to `0`, the writable `/tmp` directory is unavailable. | +| `JAIL_USER` | `1000` | UID to execute as | | `JAIL_ENV_*` | _(none)_ | Environment variables available in each jail (with the `JAIL_ENV_` prefix removed) | If it exists, `/jail/hook.sh` is executed before the jail starts. Use this script to configure nsjail options or the execution environment. diff --git a/cmd/jailrun/jailrun.go b/cmd/jailrun/jailrun.go index ba05fe2..e92a930 100644 --- a/cmd/jailrun/jailrun.go +++ b/cmd/jailrun/jailrun.go @@ -28,7 +28,7 @@ func run() error { if err != nil { return err } - if err := cg.Mount(); err != nil { + if err := cg.Mount(cfg.UserId); err != nil { return fmt.Errorf("delegate cgroup: %w", err) } msg := &nsjail.NsJailConfig{} diff --git a/internal/cgroup/cgroup.go b/internal/cgroup/cgroup.go index 9fcbd5f..1d0f6ed 100644 --- a/internal/cgroup/cgroup.go +++ b/internal/cgroup/cgroup.go @@ -12,7 +12,7 @@ import ( ) type Cgroup interface { - Mount() error + Mount(int) error SetConfig(*nsjail.NsJailConfig) error } diff --git a/internal/cgroup/cgroup1.go b/internal/cgroup/cgroup1.go index 3206b21..92f251f 100644 --- a/internal/cgroup/cgroup1.go +++ b/internal/cgroup/cgroup1.go @@ -4,7 +4,6 @@ import ( "fmt" "os" - "github.com/redpwn/jail/internal/privs" "github.com/redpwn/jail/internal/proto/nsjail" "golang.org/x/sys/unix" "google.golang.org/protobuf/proto" @@ -20,7 +19,7 @@ type cgroup1 struct { cpu *cgroup1Entry } -func mountCgroup1Entry(name string, entry *cgroup1Entry) error { +func mountCgroup1Entry(name string, entry *cgroup1Entry, userId int) error { mountPath := rootPath + "/" + name if err := unix.Mount("", mountPath, "cgroup", mountFlags, entry.controllers); err != nil { return fmt.Errorf("mount cgroup1 %s to %s: %w", entry.controllers, mountPath, err) @@ -32,20 +31,20 @@ func mountCgroup1Entry(name string, entry *cgroup1Entry) error { if err := os.Mkdir(delegated, 0755); err != nil { return err } - if err := os.Chown(delegated, privs.UserId, privs.UserId); err != nil { + if err := os.Chown(delegated, userId, userId); err != nil { return err } return nil } -func (c *cgroup1) Mount() error { - if err := mountCgroup1Entry("pids", c.pids); err != nil { +func (c *cgroup1) Mount(userId int) error { + if err := mountCgroup1Entry("pids", c.pids, userId); err != nil { return err } - if err := mountCgroup1Entry("mem", c.mem); err != nil { + if err := mountCgroup1Entry("mem", c.mem, userId); err != nil { return err } - if err := mountCgroup1Entry("cpu", c.cpu); err != nil { + if err := mountCgroup1Entry("cpu", c.cpu, userId); err != nil { return err } return nil diff --git a/internal/cgroup/cgroup2.go b/internal/cgroup/cgroup2.go index dafd606..c17f0ae 100644 --- a/internal/cgroup/cgroup2.go +++ b/internal/cgroup/cgroup2.go @@ -4,7 +4,6 @@ import ( "fmt" "os" - "github.com/redpwn/jail/internal/privs" "github.com/redpwn/jail/internal/proto/nsjail" "golang.org/x/sys/unix" "google.golang.org/protobuf/proto" @@ -12,7 +11,7 @@ import ( type cgroup2 struct{} -func (c *cgroup2) Mount() error { +func (c *cgroup2) Mount(userId int) error { mountPath := rootPath + "/unified" if err := unix.Mount("", mountPath, "cgroup2", mountFlags, ""); err != nil { return fmt.Errorf("mount cgroup2 to %s: %w", mountPath, err) @@ -27,7 +26,7 @@ func (c *cgroup2) Mount() error { if err := os.WriteFile(mountPath+"/cgroup.subtree_control", []byte("+pids +memory +cpu"), 0); err != nil { return err } - if err := os.Chown(mountPath+"/cgroup.procs", privs.UserId, privs.UserId); err != nil { + if err := os.Chown(mountPath+"/cgroup.procs", userId, userId); err != nil { return err } runPath := mountPath + "/run" @@ -37,7 +36,7 @@ func (c *cgroup2) Mount() error { if err := os.WriteFile(runPath+"/cgroup.subtree_control", []byte("+pids +memory +cpu"), 0); err != nil { return err } - if err := os.Chown(runPath, privs.UserId, privs.UserId); err != nil { + if err := os.Chown(runPath, userId, userId); err != nil { return err } return nil diff --git a/internal/config/config.go b/internal/config/config.go index 9b90ba6..0803e08 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -37,6 +37,7 @@ type Config struct { Dev []string `env:"JAIL_DEV" envDefault:"null,zero,urandom"` Syscalls []string `env:"JAIL_SYSCALLS"` TmpSize size `env:"JAIL_TMP_SIZE"` + UserId int `env:"JAIL_USER" envDefault:"1000"` Env []string } diff --git a/internal/privs/privs.go b/internal/privs/privs.go index 72d0d29..35d63ca 100644 --- a/internal/privs/privs.go +++ b/internal/privs/privs.go @@ -7,19 +7,18 @@ import ( "golang.org/x/sys/unix" ) -const UserId = 1000 - func DropPrivs(cfg *config.Config) error { + userId := cfg.UserId if err := initSeccomp(cfg); err != nil { return fmt.Errorf("init seccomp: %w", err) } - if err := unix.Setresgid(UserId, UserId, UserId); err != nil { + if err := unix.Setresgid(userId, userId, userId); err != nil { return fmt.Errorf("setresgid jail: %w", err) } - if err := unix.Setgroups([]int{UserId}); err != nil { + if err := unix.Setgroups([]int{userId}); err != nil { return fmt.Errorf("setgroups jail: %w", err) } - if err := unix.Setresuid(UserId, UserId, UserId); err != nil { + if err := unix.Setresuid(userId, userId, userId); err != nil { return fmt.Errorf("setresuid jail: %w", err) } capHeader := &unix.CapUserHeader{Version: unix.LINUX_CAPABILITY_VERSION_3}