Skip to content

Commit

Permalink
fix: correct uid/gid non-root mapping
Browse files Browse the repository at this point in the history
Ensure e2e tests for oci actions use user profile.

Set uid/gid mappings explicitly. We need to do this anyone, going
forward, but here it works around:

containers/crun#1072
Signed-off-by: Edita Kizinevic <edita.kizinevic@cern.ch>
  • Loading branch information
dtrudg authored and edytuk committed May 24, 2023
1 parent 85b3008 commit 5a71276
Show file tree
Hide file tree
Showing 9 changed files with 111 additions and 18 deletions.
5 changes: 3 additions & 2 deletions cmd/internal/cli/build_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/apptainer/apptainer/internal/pkg/build"
"github.com/apptainer/apptainer/internal/pkg/buildcfg"
"github.com/apptainer/apptainer/internal/pkg/cache"
"github.com/apptainer/apptainer/internal/pkg/fakefake"
"github.com/apptainer/apptainer/internal/pkg/fakeroot"
"github.com/apptainer/apptainer/internal/pkg/remote/endpoint"
fakerootConfig "github.com/apptainer/apptainer/internal/pkg/runtime/engine/fakeroot/config"
Expand Down Expand Up @@ -90,7 +91,7 @@ func fakerootExec(isDeffile, unprivEncrypt bool) {
if buildArgs.ignoreUserns {
err = errors.New("could not start root-mapped namespace because --ignore-userns is set")
} else {
err = fakeroot.UnshareRootMapped(args)
err = fakefake.UnshareRootMapped(args)
}
if err == nil {
// All the work has been done by the child process
Expand Down Expand Up @@ -168,7 +169,7 @@ func runBuild(cmd *cobra.Command, args []string) {
if buildArgs.ignoreFakerootCmd {
err = errors.New("fakeroot command is ignored because of --ignore-fakeroot-command")
} else {
fakerootPath, err = fakeroot.FindFake()
fakerootPath, err = fakefake.FindFake()
}
if err != nil {
sylog.Infof("fakeroot command not found")
Expand Down
2 changes: 1 addition & 1 deletion e2e/actions/oci.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func (c actionTests) actionOciRun(t *testing.T) {
c.env.RunApptainer(
t,
e2e.AsSubtest(tt.name),
e2e.WithProfile(e2e.OCIRootProfile),
e2e.WithProfile(e2e.OCIUserProfile),
e2e.WithCommand("run"),
// While we don't support args we are entering a /bin/sh interactively.
e2e.ConsoleRun(e2e.ConsoleSendLine("exit")),
Expand Down
5 changes: 3 additions & 2 deletions internal/app/apptainer/overlay_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"runtime"
"strings"

"github.com/apptainer/apptainer/internal/pkg/fakefake"
"github.com/apptainer/apptainer/internal/pkg/fakeroot"
"github.com/apptainer/apptainer/internal/pkg/util/bin"
"github.com/apptainer/apptainer/pkg/image"
Expand Down Expand Up @@ -232,7 +233,7 @@ func OverlayCreate(size int, imgPath string, overlaySparse bool, isFakeroot bool
// the fakeroot command (in suid flow with no user
// namespaces), using the --fakeroot option here
// prevents overlay from working, most unfortunately.
err = fakeroot.UnshareRootMapped([]string{"/bin/true"})
err = fakefake.UnshareRootMapped([]string{"/bin/true"})
if err != nil {
sylog.Debugf("UnshareRootMapped failed: %v", err)
if isFakeroot {
Expand All @@ -248,7 +249,7 @@ func OverlayCreate(size int, imgPath string, overlaySparse bool, isFakeroot bool

if isFakeroot {
sylog.Debugf("Trying root-mapped namespace")
err = fakeroot.UnshareRootMapped(os.Args)
err = fakefake.UnshareRootMapped(os.Args)
if err == nil {
// everything was done by the child
os.Exit(0)
Expand Down
4 changes: 2 additions & 2 deletions internal/pkg/build/stage.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (

"github.com/apptainer/apptainer/internal/pkg/build/files"
"github.com/apptainer/apptainer/internal/pkg/buildcfg"
"github.com/apptainer/apptainer/internal/pkg/fakeroot"
"github.com/apptainer/apptainer/internal/pkg/fakefake"
"github.com/apptainer/apptainer/pkg/build/types"
"github.com/apptainer/apptainer/pkg/sylog"
)
Expand Down Expand Up @@ -99,7 +99,7 @@ func (s *stage) runPostScript(sessionResolv, sessionHosts string) error {
// the nested apptainer will run fakeroot if it isn't
// started and pass down the components and environment
// to nested apptainers.
fakerootBinds, err = fakeroot.GetFakeBinds(s.b.Opts.FakerootPath)
fakerootBinds, err = fakefake.GetFakeBinds(s.b.Opts.FakerootPath)
if err != nil {
return fmt.Errorf("while getting fakeroot bindpoints: %v", err)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
// This file is for "fake fakeroot", that is, root-mapped unprivileged
// user namespaces (unshare -r) and the fakeroot command

package fakeroot
package fakefake

import (
"bufio"
Expand Down
3 changes: 2 additions & 1 deletion internal/pkg/runtime/engine/apptainer/prepare_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/ProtonMail/go-crypto/openpgp"
"github.com/apptainer/apptainer/internal/pkg/buildcfg"
"github.com/apptainer/apptainer/internal/pkg/cgroups"
"github.com/apptainer/apptainer/internal/pkg/fakefake"
fakerootutil "github.com/apptainer/apptainer/internal/pkg/fakeroot"
"github.com/apptainer/apptainer/internal/pkg/image/driver"
"github.com/apptainer/apptainer/internal/pkg/instance"
Expand Down Expand Up @@ -98,7 +99,7 @@ func (e *EngineOperations) PrepareConfig(starterConfig *starter.Config) error {
if fakerootPath := e.EngineConfig.GetFakerootPath(); fakerootPath != "" {
// look for fakeroot again because the PATH used is
// more restricted at this point than it was earlier
newPath, err := fakerootutil.FindFake()
newPath, err := fakefake.FindFake()
if err != nil {
return fmt.Errorf("error finding fakeroot in privileged PATH: %v", err)
}
Expand Down
6 changes: 3 additions & 3 deletions internal/pkg/runtime/engine/apptainer/process_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import (
"unsafe"

"github.com/apptainer/apptainer/internal/pkg/checkpoint/dmtcp"
"github.com/apptainer/apptainer/internal/pkg/fakeroot"
"github.com/apptainer/apptainer/internal/pkg/fakefake"
"github.com/apptainer/apptainer/internal/pkg/instance"
"github.com/apptainer/apptainer/internal/pkg/plugin"
"github.com/apptainer/apptainer/internal/pkg/security"
Expand Down Expand Up @@ -889,7 +889,7 @@ func runActionScript(engineConfig *apptainerConfig.EngineConfig) ([]string, []st
}
}

fakeargs := fakeroot.GetFakeArgs()
fakeargs := fakefake.GetFakeArgs()
fakerootPath := fakeargs[0]
_, err = os.Stat(fakerootPath)
if err == nil && getEnvVal(penv, "FAKEROOTKEY") == "" {
Expand All @@ -906,7 +906,7 @@ func runActionScript(engineConfig *apptainerConfig.EngineConfig) ([]string, []st
if engineConfig.GetFakerootPath() == "" {
// Must be joining an instance, so also set BIND
// variables for nesting
fakebinds, _ := fakeroot.GetFakeBinds(fakerootPath)
fakebinds, _ := fakefake.GetFakeBinds(fakerootPath)
bindval := strings.Join(fakebinds, ",")
for _, pfx := range env.ApptainerPrefixes {
bindvar := pfx + "BIND="
Expand Down
9 changes: 5 additions & 4 deletions internal/pkg/runtime/launcher/native/launcher_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/apptainer/apptainer/internal/pkg/buildcfg"
"github.com/apptainer/apptainer/internal/pkg/cgroups"
"github.com/apptainer/apptainer/internal/pkg/checkpoint/dmtcp"
"github.com/apptainer/apptainer/internal/pkg/fakefake"
"github.com/apptainer/apptainer/internal/pkg/fakeroot"
"github.com/apptainer/apptainer/internal/pkg/image/driver"
"github.com/apptainer/apptainer/internal/pkg/image/unpacker"
Expand Down Expand Up @@ -133,7 +134,7 @@ func (l *Launcher) Exec(ctx context.Context, image string, process string, args
if l.cfg.IgnoreFakerootCmd {
err = errors.New("fakeroot command is ignored because of --ignore-fakeroot-command")
} else {
fakerootPath, err = fakeroot.FindFake()
fakerootPath, err = fakefake.FindFake()
}
if err != nil {
sylog.Infof("fakeroot command not found, using only root-mapped namespace")
Expand All @@ -147,7 +148,7 @@ func (l *Launcher) Exec(ctx context.Context, image string, process string, args
if l.cfg.IgnoreUserns {
err = errors.New("could not start root-mapped namespace because --ignore-userns is set")
} else {
err = fakeroot.UnshareRootMapped(os.Args)
err = fakefake.UnshareRootMapped(os.Args)
}
if err == nil {
// All good
Expand All @@ -157,7 +158,7 @@ func (l *Launcher) Exec(ctx context.Context, image string, process string, args
if l.cfg.IgnoreFakerootCmd {
err = errors.New("fakeroot command is ignored because of --ignore-fakeroot-command")
} else {
fakerootPath, err = fakeroot.FindFake()
fakerootPath, err = fakefake.FindFake()
}
if err != nil {
sylog.Fatalf("--fakeroot requires either being in %v, unprivileged user namespaces, or the fakeroot command", fakeroot.SubUIDFile)
Expand Down Expand Up @@ -663,7 +664,7 @@ func (l *Launcher) setBinds(fakerootPath string) error {
if fakerootPath != "" {
l.engineConfig.SetFakerootPath(fakerootPath)
// Add binds for fakeroot command
fakebindPaths, err := fakeroot.GetFakeBinds(fakerootPath)
fakebindPaths, err := fakefake.GetFakeBinds(fakerootPath)
if err != nil {
return fmt.Errorf("while getting fakeroot bindpoints: %w", err)
}
Expand Down
93 changes: 91 additions & 2 deletions pkg/ocibundle/native/bundle_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
apexlog "github.com/apex/log"
"github.com/apptainer/apptainer/internal/pkg/build/oci"
"github.com/apptainer/apptainer/internal/pkg/cache"
"github.com/apptainer/apptainer/internal/pkg/fakeroot"
"github.com/apptainer/apptainer/internal/pkg/runtime/engine/config/oci/generate"
"github.com/apptainer/apptainer/pkg/ocibundle"
"github.com/apptainer/apptainer/pkg/ocibundle/tools"
Expand Down Expand Up @@ -160,7 +161,9 @@ func (b *Bundle) Create(ctx context.Context, ociConfig *specs.Spec) error {
b.setProcessArgs(g)
// TODO - Handle custom env and user
b.setProcessEnv(g)
b.setProcessUser(g)
if err := b.setProcessUser(g); err != nil {
return err
}

return b.writeConfig(g)
}
Expand All @@ -170,14 +173,100 @@ func (b *Bundle) Path() string {
return b.bundlePath
}

func (b *Bundle) setProcessUser(g *generate.Generator) {
func (b *Bundle) setProcessUser(g *generate.Generator) error {
// Set non-root uid/gid per Apptainer defaults
uid := uint32(os.Getuid())
if uid != 0 {
gid := uint32(os.Getgid())
g.Config.Process.User.UID = uid
g.Config.Process.User.GID = gid
// Get user's configured subuid & subgid ranges
subuidRange, err := fakeroot.GetIDRange(fakeroot.SubUIDFile, uid)
if err != nil {
return err
}
// We must be able to map at least 0->65535 inside the container
if subuidRange.Size < 65536 {
return fmt.Errorf("subuid range size (%d) must be at least 65536", subuidRange.Size)
}
subgidRange, err := fakeroot.GetIDRange(fakeroot.SubGIDFile, uid)
if err != nil {
return err
}
if subgidRange.Size <= gid {
return fmt.Errorf("subuid range size (%d) must be at least 65536", subgidRange.Size)
}

// Preserve own uid container->host, map everything else to subuid range.
if uid < 65536 {
g.Config.Linux.UIDMappings = []specs.LinuxIDMapping{
{
ContainerID: 0,
HostID: subuidRange.HostID,
Size: uid,
},
{
ContainerID: uid,
HostID: uid,
Size: 1,
},
{
ContainerID: uid + 1,
HostID: subuidRange.HostID + uid,
Size: subuidRange.Size - uid,
},
}
} else {
g.Config.Linux.UIDMappings = []specs.LinuxIDMapping{
{
ContainerID: 0,
HostID: subuidRange.HostID,
Size: 65536,
},
{
ContainerID: uid,
HostID: uid,
Size: 1,
},
}
}

// Preserve own gid container->host, map everything else to subgid range.
if gid < 65536 {
g.Config.Linux.GIDMappings = []specs.LinuxIDMapping{
{
ContainerID: 0,
HostID: subgidRange.HostID,
Size: gid,
},
{
ContainerID: gid,
HostID: gid,
Size: 1,
},
{
ContainerID: gid + 1,
HostID: subgidRange.HostID + gid,
Size: subgidRange.Size - gid,
},
}
} else {
g.Config.Linux.GIDMappings = []specs.LinuxIDMapping{
{
ContainerID: 0,
HostID: subgidRange.HostID,
Size: 65536,
},
{
ContainerID: gid,
HostID: gid,
Size: 1,
},
}
}
g.Config.Linux.Namespaces = append(g.Config.Linux.Namespaces, specs.LinuxNamespace{Type: "user"})
}
return nil
}

func (b *Bundle) setProcessEnv(g *generate.Generator) {
Expand Down

0 comments on commit 5a71276

Please sign in to comment.