diff options
| author | Ophestra <cat@gensokyo.uk> | 2025-03-14 00:16:41 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2025-03-14 00:16:41 +0900 |
| commit | f1002157a58a5a0a559ba9295c3193c300a4235d (patch) | |
| tree | f0f388e84a4a6a30e39efc7bf6ee3202b99ce833 /internal/sandbox/mount.go | |
| parent | 4133b555ba8dd38accb272d86c01898ac4b99f95 (diff) | |
sandbox: separate bind mount function from op
This is useful in the implementation of various other ops.
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal/sandbox/mount.go')
| -rw-r--r-- | internal/sandbox/mount.go | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/internal/sandbox/mount.go b/internal/sandbox/mount.go new file mode 100644 index 00000000..3c6ae2d8 --- /dev/null +++ b/internal/sandbox/mount.go @@ -0,0 +1,81 @@ +package sandbox + +import ( + "errors" + "fmt" + "os" + "strings" + "syscall" + + "git.gensokyo.uk/security/fortify/internal/fmsg" +) + +const ( + BindOptional = 1 << iota + BindSource + BindRecursive + BindWritable + BindDevices +) + +func bindMount(src, dest string, flags int) error { + target := toSysroot(dest) + var source string + + if flags&BindSource == 0 { + // this is what bwrap does, so the behaviour is kept for now, + // however recursively resolving links might improve user experience + if rp, err := realpathHost(src); err != nil { + if os.IsNotExist(err) { + if flags&BindOptional != 0 { + return nil + } else { + return fmsg.WrapError(err, + fmt.Sprintf("path %q does not exist", src)) + } + } + return fmsg.WrapError(err, err.Error()) + } else { + source = toHost(rp) + } + } else if flags&BindOptional != 0 { + return fmsg.WrapError(syscall.EINVAL, + "flag source excludes optional") + } + + if fi, err := os.Stat(source); err != nil { + return fmsg.WrapError(err, err.Error()) + } else if fi.IsDir() { + if err = os.MkdirAll(target, 0755); err != nil { + return fmsg.WrapErrorSuffix(err, + fmt.Sprintf("cannot create directory %q:", dest)) + } + } else if err = ensureFile(target, 0444); err != nil { + if errors.Is(err, syscall.EISDIR) { + return fmsg.WrapError(err, + fmt.Sprintf("path %q is a directory", dest)) + } + return fmsg.WrapErrorSuffix(err, + fmt.Sprintf("cannot create %q:", dest)) + } + + var mf uintptr = syscall.MS_SILENT | syscall.MS_BIND + if flags&BindRecursive != 0 { + mf |= syscall.MS_REC + } + if flags&BindWritable == 0 { + mf |= syscall.MS_RDONLY + } + if flags&BindDevices == 0 { + mf |= syscall.MS_NODEV + } + if fmsg.Load() { + if strings.TrimPrefix(source, hostPath) == strings.TrimPrefix(target, sysrootPath) { + fmsg.Verbosef("resolved %q flags %#x", target, mf) + } else { + fmsg.Verbosef("resolved %q on %q flags %#x", source, target, mf) + } + } + return fmsg.WrapErrorSuffix(syscall.Mount(source, target, "", mf, ""), + fmt.Sprintf("cannot bind %q on %q:", src, dest)) +} |
