diff --git a/sandbox/container.go b/sandbox/container.go index fd6c588..df15810 100644 --- a/sandbox/container.go +++ b/sandbox/container.go @@ -11,7 +11,7 @@ import ( "os/exec" "path" "strconv" - "syscall" + . "syscall" "time" "git.gensokyo.uk/security/hakurei/sandbox/seccomp" @@ -119,11 +119,9 @@ func (p *Container) Start() error { ctx, cancel := context.WithCancel(p.ctx) p.cancel = cancel - var cloneFlags uintptr = syscall.CLONE_NEWIPC | - syscall.CLONE_NEWUTS | - syscall.CLONE_NEWCGROUP + var cloneFlags uintptr = CLONE_NEWIPC | CLONE_NEWUTS | CLONE_NEWCGROUP if p.Flags&FAllowNet == 0 { - cloneFlags |= syscall.CLONE_NEWNET + cloneFlags |= CLONE_NEWNET } // map to overflow id to work around ownership checks @@ -146,17 +144,13 @@ func (p *Container) Start() error { if p.Cancel != nil { p.cmd.Cancel = func() error { return p.Cancel(p.cmd) } } else { - p.cmd.Cancel = func() error { return p.cmd.Process.Signal(syscall.SIGTERM) } + p.cmd.Cancel = func() error { return p.cmd.Process.Signal(SIGTERM) } } p.cmd.Dir = "/" - p.cmd.SysProcAttr = &syscall.SysProcAttr{ - Setsid: p.Flags&FAllowTTY == 0, - Pdeathsig: syscall.SIGKILL, - - Cloneflags: cloneFlags | - syscall.CLONE_NEWUSER | - syscall.CLONE_NEWPID | - syscall.CLONE_NEWNS, + p.cmd.SysProcAttr = &SysProcAttr{ + Setsid: p.Flags&FAllowTTY == 0, + Pdeathsig: SIGKILL, + Cloneflags: cloneFlags | CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNS, // remain privileged for setup AmbientCaps: []uintptr{CAP_SYS_ADMIN, CAP_SETPCAP}, @@ -194,7 +188,7 @@ func (p *Container) Serve() error { if p.Path != "" && !path.IsAbs(p.Path) { p.cancel() - return msg.WrapErr(syscall.EINVAL, + return msg.WrapErr(EINVAL, fmt.Sprintf("invalid executable path %q", p.Path)) } @@ -203,7 +197,7 @@ func (p *Container) Serve() error { p.Path = os.Getenv("SHELL") if !path.IsAbs(p.Path) { p.cancel() - return msg.WrapErr(syscall.EBADE, + return msg.WrapErr(EBADE, "no command specified and $SHELL is invalid") } p.name = path.Base(p.Path) @@ -220,8 +214,8 @@ func (p *Container) Serve() error { err := setup.Encode( &initParams{ p.Params, - syscall.Getuid(), - syscall.Getgid(), + Getuid(), + Getgid(), len(p.ExtraFiles), msg.IsVerbose(), }, diff --git a/sandbox/init.go b/sandbox/init.go index 4fcdd9c..2fa84e6 100644 --- a/sandbox/init.go +++ b/sandbox/init.go @@ -10,7 +10,7 @@ import ( "path" "runtime" "strconv" - "syscall" + . "syscall" "time" "git.gensokyo.uk/security/hakurei/sandbox/seccomp" @@ -97,9 +97,9 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) { log.Fatalf("cannot set SUID_DUMP_DISABLE: %s", err) } - oldmask := syscall.Umask(0) + oldmask := Umask(0) if params.Hostname != "" { - if err := syscall.Sethostname([]byte(params.Hostname)); err != nil { + if err := Sethostname([]byte(params.Hostname)); err != nil { log.Fatalf("cannot set hostname: %v", err) } } @@ -107,9 +107,7 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) { // cache sysctl before pivot_root LastCap() - if err := syscall.Mount("", "/", "", - syscall.MS_SILENT|syscall.MS_SLAVE|syscall.MS_REC, - ""); err != nil { + if err := Mount("", "/", "", MS_SILENT|MS_SLAVE|MS_REC, ""); err != nil { log.Fatalf("cannot make / rslave: %v", err) } @@ -126,9 +124,7 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) { } } - if err := syscall.Mount("rootfs", basePath, "tmpfs", - syscall.MS_NODEV|syscall.MS_NOSUID, - ""); err != nil { + if err := Mount("rootfs", basePath, "tmpfs", MS_NODEV|MS_NOSUID, ""); err != nil { log.Fatalf("cannot mount intermediate root: %v", err) } if err := os.Chdir(basePath); err != nil { @@ -138,9 +134,7 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) { if err := os.Mkdir(sysrootDir, 0755); err != nil { log.Fatalf("%v", err) } - if err := syscall.Mount(sysrootDir, sysrootDir, "", - syscall.MS_SILENT|syscall.MS_MGC_VAL|syscall.MS_BIND|syscall.MS_REC, - ""); err != nil { + if err := Mount(sysrootDir, sysrootDir, "", MS_SILENT|MS_MGC_VAL|MS_BIND|MS_REC, ""); err != nil { log.Fatalf("cannot bind sysroot: %v", err) } @@ -148,7 +142,7 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) { log.Fatalf("%v", err) } // pivot_root uncovers basePath in hostDir - if err := syscall.PivotRoot(basePath, hostDir); err != nil { + if err := PivotRoot(basePath, hostDir); err != nil { log.Fatalf("cannot pivot into intermediate root: %v", err) } if err := os.Chdir("/"); err != nil { @@ -167,19 +161,17 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) { } // setup requiring host root complete at this point - if err := syscall.Mount(hostDir, hostDir, "", - syscall.MS_SILENT|syscall.MS_REC|syscall.MS_PRIVATE, - ""); err != nil { + if err := Mount(hostDir, hostDir, "", MS_SILENT|MS_REC|MS_PRIVATE, ""); err != nil { log.Fatalf("cannot make host root rprivate: %v", err) } - if err := syscall.Unmount(hostDir, syscall.MNT_DETACH); err != nil { + if err := Unmount(hostDir, MNT_DETACH); err != nil { log.Fatalf("cannot unmount host root: %v", err) } { var fd int if err := IgnoringEINTR(func() (err error) { - fd, err = syscall.Open("/", syscall.O_DIRECTORY|syscall.O_RDONLY, 0) + fd, err = Open("/", O_DIRECTORY|O_RDONLY, 0) return }); err != nil { log.Fatalf("cannot open intermediate root: %v", err) @@ -188,36 +180,36 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) { log.Fatalf("%v", err) } - if err := syscall.PivotRoot(".", "."); err != nil { + if err := PivotRoot(".", "."); err != nil { log.Fatalf("cannot pivot into sysroot: %v", err) } - if err := syscall.Fchdir(fd); err != nil { + if err := Fchdir(fd); err != nil { log.Fatalf("cannot re-enter intermediate root: %v", err) } - if err := syscall.Unmount(".", syscall.MNT_DETACH); err != nil { + if err := Unmount(".", MNT_DETACH); err != nil { log.Fatalf("cannot unmount intemediate root: %v", err) } if err := os.Chdir("/"); err != nil { log.Fatalf("%v", err) } - if err := syscall.Close(fd); err != nil { + if err := Close(fd); err != nil { log.Fatalf("cannot close intermediate root: %v", err) } } - if _, _, errno := syscall.Syscall(PR_SET_NO_NEW_PRIVS, 1, 0, 0); errno != 0 { + if _, _, errno := Syscall(PR_SET_NO_NEW_PRIVS, 1, 0, 0); errno != 0 { log.Fatalf("prctl(PR_SET_NO_NEW_PRIVS): %v", errno) } - if _, _, errno := syscall.Syscall(syscall.SYS_PRCTL, PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0); errno != 0 { + if _, _, errno := Syscall(SYS_PRCTL, PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0); errno != 0 { log.Fatalf("cannot clear the ambient capability set: %v", errno) } for i := uintptr(0); i <= LastCap(); i++ { if params.Privileged && i == CAP_SYS_ADMIN { continue } - if _, _, errno := syscall.Syscall(syscall.SYS_PRCTL, syscall.PR_CAPBSET_DROP, i, 0); errno != 0 { + if _, _, errno := Syscall(SYS_PRCTL, PR_CAPBSET_DROP, i, 0); errno != 0 { log.Fatalf("cannot drop capability from bonding set: %v", errno) } } @@ -226,7 +218,7 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) { if params.Privileged { keep[capToIndex(CAP_SYS_ADMIN)] |= capToMask(CAP_SYS_ADMIN) - if _, _, errno := syscall.Syscall(syscall.SYS_PRCTL, PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_SYS_ADMIN); errno != 0 { + if _, _, errno := Syscall(SYS_PRCTL, PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_SYS_ADMIN); errno != 0 { log.Fatalf("cannot raise CAP_SYS_ADMIN: %v", errno) } } @@ -246,7 +238,7 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) { // setup fd is placed before all extra files extraFiles[i] = os.NewFile(uintptr(offsetSetup+i), "extra file "+strconv.Itoa(i)) } - syscall.Umask(oldmask) + Umask(oldmask) cmd := exec.Command(params.Path) cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr @@ -267,7 +259,7 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) { type winfo struct { wpid int - wstatus syscall.WaitStatus + wstatus WaitStatus } info := make(chan winfo, 1) done := make(chan struct{}) @@ -276,7 +268,7 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) { var ( err error wpid = -2 - wstatus syscall.WaitStatus + wstatus WaitStatus ) // keep going until no child process is left @@ -289,12 +281,12 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) { info <- winfo{wpid, wstatus} } - err = syscall.EINTR - for errors.Is(err, syscall.EINTR) { - wpid, err = syscall.Wait4(-1, &wstatus, 0, nil) + err = EINTR + for errors.Is(err, EINTR) { + wpid, err = Wait4(-1, &wstatus, 0, nil) } } - if !errors.Is(err, syscall.ECHILD) { + if !errors.Is(err, ECHILD) { log.Println("unexpected wait4 response:", err) } @@ -303,7 +295,7 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) { // handle signals to dump withheld messages sig := make(chan os.Signal, 2) - signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM) + signal.Notify(sig, SIGINT, SIGTERM) // closed after residualProcessTimeout has elapsed after initial process death timeout := make(chan struct{}) diff --git a/sandbox/mount.go b/sandbox/mount.go index 73dd14a..4dc7c0e 100644 --- a/sandbox/mount.go +++ b/sandbox/mount.go @@ -5,7 +5,7 @@ import ( "fmt" "os" "path/filepath" - "syscall" + . "syscall" "git.gensokyo.uk/security/hakurei/sandbox/vfs" ) @@ -17,8 +17,7 @@ func (p *procPaths) bindMount(source, target string, flags uintptr, eq bool) err msg.Verbosef("resolved %q on %q flags %#x", source, target, flags) } - if err := syscall.Mount(source, target, "", - syscall.MS_SILENT|syscall.MS_BIND|flags&syscall.MS_REC, ""); err != nil { + if err := Mount(source, target, "", MS_SILENT|MS_BIND|flags&MS_REC, ""); err != nil { return wrapErrSuffix(err, fmt.Sprintf("cannot mount %q on %q:", source, target)) } @@ -38,7 +37,7 @@ func (p *procPaths) bindMount(source, target string, flags uintptr, eq bool) err { var destFd int if err := IgnoringEINTR(func() (err error) { - destFd, err = syscall.Open(targetFinal, O_PATH|syscall.O_CLOEXEC, 0) + destFd, err = Open(targetFinal, O_PATH|O_CLOEXEC, 0) return }); err != nil { return wrapErrSuffix(err, @@ -46,7 +45,7 @@ func (p *procPaths) bindMount(source, target string, flags uintptr, eq bool) err } if v, err := os.Readlink(p.fd(destFd)); err != nil { return wrapErrSelf(err) - } else if err = syscall.Close(destFd); err != nil { + } else if err = Close(destFd); err != nil { return wrapErrSuffix(err, fmt.Sprintf("cannot close %q:", targetFinal)) } else { @@ -54,11 +53,11 @@ func (p *procPaths) bindMount(source, target string, flags uintptr, eq bool) err } } - mf := syscall.MS_NOSUID | flags&syscall.MS_NODEV | flags&syscall.MS_RDONLY + mf := MS_NOSUID | flags&MS_NODEV | flags&MS_RDONLY return hostProc.mountinfo(func(d *vfs.MountInfoDecoder) error { n, err := d.Unfold(targetKFinal) if err != nil { - if errors.Is(err, syscall.ESTALE) { + if errors.Is(err, ESTALE) { return msg.WrapErr(err, fmt.Sprintf("mount point %q never appeared in mountinfo", targetKFinal)) } @@ -69,13 +68,13 @@ func (p *procPaths) bindMount(source, target string, flags uintptr, eq bool) err if err = remountWithFlags(n, mf); err != nil { return err } - if flags&syscall.MS_REC == 0 { + if flags&MS_REC == 0 { return nil } for cur := range n.Collective() { err = remountWithFlags(cur, mf) - if err != nil && !errors.Is(err, syscall.EACCES) { + if err != nil && !errors.Is(err, EACCES) { return err } } @@ -91,9 +90,8 @@ func remountWithFlags(n *vfs.MountInfoNode, mf uintptr) error { } if kf&mf != mf { - return wrapErrSuffix(syscall.Mount("none", n.Clean, "", - syscall.MS_SILENT|syscall.MS_BIND|syscall.MS_REMOUNT|kf|mf, - ""), + return wrapErrSuffix( + Mount("none", n.Clean, "", MS_SILENT|MS_BIND|MS_REMOUNT|kf|mf, ""), fmt.Sprintf("cannot remount %q:", n.Clean)) } return nil @@ -108,8 +106,8 @@ func mountTmpfs(fsname, name string, size int, perm os.FileMode) error { if size > 0 { opt += fmt.Sprintf(",size=%d", size) } - return wrapErrSuffix(syscall.Mount(fsname, target, "tmpfs", - syscall.MS_NOSUID|syscall.MS_NODEV, opt), + return wrapErrSuffix( + Mount(fsname, target, "tmpfs", MS_NOSUID|MS_NODEV, opt), fmt.Sprintf("cannot mount tmpfs on %q:", name)) } diff --git a/sandbox/ops.go b/sandbox/ops.go index 26aaec7..5226c7a 100644 --- a/sandbox/ops.go +++ b/sandbox/ops.go @@ -9,7 +9,7 @@ import ( "path/filepath" "slices" "strings" - "syscall" + . "syscall" "unsafe" ) @@ -46,8 +46,7 @@ const ( func (b *BindMountOp) early(*Params) error { if !path.IsAbs(b.Source) { - return msg.WrapErr(syscall.EBADE, - fmt.Sprintf("path %q is not absolute", b.Source)) + return msg.WrapErr(EBADE, fmt.Sprintf("path %q is not absolute", b.Source)) } if v, err := filepath.EvalSymlinks(b.Source); err != nil { @@ -66,14 +65,13 @@ func (b *BindMountOp) apply(*Params) error { if b.SourceFinal == "\x00" { if b.Flags&BindOptional == 0 { // unreachable - return syscall.EBADE + return EBADE } return nil } if !path.IsAbs(b.SourceFinal) || !path.IsAbs(b.Target) { - return msg.WrapErr(syscall.EBADE, - "path is not absolute") + return msg.WrapErr(EBADE, "path is not absolute") } source := toHost(b.SourceFinal) @@ -91,12 +89,12 @@ func (b *BindMountOp) apply(*Params) error { return err } - var flags uintptr = syscall.MS_REC + var flags uintptr = MS_REC if b.Flags&BindWritable == 0 { - flags |= syscall.MS_RDONLY + flags |= MS_RDONLY } if b.Flags&BindDevice == 0 { - flags |= syscall.MS_NODEV + flags |= MS_NODEV } return hostProc.bindMount(source, target, flags, b.SourceFinal == b.Target) @@ -125,16 +123,14 @@ func (p MountProcOp) apply(params *Params) error { v := string(p) if !path.IsAbs(v) { - return msg.WrapErr(syscall.EBADE, - fmt.Sprintf("path %q is not absolute", v)) + return msg.WrapErr(EBADE, fmt.Sprintf("path %q is not absolute", v)) } target := toSysroot(v) if err := os.MkdirAll(target, params.ParentPerm); err != nil { return wrapErrSelf(err) } - return wrapErrSuffix(syscall.Mount("proc", target, "proc", - syscall.MS_NOSUID|syscall.MS_NOEXEC|syscall.MS_NODEV, ""), + return wrapErrSuffix(Mount("proc", target, "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, ""), fmt.Sprintf("cannot mount proc on %q:", v)) } @@ -156,8 +152,7 @@ func (d MountDevOp) apply(params *Params) error { v := string(d) if !path.IsAbs(v) { - return msg.WrapErr(syscall.EBADE, - fmt.Sprintf("path %q is not absolute", v)) + return msg.WrapErr(EBADE, fmt.Sprintf("path %q is not absolute", v)) } target := toSysroot(v) @@ -204,8 +199,7 @@ func (d MountDevOp) apply(params *Params) error { } } - if err := syscall.Mount("devpts", devPtsPath, "devpts", - syscall.MS_NOSUID|syscall.MS_NOEXEC, + if err := Mount("devpts", devPtsPath, "devpts", MS_NOSUID|MS_NOEXEC, "newinstance,ptmxmode=0666,mode=620"); err != nil { return wrapErrSuffix(err, fmt.Sprintf("cannot mount devpts on %q:", devPtsPath)) @@ -213,10 +207,7 @@ func (d MountDevOp) apply(params *Params) error { if params.Flags&FAllowTTY != 0 { var buf [8]byte - if _, _, errno := syscall.Syscall( - syscall.SYS_IOCTL, 1, syscall.TIOCGWINSZ, - uintptr(unsafe.Pointer(&buf[0])), - ); errno == 0 { + if _, _, errno := Syscall(SYS_IOCTL, 1, TIOCGWINSZ, uintptr(unsafe.Pointer(&buf[0]))); errno == 0 { consolePath := toSysroot(path.Join(v, "console")) if err := ensureFile(consolePath, 0444, params.ParentPerm); err != nil { return err @@ -255,16 +246,14 @@ func (m MountMqueueOp) apply(params *Params) error { v := string(m) if !path.IsAbs(v) { - return msg.WrapErr(syscall.EBADE, - fmt.Sprintf("path %q is not absolute", v)) + return msg.WrapErr(EBADE, fmt.Sprintf("path %q is not absolute", v)) } target := toSysroot(v) if err := os.MkdirAll(target, params.ParentPerm); err != nil { return wrapErrSelf(err) } - return wrapErrSuffix(syscall.Mount("mqueue", target, "mqueue", - syscall.MS_NOSUID|syscall.MS_NOEXEC|syscall.MS_NODEV, ""), + return wrapErrSuffix(Mount("mqueue", target, "mqueue", MS_NOSUID|MS_NOEXEC|MS_NODEV, ""), fmt.Sprintf("cannot mount mqueue on %q:", v)) } @@ -288,12 +277,10 @@ type MountTmpfsOp struct { func (t *MountTmpfsOp) early(*Params) error { return nil } func (t *MountTmpfsOp) apply(*Params) error { if !path.IsAbs(t.Path) { - return msg.WrapErr(syscall.EBADE, - fmt.Sprintf("path %q is not absolute", t.Path)) + return msg.WrapErr(EBADE, fmt.Sprintf("path %q is not absolute", t.Path)) } if t.Size < 0 || t.Size > math.MaxUint>>1 { - return msg.WrapErr(syscall.EBADE, - fmt.Sprintf("size %d out of bounds", t.Size)) + return msg.WrapErr(EBADE, fmt.Sprintf("size %d out of bounds", t.Size)) } return mountTmpfs("tmpfs", t.Path, t.Size, t.Perm) } @@ -315,8 +302,7 @@ func (l *SymlinkOp) early(*Params) error { if strings.HasPrefix(l[0], "*") { l[0] = l[0][1:] if !path.IsAbs(l[0]) { - return msg.WrapErr(syscall.EBADE, - fmt.Sprintf("path %q is not absolute", l[0])) + return msg.WrapErr(EBADE, fmt.Sprintf("path %q is not absolute", l[0])) } if name, err := os.Readlink(l[0]); err != nil { return wrapErrSelf(err) @@ -329,8 +315,7 @@ func (l *SymlinkOp) early(*Params) error { func (l *SymlinkOp) apply(params *Params) error { // symlink target is an arbitrary path value, so only validate link name here if !path.IsAbs(l[1]) { - return msg.WrapErr(syscall.EBADE, - fmt.Sprintf("path %q is not absolute", l[1])) + return msg.WrapErr(EBADE, fmt.Sprintf("path %q is not absolute", l[1])) } target := toSysroot(l[1]) @@ -362,8 +347,7 @@ type MkdirOp struct { func (m *MkdirOp) early(*Params) error { return nil } func (m *MkdirOp) apply(*Params) error { if !path.IsAbs(m.Path) { - return msg.WrapErr(syscall.EBADE, - fmt.Sprintf("path %q is not absolute", m.Path)) + return msg.WrapErr(EBADE, fmt.Sprintf("path %q is not absolute", m.Path)) } if err := os.MkdirAll(toSysroot(m.Path), m.Perm); err != nil { @@ -391,8 +375,7 @@ type TmpfileOp struct { func (t *TmpfileOp) early(*Params) error { return nil } func (t *TmpfileOp) apply(params *Params) error { if !path.IsAbs(t.Path) { - return msg.WrapErr(syscall.EBADE, - fmt.Sprintf("path %q is not absolute", t.Path)) + return msg.WrapErr(EBADE, fmt.Sprintf("path %q is not absolute", t.Path)) } var tmpPath string @@ -414,7 +397,7 @@ func (t *TmpfileOp) apply(params *Params) error { } else if err = hostProc.bindMount( tmpPath, target, - syscall.MS_RDONLY|syscall.MS_NODEV, + MS_RDONLY|MS_NODEV, false, ); err != nil { return err