diff --git a/.github/contributors.yaml b/.github/contributors.yaml index 115a711b..99414634 100644 --- a/.github/contributors.yaml +++ b/.github/contributors.yaml @@ -113,3 +113,7 @@ users: pocopepe: name: Viju Sanjai email: avijusanjai@gmail.com + Anand-240: + name: Anand Prakash Srivastava + email: anandprakashsrivastava68@gmail.com + diff --git a/pkg/unikontainers/unikontainers.go b/pkg/unikontainers/unikontainers.go index bc43bcac..b218c4ce 100644 --- a/pkg/unikontainers/unikontainers.go +++ b/pkg/unikontainers/unikontainers.go @@ -698,10 +698,12 @@ func (u *Unikontainer) Exec(metrics m.Writer) error { // pivot _, err = findNS(u.Spec.Linux.Namespaces, specs.MountNamespace) - // We just want to check if a mount namespace was define din the list - // Therefore, if there was no error and the mount namespace was found - // we can pivot. - withPivot := err != nil + // Only pivot if a mount namespace entry is actually present in the + // spec, either to join (err is nil) or to create (err is + // ErrNotExistingNS). If the entry is missing entirely, no new mount + // namespace gets created and we have to chroot instead, otherwise + // pivot_root would run against the caller's own root filesystem. + withPivot := err == nil || errors.Is(err, ErrNotExistingNS) err = changeRoot(rootfsParams.MonRootfs, withPivot) if err != nil { return err diff --git a/pkg/unikontainers/utils_test.go b/pkg/unikontainers/utils_test.go index b779b982..2d23ea33 100644 --- a/pkg/unikontainers/utils_test.go +++ b/pkg/unikontainers/utils_test.go @@ -16,6 +16,7 @@ package unikontainers import ( "encoding/json" + "errors" "os" "path/filepath" "strconv" @@ -240,6 +241,47 @@ func TestRemovePreservesOrder(t *testing.T) { assert.Equal(t, []string{"b", "c", "d"}, result) } +// TestFindNS checks that findNS lets callers tell apart a namespace type +// missing from the spec from one that's present but not created yet +// (empty path). Exec() relies on that distinction to decide when it's +// safe to pivot_root. +func TestFindNS(t *testing.T) { + t.Parallel() + + t.Run("namespace type missing from spec", func(t *testing.T) { + t.Parallel() + namespaces := []specs.LinuxNamespace{ + {Type: specs.NetworkNamespace, Path: "/dummy/path"}, + } + path, err := findNS(namespaces, specs.MountNamespace) + assert.Empty(t, path) + assert.Error(t, err) + assert.False(t, errors.Is(err, ErrNotExistingNS), "a namespace type absent from the spec must not be reported as ErrNotExistingNS") + }) + + t.Run("namespace present without a path yet", func(t *testing.T) { + t.Parallel() + namespaces := []specs.LinuxNamespace{ + {Type: specs.MountNamespace, Path: ""}, + } + path, err := findNS(namespaces, specs.MountNamespace) + assert.Empty(t, path) + assert.ErrorIs(t, err, ErrNotExistingNS) + }) + + t.Run("namespace present with an existing path", func(t *testing.T) { + t.Parallel() + nsPath := t.TempDir() + + namespaces := []specs.LinuxNamespace{ + {Type: specs.MountNamespace, Path: nsPath}, + } + path, err := findNS(namespaces, specs.MountNamespace) + assert.NoError(t, err) + assert.Equal(t, nsPath, path) + }) +} + func TestLoadSpec(t *testing.T) { t.Run("load spec success", func(t *testing.T) { t.Parallel()