mirror of
https://github.com/containers/podman.git
synced 2025-06-20 00:51:16 +08:00
Merge pull request #2426 from giuseppe/exec-preserve-fds
exec: support --preserve-fds
This commit is contained in:
@ -100,6 +100,7 @@ type ExecValues struct {
|
||||
User string
|
||||
Latest bool
|
||||
Workdir string
|
||||
PreserveFDs int
|
||||
}
|
||||
|
||||
type ImageExistsValues struct {
|
||||
|
@ -869,7 +869,7 @@ func joinOrCreateRootlessUserNamespace(createConfig *cc.CreateConfig, runtime *l
|
||||
}
|
||||
return false, -1, errors.Errorf("dependency container %s is not running", ctr.ID())
|
||||
}
|
||||
return rootless.JoinNS(uint(pid))
|
||||
return rootless.JoinNS(uint(pid), 0)
|
||||
}
|
||||
}
|
||||
return rootless.BecomeRootInUserNS()
|
||||
|
@ -4,7 +4,9 @@ import (
|
||||
"fmt"
|
||||
"github.com/containers/libpod/cmd/podman/cliconfig"
|
||||
"github.com/spf13/cobra"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/containers/libpod/cmd/podman/libpodruntime"
|
||||
"github.com/containers/libpod/libpod"
|
||||
@ -47,6 +49,7 @@ func init() {
|
||||
flags.BoolVarP(&execCommand.Tty, "tty", "t", false, "Allocate a pseudo-TTY. The default is false")
|
||||
flags.StringVarP(&execCommand.User, "user", "u", "", "Sets the username or UID used and optionally the groupname or GID for the specified command")
|
||||
|
||||
flags.IntVar(&execCommand.PreserveFDs, "preserve-fds", 0, "Pass N additional file descriptors to the container")
|
||||
flags.StringVarP(&execCommand.Workdir, "workdir", "w", "", "Working directory inside the container")
|
||||
markFlagHiddenForRemoteClient("latest", flags)
|
||||
}
|
||||
@ -82,11 +85,34 @@ func execCmd(c *cliconfig.ExecValues) error {
|
||||
return errors.Wrapf(err, "unable to exec into %s", args[0])
|
||||
}
|
||||
|
||||
if c.PreserveFDs > 0 {
|
||||
entries, err := ioutil.ReadDir("/proc/self/fd")
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to read /proc/self/fd")
|
||||
}
|
||||
m := make(map[int]bool)
|
||||
for _, e := range entries {
|
||||
i, err := strconv.Atoi(e.Name())
|
||||
if err != nil {
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "cannot parse %s in /proc/self/fd", e.Name())
|
||||
}
|
||||
}
|
||||
m[i] = true
|
||||
}
|
||||
for i := 3; i < 3+c.PreserveFDs; i++ {
|
||||
if _, found := m[i]; !found {
|
||||
return errors.New("invalid --preserve-fds=N specified. Not enough FDs available")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pid, err := ctr.PID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
became, ret, err := rootless.JoinNS(uint(pid))
|
||||
became, ret, err := rootless.JoinNS(uint(pid), c.PreserveFDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -113,5 +139,5 @@ func execCmd(c *cliconfig.ExecValues) error {
|
||||
streams.AttachError = true
|
||||
streams.AttachInput = true
|
||||
|
||||
return ctr.Exec(c.Tty, c.Privileged, envs, cmd, c.User, c.Workdir, streams)
|
||||
return ctr.Exec(c.Tty, c.Privileged, envs, cmd, c.User, c.Workdir, streams, c.PreserveFDs)
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ func topCmd(c *cliconfig.TopValues) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
became, ret, err := rootless.JoinNS(uint(pid))
|
||||
became, ret, err := rootless.JoinNS(uint(pid), 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -26,6 +26,10 @@ to run containers such as CRI-O, the last started container could be from eithe
|
||||
|
||||
The latest option is not supported on the remote client.
|
||||
|
||||
**--preserve-fds=N**
|
||||
|
||||
Pass down to the process N additional file descriptors (in addition to 0, 1, 2). The total FDs will be 3+N.
|
||||
|
||||
**--privileged**
|
||||
|
||||
Give the process extended Linux capabilities when running the command in container.
|
||||
|
@ -204,7 +204,7 @@ func (c *Container) Kill(signal uint) error {
|
||||
|
||||
// Exec starts a new process inside the container
|
||||
// TODO investigate allowing exec without attaching
|
||||
func (c *Container) Exec(tty, privileged bool, env, cmd []string, user, workDir string, streams *AttachStreams) error {
|
||||
func (c *Container) Exec(tty, privileged bool, env, cmd []string, user, workDir string, streams *AttachStreams, preserveFDs int) error {
|
||||
var capList []string
|
||||
|
||||
locked := false
|
||||
@ -266,7 +266,7 @@ func (c *Container) Exec(tty, privileged bool, env, cmd []string, user, workDir
|
||||
|
||||
logrus.Debugf("Creating new exec session in container %s with session id %s", c.ID(), sessionID)
|
||||
|
||||
execCmd, err := c.runtime.ociRuntime.execContainer(c, cmd, capList, env, tty, workDir, hostUser, sessionID, streams)
|
||||
execCmd, err := c.runtime.ociRuntime.execContainer(c, cmd, capList, env, tty, workDir, hostUser, sessionID, streams, preserveFDs)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error exec %s", c.ID())
|
||||
}
|
||||
|
@ -733,7 +733,7 @@ func (r *OCIRuntime) unpauseContainer(ctr *Container) error {
|
||||
// TODO: Add --detach support
|
||||
// TODO: Convert to use conmon
|
||||
// TODO: add --pid-file and use that to generate exec session tracking
|
||||
func (r *OCIRuntime) execContainer(c *Container, cmd, capAdd, env []string, tty bool, cwd, user, sessionID string, streams *AttachStreams) (*exec.Cmd, error) {
|
||||
func (r *OCIRuntime) execContainer(c *Container, cmd, capAdd, env []string, tty bool, cwd, user, sessionID string, streams *AttachStreams, preserveFDs int) (*exec.Cmd, error) {
|
||||
if len(cmd) == 0 {
|
||||
return nil, errors.Wrapf(ErrInvalidArg, "must provide a command to execute")
|
||||
}
|
||||
@ -770,6 +770,9 @@ func (r *OCIRuntime) execContainer(c *Container, cmd, capAdd, env []string, tty
|
||||
args = append(args, "--user", user)
|
||||
}
|
||||
|
||||
if preserveFDs > 0 {
|
||||
args = append(args, fmt.Sprintf("--preserve-fds=%d", preserveFDs))
|
||||
}
|
||||
if c.config.Spec.Process.NoNewPrivileges {
|
||||
args = append(args, "--no-new-privs")
|
||||
}
|
||||
@ -806,6 +809,14 @@ func (r *OCIRuntime) execContainer(c *Container, cmd, capAdd, env []string, tty
|
||||
return nil, errors.Wrapf(err, "cannot start container %s", c.ID())
|
||||
}
|
||||
|
||||
if preserveFDs > 0 {
|
||||
for fd := 3; fd < 3+preserveFDs; fd++ {
|
||||
// These fds were passed down to the runtime. Close them
|
||||
// and not interfere
|
||||
os.NewFile(uintptr(fd), fmt.Sprintf("fd-%d", fd)).Close()
|
||||
}
|
||||
}
|
||||
|
||||
return execCmd, nil
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,7 @@ func tryMappingTool(tool string, pid int, hostID int, mappings []idtools.IDMap)
|
||||
|
||||
// JoinNS re-exec podman in a new userNS and join the user namespace of the specified
|
||||
// PID.
|
||||
func JoinNS(pid uint) (bool, int, error) {
|
||||
func JoinNS(pid uint, preserveFDs int) (bool, int, error) {
|
||||
if os.Geteuid() == 0 || os.Getenv("_LIBPOD_USERNS_CONFIGURED") != "" {
|
||||
return false, -1, nil
|
||||
}
|
||||
@ -117,6 +117,13 @@ func JoinNS(pid uint) (bool, int, error) {
|
||||
if int(pidC) < 0 {
|
||||
return false, -1, errors.Errorf("cannot re-exec process")
|
||||
}
|
||||
if preserveFDs > 0 {
|
||||
for fd := 3; fd < 3+preserveFDs; fd++ {
|
||||
// These fds were passed down to the runtime. Close them
|
||||
// and not interfere
|
||||
os.NewFile(uintptr(fd), fmt.Sprintf("fd-%d", fd)).Close()
|
||||
}
|
||||
}
|
||||
|
||||
ret := C.reexec_in_user_namespace_wait(pidC)
|
||||
if ret < 0 {
|
||||
|
Reference in New Issue
Block a user