Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v8] backport #11283 (Linux reexec) #11454

Merged
merged 1 commit into from
Mar 25, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions lib/srv/reexec_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,49 @@
package srv

import (
"fmt"
"os"
"os/exec"
"syscall"

"golang.org/x/sys/unix"
)

func init() {
// errors in open/openat are signaled by returning -1, we don't really care
// about the specifics anyway so we can just ignore the error value
//
// we're opening with O_PATH rather than O_RDONLY because the binary might
// not actually be readable (but only executable)
fd1, _ := syscall.Open("/proc/self/exe", unix.O_PATH|syscall.O_NOCTTY|syscall.O_CLOEXEC, 0)
fd2, _ := syscall.Open("/proc/self/exe", unix.O_PATH|syscall.O_NOCTTY|syscall.O_CLOEXEC, 0)

// this can happen if both calls returned -1 or if we're in running in a
// version of qemu-user that's affected by this bug:
// https://gitlab.com/qemu-project/qemu/-/issues/927
if fd1 == fd2 {
return
}

// if one has failed but not the other we can't really trust what's
// happening anymore
if fd1 == -1 || fd2 == -1 {
syscall.Close(fd1)
syscall.Close(fd2)
return
}

syscall.Close(fd2)
// we must specify the path with our pid number instead of self, because
// file descriptors are shuffled and overwritten during (*exec.Cmd).Start()
// after forking
reexecPath = fmt.Sprintf("/proc/%d/fd/%d", os.Getpid(), fd1)
}

// reexecPath specifies a path to execute on reexec, overriding Path in the cmd
// passed to reexecCommandOSTweaks, if not empty.
var reexecPath string

func reexecCommandOSTweaks(cmd *exec.Cmd) {
if cmd.SysProcAttr == nil {
cmd.SysProcAttr = new(syscall.SysProcAttr)
Expand All @@ -30,6 +69,13 @@ func reexecCommandOSTweaks(cmd *exec.Cmd) {
// cleaning up child processes, send a signal for graceful shutdown
// to children.
cmd.SysProcAttr.Pdeathsig = syscall.SIGQUIT

// replace the path on disk (which might not exist, or refer to an
// upgraded version of teleport) with reexecPath, which contains
// some path that refers to the specific binary we're running
if reexecPath != "" {
cmd.Path = reexecPath
}
}

func userCommandOSTweaks(cmd *exec.Cmd) {
Expand Down