Skip to content

Commit

Permalink
Add reexec branch for socket activation to correct LISTEN_PID
Browse files Browse the repository at this point in the history
Signed-off-by: Andrei Lopukhov <andrewlopukhov@gmail.com>
  • Loading branch information
alopukhov committed Jul 5, 2024
1 parent 71f54df commit 64ff345
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 39 deletions.
49 changes: 37 additions & 12 deletions cmd/rootlesskit/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"

"github.com/rootless-containers/rootlesskit/v2/pkg/activation"
"github.com/rootless-containers/rootlesskit/v2/pkg/child"
"github.com/rootless-containers/rootlesskit/v2/pkg/common"
"github.com/rootless-containers/rootlesskit/v2/pkg/copyup/tmpfssymlink"
Expand All @@ -29,17 +30,24 @@ import (
"github.com/rootless-containers/rootlesskit/v2/pkg/version"
)


const (
pipeFDEnvKey = "_ROOTLESSKIT_PIPEFD_UNDOCUMENTED"
childUseActivationEnvKey = "_ROOTLESSKIT_CHILD_USE_ACTIVATION_UNDOCUMENTED"
runActivationEnvKey = "_ROOTLESSKIT_RUN_ACTIVATION_UNDOCUMENTED"
stateDirEnvKey = "ROOTLESSKIT_STATE_DIR" // documented
parentEUIDEnvKey = "ROOTLESSKIT_PARENT_EUID" // documented
parentEGIDEnvKey = "ROOTLESSKIT_PARENT_EGID" // documented
)

