diff options
author | Kamil Trzciński <ayufan@ayufan.eu> | 2020-09-01 13:18:10 +0300 |
---|---|---|
committer | Kamil Trzciński <ayufan@ayufan.eu> | 2020-09-02 13:39:52 +0300 |
commit | 4e64869e248537b2bb8719c47620597595a46ea4 (patch) | |
tree | dec77058f4f41619ac53ecde0ff326ff472d0e94 /daemon.go | |
parent | 92dae330532ca47abab1b31b65a0778eeff2b53f (diff) |
Unshare mount namespace to fix `getcwd`
Previously we would call `LazyUnbind` as soon
as proces starts. This does break `getcwd`
as it starts returning `(unreachable)`
due to mountpoint being gone from `chroot`.
This removes the need for `LazyUnbind` and
instead `unshare` mount namespace, making
the new process to have it's own mounts
that are not shared with parent process.
The mounts gets cleaned-up once the process
exists.
Diffstat (limited to 'daemon.go')
-rw-r--r-- | daemon.go | 37 |
1 files changed, 22 insertions, 15 deletions
@@ -8,6 +8,7 @@ import ( "os" "os/exec" "os/signal" + "strings" "syscall" "github.com/kardianos/osext" @@ -27,9 +28,19 @@ func daemonMain() { return } + // Validate that a working directory is valid + // https://man7.org/linux/man-pages/man2/getcwd.2.html + wd, err := os.Getwd() + if err != nil { + fatal(err, "could not get current working directory") + } else if strings.HasPrefix(wd, "(unreachable)") { + fatal(os.ErrPermission, "could not get current working directory") + } + log.WithFields(log.Fields{ "uid": syscall.Getuid(), "gid": syscall.Getgid(), + "wd": wd, }).Info("starting the daemon as unprivileged user") // read the configuration from the pipe "ExtraFiles" @@ -132,10 +143,6 @@ func chrootDaemon(cmd *exec.Cmd) (*jail.Jail, error) { cmd.Path = tempExecutablePath cmd.Dir = "/" - if err := chroot.Build(); err != nil { - return nil, err - } - return chroot, nil } @@ -249,11 +256,6 @@ func jailDaemon(cmd *exec.Cmd) (*jail.Jail, error) { cmd.Path = "/gitlab-pages" cmd.Dir = pagesRootInChroot - err = cage.Build() - if err != nil { - return nil, err - } - return cage, nil } @@ -283,6 +285,17 @@ func daemonize(config appConfig, uid, gid uint, inPlace bool) error { } defer wrapper.Dispose() + // Unshare mount namespace + // 1. If this fails, in a worst case changes to mounts will propagate to other processes + // 2. Needed for fixing `os.Getwd()` which does return `(unreachable)`: + // 3. https://man7.org/linux/man-pages/man2/getcwd.2.html. + _ = wrapper.Unshare() + + if err := wrapper.Build(); err != nil { + log.WithError(err).Print("chroot build failed") + return err + } + // Create a pipe to pass the configuration configReader, configWriter, err := os.Pipe() if err != nil { @@ -299,12 +312,6 @@ func daemonize(config appConfig, uid, gid uint, inPlace bool) error { return err } - // Proactively detach any bind-mounts so they can't be left dangling - if err := wrapper.LazyUnbind(); err != nil { - log.WithError(err).Print("jail lazy umount failed") - return err - } - // Write the configuration if err := json.NewEncoder(configWriter).Encode(config); err != nil { return err |