diff options
author | Kamil Trzcinski <ayufan@ayufan.eu> | 2016-02-16 17:25:59 +0300 |
---|---|---|
committer | Kamil Trzcinski <ayufan@ayufan.eu> | 2016-02-16 17:25:59 +0300 |
commit | 7f12dcc6036f3935688e3fc4be61e8b1596cbc1d (patch) | |
tree | 7778d66b3adea6d781042f98d581b25f16879719 /daemon.go | |
parent | ecfc0c55d22cc8d76c88dce750996256856827a8 (diff) |
Execute in chroot
Diffstat (limited to 'daemon.go')
-rw-r--r-- | daemon.go | 87 |
1 files changed, 87 insertions, 0 deletions
@@ -1,16 +1,20 @@ package main import ( + "crypto/rand" "encoding/json" + "fmt" "log" "os" "os/exec" "os/signal" "os/user" + "path/filepath" "strconv" "syscall" "github.com/kardianos/osext" + "io" ) const daemonRunProgram = "gitlab-pages-unprivileged" @@ -105,6 +109,79 @@ func passSignals(cmd *exec.Cmd) { }() } +func copyFile(dest, src string, perm os.FileMode) (err error) { + srcFile, err := os.Open(src) + if err != nil { + return + } + defer srcFile.Close() + + destFile, err := os.OpenFile(dest, os.O_RDWR|os.O_CREATE|os.O_EXCL, perm) + if err != nil { + return + } + defer destFile.Close() + + _, err = io.Copy(destFile, srcFile) + return +} + +func daemonCreateExecutable(name string, perm os.FileMode) (file *os.File, err error) { + // We assume that crypto random generates true random, non-colliding hash + b := make([]byte, 16) + _, err = rand.Read(b) + if err != nil { + return + } + + path := fmt.Sprintf("%s.%x", name, b) + file, err = os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_EXCL, perm) + if err != nil { + return + } + return +} + +func daemonChroot(cmd *exec.Cmd) (path string, err error) { + wd, err := os.Getwd() + if err != nil { + return + } + + // Generate temporary file + temporaryExecutable, err := daemonCreateExecutable(".daemon", 0755) + if err != nil { + return + } + defer temporaryExecutable.Close() + defer func() { + // Remove the temporary file in case of failure + if err != nil { + os.Remove(temporaryExecutable.Name()) + } + }() + + // Open current executable + executableFile, err := os.Open(cmd.Path) + if err != nil { + return + } + defer executableFile.Close() + + // Copy the executable content + _, err = io.Copy(temporaryExecutable, executableFile) + if err != nil { + return + } + + // Update command to use chroot + cmd.SysProcAttr.Chroot = wd + cmd.Path = "/" + temporaryExecutable.Name() + cmd.Dir = "/" + path = filepath.Join(wd, temporaryExecutable.Name()) + return +} + func daemonize(config appConfig, cmdUser string) { var err error defer func() { @@ -120,6 +197,13 @@ func daemonize(config appConfig, cmdUser string) { } defer killProcess(cmd) + // Run daemon in chroot environment + temporaryExecutable, err := daemonChroot(cmd) + if err != nil { + return + } + defer os.Remove(temporaryExecutable) + // Create a pipe to pass the configuration configReader, configWriter, err := os.Pipe() if err != nil { @@ -144,6 +228,9 @@ func daemonize(config appConfig, cmdUser string) { } configWriter.Close() + // Remove executable + os.Remove(temporaryExecutable) + // Pass through signals passSignals(cmd) |