diff --git a/sandbox/container_test.go b/sandbox/container_test.go index d47fd12..5ed9fee 100644 --- a/sandbox/container_test.go +++ b/sandbox/container_test.go @@ -93,7 +93,7 @@ func TestContainer(t *testing.T) { container. Tmpfs("/tmp", 0, 0755). Bind(os.Args[0], os.Args[0], 0). - Mkdir("/usr/bin"). + Mkdir("/usr/bin", 0755). Link(os.Args[0], "/usr/bin/sandbox.test"). Place("/etc/hostname", []byte(container.Args[5])) // in case test has cgo enabled diff --git a/sandbox/mount.go b/sandbox/mount.go index 6683aae..abad54c 100644 --- a/sandbox/mount.go +++ b/sandbox/mount.go @@ -101,7 +101,7 @@ func remountWithFlags(n *vfs.MountInfoNode, mf uintptr) error { func mountTmpfs(fsname, name string, size int, perm os.FileMode) error { target := toSysroot(name) - if err := os.MkdirAll(target, perm); err != nil { + if err := os.MkdirAll(target, parentPerm(perm)); err != nil { return msg.WrapErr(err, err.Error()) } opt := fmt.Sprintf("mode=%#o", perm) @@ -112,3 +112,14 @@ func mountTmpfs(fsname, name string, size int, perm os.FileMode) error { syscall.MS_NOSUID|syscall.MS_NODEV, opt), fmt.Sprintf("cannot mount tmpfs on %q:", name)) } + +func parentPerm(perm os.FileMode) os.FileMode { + pperm := 0755 + if perm&0070 == 0 { + pperm &= ^0050 + } + if perm&0007 == 0 { + pperm &= ^0005 + } + return os.FileMode(pperm) +} diff --git a/sandbox/path.go b/sandbox/path.go index 78c5a99..bc40026 100644 --- a/sandbox/path.go +++ b/sandbox/path.go @@ -30,8 +30,8 @@ func toHost(name string) string { return path.Join(hostPath, name) } -func createFile(name string, perm os.FileMode, content []byte) error { - if err := os.MkdirAll(path.Dir(name), 0755); err != nil { +func createFile(name string, perm, pperm os.FileMode, content []byte) error { + if err := os.MkdirAll(path.Dir(name), pperm); err != nil { return msg.WrapErr(err, err.Error()) } f, err := os.OpenFile(name, syscall.O_CREAT|syscall.O_EXCL|syscall.O_WRONLY, perm) @@ -47,13 +47,13 @@ func createFile(name string, perm os.FileMode, content []byte) error { return errors.Join(f.Close(), err) } -func ensureFile(name string, perm os.FileMode) error { +func ensureFile(name string, perm, pperm os.FileMode) error { fi, err := os.Stat(name) if err != nil { if !os.IsNotExist(err) { return err } - return createFile(name, perm, nil) + return createFile(name, perm, pperm, nil) } if mode := fi.Mode(); mode&fs.ModeDir != 0 || mode&fs.ModeSymlink != 0 { diff --git a/sandbox/sequential.go b/sandbox/sequential.go index 4af38d0..f37567d 100644 --- a/sandbox/sequential.go +++ b/sandbox/sequential.go @@ -61,13 +61,16 @@ func (b *BindMount) apply(*Params) error { source := toHost(b.SourceFinal) target := toSysroot(b.Target) + + // this perm value emulates bwrap behaviour as it clears bits from 0755 based on + // op->perms which is never set for any bind setup op so always results in 0700 if fi, err := os.Stat(source); err != nil { return msg.WrapErr(err, err.Error()) } else if fi.IsDir() { - if err = os.MkdirAll(target, 0755); err != nil { + if err = os.MkdirAll(target, 0700); err != nil { return msg.WrapErr(err, err.Error()) } - } else if err = ensureFile(target, 0444); err != nil { + } else if err = ensureFile(target, 0444, 0700); err != nil { return err } @@ -147,7 +150,7 @@ func (d MountDev) apply(params *Params) error { for _, name := range []string{"null", "zero", "full", "random", "urandom", "tty"} { targetPath := toSysroot(path.Join(v, name)) - if err := ensureFile(targetPath, 0444); err != nil { + if err := ensureFile(targetPath, 0444, 0755); err != nil { return err } if err := hostProc.bindMount( @@ -198,7 +201,7 @@ func (d MountDev) apply(params *Params) error { uintptr(unsafe.Pointer(&buf[0])), ); errno == 0 { consolePath := toSysroot(path.Join(v, "console")) - if err := ensureFile(consolePath, 0444); err != nil { + if err := ensureFile(consolePath, 0444, 0755); err != nil { return err } if err := hostProc.bindMount( @@ -313,29 +316,29 @@ func (f *Ops) Link(target, linkName string) *Ops { func init() { gob.Register(new(Mkdir)) } // Mkdir creates a directory in the container filesystem. -type Mkdir string +type Mkdir struct { + Path string + Perm os.FileMode +} -func (m Mkdir) early(*Params) error { return nil } -func (m Mkdir) apply(*Params) error { - v := string(m) - - if !path.IsAbs(v) { +func (m *Mkdir) early(*Params) error { return nil } +func (m *Mkdir) apply(*Params) error { + if !path.IsAbs(m.Path) { return msg.WrapErr(syscall.EBADE, - fmt.Sprintf("path %q is not absolute", v)) + fmt.Sprintf("path %q is not absolute", m.Path)) } - target := toSysroot(v) - if err := os.MkdirAll(target, 0755); err != nil { + if err := os.MkdirAll(toSysroot(m.Path), m.Perm); err != nil { return msg.WrapErr(err, err.Error()) } return nil } -func (m Mkdir) Is(op Op) bool { vm, ok := op.(Mkdir); return ok && m == vm } -func (Mkdir) prefix() string { return "creating" } -func (m Mkdir) String() string { return fmt.Sprintf("directory %q", string(m)) } -func (f *Ops) Mkdir(dest string) *Ops { - *f = append(*f, Mkdir(dest)) +func (m *Mkdir) Is(op Op) bool { vm, ok := op.(*Mkdir); return ok && m == vm } +func (*Mkdir) prefix() string { return "creating" } +func (m *Mkdir) String() string { return fmt.Sprintf("directory %q perm %s", m.Path, m.Perm) } +func (f *Ops) Mkdir(dest string, perm os.FileMode) *Ops { + *f = append(*f, &Mkdir{dest, perm}) return f } @@ -368,7 +371,7 @@ func (t *Tmpfile) apply(*Params) error { } target := toSysroot(t.Path) - if err := ensureFile(target, 0444); err != nil { + if err := ensureFile(target, 0444, 0755); err != nil { return err } else if err = hostProc.bindMount( tmpPath,