func main() {
const (
pipeFDEnvKey = "_ROOTLESSKIT_PIPEFD_UNDOCUMENTED"
stateDirEnvKey = "ROOTLESSKIT_STATE_DIR" // documented
parentEUIDEnvKey = "ROOTLESSKIT_PARENT_EUID" // documented
parentEGIDEnvKey = "ROOTLESSKIT_PARENT_EGID" // documented
)
iAmActivationHelper := os.Getenv(runActivationEnvKey) == "true"
iAmChild := os.Getenv(pipeFDEnvKey) != ""
id := "parent"
if iAmChild {
id = "child " // padded to len("parent")
} else if iAmActivationHelper {
id = "activ."
}
debug := false
app := cli.NewApp()
Expand Down Expand Up @@ -252,15 +260,21 @@ OPTIONS:
if clicontext.NArg() < 1 {
return errors.New("no command specified")
}
if iAmActivationHelper {
activationOpt, err := createActivationOpts(clicontext)
if err != nil {
return err
}
return activation.ActivationHelper(activationOpt)
}
if iAmChild {
childOpt, err := createChildOpt(clicontext, pipeFDEnvKey, stateDirEnvKey, clicontext.Args().Slice())
childOpt, err := createChildOpt(clicontext)
if err != nil {
return err
}
return child.Child(childOpt)
}
parentOpt, err := createParentOpt(clicontext, pipeFDEnvKey, stateDirEnvKey,
parentEUIDEnvKey, parentEGIDEnvKey)
parentOpt, err := createParentOpt(clicontext)
if err != nil {
return err
}
Expand Down Expand Up @@ -305,11 +319,12 @@ func parseCIDR(s string) (*net.IPNet, error) {
return ipnet, nil
}

func createParentOpt(clicontext *cli.Context, pipeFDEnvKey, stateDirEnvKey, parentEUIDEnvKey, parentEGIDEnvKey string) (parent.Opt, error) {
func createParentOpt(clicontext *cli.Context) (parent.Opt, error) {
var err error
opt := parent.Opt{
PipeFDEnvKey: pipeFDEnvKey,
StateDirEnvKey: stateDirEnvKey,
ChildUseActivationEnvKey: childUseActivationEnvKey,
CreatePIDNS: clicontext.Bool("pidns"),
CreateCgroupNS: clicontext.Bool("cgroupns"),
CreateUTSNS: clicontext.Bool("utsns"),
Expand Down Expand Up @@ -575,13 +590,15 @@ func (w *logrusDebugWriter) Write(p []byte) (int, error) {
return len(p), nil
}

func createChildOpt(clicontext *cli.Context, pipeFDEnvKey, stateDirEnvKey string, targetCmd []string) (child.Opt, error) {
func createChildOpt(clicontext *cli.Context) (child.Opt, error) {
pidns := clicontext.Bool("pidns")
detachNetNS := clicontext.Bool("detach-netns")
opt := child.Opt{
PipeFDEnvKey: pipeFDEnvKey,
RunActivationEnvKey: runActivationEnvKey,
ChildUseActivationEnvKey: childUseActivationEnvKey,
StateDirEnvKey: stateDirEnvKey,
TargetCmd: targetCmd,
TargetCmd: clicontext.Args().Slice(),
MountProcfs: pidns,
DetachNetNS: detachNetNS,
Propagation: clicontext.String("propagation"),
Expand Down Expand Up @@ -664,3 +681,11 @@ func unameM() string {
}
return machine
}

func createActivationOpts(clicontext *cli.Context) (activation.Opt, error) {
opt := activation.Opt {
RunActivationEnvKey: runActivationEnvKey,
TargetCmd: clicontext.Args().Slice(),
}
return opt, nil
}
36 changes: 36 additions & 0 deletions pkg/activation/activation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package activation

import (
"os"
"os/exec"
"strings"
"syscall"
"strconv"
)

type Opt struct {
RunActivationEnvKey string // needs to be set
TargetCmd []string // needs to be set
}

func ActivationHelper(opt Opt) error {
pid := os.Getpid()
os.Unsetenv(opt.RunActivationEnvKey)
os.Setenv("LISTEN_PID", strconv.Itoa(pid))
argsv := opt.TargetCmd
execPath, err := selectExecutable(argsv[0])
if err != nil {
return err
}
if err = syscall.Exec(execPath, argsv, os.Environ()); err != nil {
return err
}
panic("should not reach here")
}

func selectExecutable(path string) (string, error) {
if strings.Contains(path, "/") {
return path, nil
}
return exec.LookPath(path)
}
28 changes: 20 additions & 8 deletions pkg/child/child.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,26 @@ func setupFiles(cmd *exec.Cmd) {
}


func createCmd(targetCmd []string) (*exec.Cmd, error) {
var args []string
if len(targetCmd) > 1 {
args = targetCmd[1:]
}
cmd := exec.Command(targetCmd[0], args...)
func createCmd(opt Opt) (*exec.Cmd, error) {
fixListenPidEnv := os.Getenv(opt.ChildUseActivationEnvKey) == "true"
os.Unsetenv(opt.ChildUseActivationEnvKey)
targetCmd := opt.TargetCmd
var cmd *exec.Cmd
cmdEnv := os.Environ()
if fixListenPidEnv {
cmd = exec.Command("/proc/self/exe", os.Args[1:]...)
cmdEnv = append(cmdEnv, opt.RunActivationEnvKey + "=true")
} else {
var args []string
if len(targetCmd) > 1 {
args = targetCmd[1:]
}
cmd = exec.Command(targetCmd[0], args...)
}
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Env = os.Environ()
cmd.Env = cmdEnv
cmd.SysProcAttr = &syscall.SysProcAttr{
Pdeathsig: syscall.SIGKILL,
}
Expand Down Expand Up @@ -252,6 +262,8 @@ func setupNet(stateDir string, msg *messages.ParentInitNetworkDriverCompleted, e

type Opt struct {
PipeFDEnvKey string // needs to be set
RunActivationEnvKey string // needs to be set
ChildUseActivationEnvKey string // needs to be set
StateDirEnvKey string // needs to be set
TargetCmd []string // needs to be set
NetworkDriver network.ChildDriver // nil for HostNetwork
Expand Down Expand Up @@ -458,7 +470,7 @@ func Child(opt Opt) error {
}()
}

cmd, err := createCmd(opt.TargetCmd)
cmd, err := createCmd(opt)
if err != nil {
return err
}
Expand Down
41 changes: 22 additions & 19 deletions pkg/parent/parent.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (

type Opt struct {
PipeFDEnvKey string // needs to be set
ChildUseActivationEnvKey string // needs to be set
StateDir string // directory needs to be precreated
StateDirEnvKey string // optional env key to propagate StateDir value
NetworkDriver network.ParentDriver // nil for HostNetwork
Expand Down Expand Up @@ -125,25 +126,27 @@ func LockStateDir(stateDir string) (*flock.Flock, error) {
return lock, nil
}

func setupFilesAndEnv(cmd *exec.Cmd, readPipe *os.File, writePipe *os.File, envKey string) {
func setupFilesAndEnv(readPipe *os.File, writePipe *os.File, opt Opt) ([]*os.File, []string) {
// 0 1 and 2 are used for stdin. stdout, and stderr
const firstExtraFD = 3
systemdActivationFDs := 0
// check for systemd socket activation sockets
if v := os.Getenv("LISTEN_FDS"); v != "" {
if num, err := strconv.Atoi(v); err == nil {
systemdActivationFDs = num
}
}
cmd.ExtraFiles = make([]*os.File, systemdActivationFDs + 2)
for fd := 0; fd < systemdActivationFDs; fd++ {
cmd.ExtraFiles[fd] = os.NewFile(uintptr(firstExtraFD + fd), "")
}
readIndex := systemdActivationFDs
writeIndex := readIndex + 1
cmd.ExtraFiles[readIndex] = readPipe
cmd.ExtraFiles[writeIndex] = writePipe
cmd.Env = append(os.Environ(), envKey+"="+strconv.Itoa(firstExtraFD+readIndex)+","+strconv.Itoa(firstExtraFD+writeIndex))
const listenFdsStart = 3
listenPid, listenPidErr := strconv.Atoi(os.Getenv("LISTEN_PID"))
listenFds, listenFdsErr := strconv.Atoi(os.Getenv("LISTEN_FDS"))
useSystemdSocketFDs := listenPidErr == nil && listenFdsErr == nil && listenFds > 0
if !useSystemdSocketFDs {
listenFds = 0
}
extraFiles := make([]*os.File, listenFds + 2)
for i, fd := 0, listenFdsStart; i < listenFds; i, fd = i + 1, fd + 1 {
// is it required?: syscall.CloseOnExec(fd)
name := "LISTEN_FD_" + strconv.Itoa(fd)
extraFiles[i] = os.NewFile(uintptr(fd), name)
}
extraFiles[listenFds] = readPipe
extraFiles[listenFds + 1] = writePipe
cmdEnv := os.Environ()
cmdEnv = append(cmdEnv, opt.PipeFDEnvKey + "=" + strconv.Itoa(listenFdsStart + listenFds) + "," + strconv.Itoa(listenFdsStart + listenFds + 1))
cmdEnv = append(cmdEnv, opt.ChildUseActivationEnvKey + "=" + strconv.FormatBool(listenPid == os.Getpid()))
return extraFiles, cmdEnv
}

func Parent(opt Opt) error {
Expand Down Expand Up @@ -199,7 +202,7 @@ func Parent(opt Opt) error {
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
setupFilesAndEnv(cmd, pipeR, pipe2W, opt.PipeFDEnvKey)
cmd.ExtraFiles, cmd.Env = setupFilesAndEnv(pipeR, pipe2W, opt)
if opt.StateDirEnvKey != "" {
cmd.Env = append(cmd.Env, opt.StateDirEnvKey+"="+opt.StateDir)
}
Expand Down

0 comments on commit 64ff345

Please sign in to comment.