Merge pull request #2028 from giuseppe/fix-rootless-export
rootless: fix export when using fuse-overlayfs
This commit is contained in:
commit
faa7ff3568
|
@ -1,9 +1,13 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/containers/libpod/cmd/podman/libpodruntime"
|
||||
"github.com/containers/libpod/libpod"
|
||||
"github.com/containers/libpod/pkg/rootless"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
|
@ -35,6 +39,9 @@ func exportCmd(c *cli.Context) error {
|
|||
if err := validateFlags(c, exportFlags); err != nil {
|
||||
return err
|
||||
}
|
||||
if os.Geteuid() != 0 {
|
||||
rootless.SetSkipStorageSetup(true)
|
||||
}
|
||||
|
||||
runtime, err := libpodruntime.GetRuntime(c)
|
||||
if err != nil {
|
||||
|
@ -66,5 +73,37 @@ func exportCmd(c *cli.Context) error {
|
|||
return errors.Wrapf(err, "error looking up container %q", args[0])
|
||||
}
|
||||
|
||||
if os.Geteuid() != 0 {
|
||||
state, err := ctr.State()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "cannot read container state %q", ctr.ID())
|
||||
}
|
||||
if state == libpod.ContainerStateRunning || state == libpod.ContainerStatePaused {
|
||||
data, err := ioutil.ReadFile(ctr.Config().ConmonPidFile)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "cannot read conmon PID file %q", ctr.Config().ConmonPidFile)
|
||||
}
|
||||
conmonPid, err := strconv.Atoi(string(data))
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "cannot parse PID %q", data)
|
||||
}
|
||||
became, ret, err := rootless.JoinDirectUserAndMountNS(uint(conmonPid))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if became {
|
||||
os.Exit(ret)
|
||||
}
|
||||
} else {
|
||||
became, ret, err := rootless.BecomeRootInUserNS()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if became {
|
||||
os.Exit(ret)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ctr.Export(output)
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ var cmdsNotRequiringRootless = map[string]bool{
|
|||
"version": true,
|
||||
"create": true,
|
||||
"exec": true,
|
||||
"export": true,
|
||||
// `info` must be executed in an user namespace.
|
||||
// If this change, please also update libpod.refreshRootless()
|
||||
"login": true,
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containers/libpod/pkg/rootless"
|
||||
"github.com/containers/storage"
|
||||
"github.com/containers/storage/pkg/stringid"
|
||||
spec "github.com/opencontainers/runtime-spec/specs-go"
|
||||
|
@ -154,6 +155,10 @@ func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options ..
|
|||
}
|
||||
}()
|
||||
|
||||
if rootless.IsRootless() && ctr.config.ConmonPidFile == "" {
|
||||
ctr.config.ConmonPidFile = filepath.Join(ctr.state.RunDir, "conmon.pid")
|
||||
}
|
||||
|
||||
// Go through the volume mounts and check for named volumes
|
||||
// If the named volme already exists continue, otherwise create
|
||||
// the storage for the named volume.
|
||||
|
|
|
@ -99,7 +99,7 @@ get_cmd_line_args (pid_t pid)
|
|||
}
|
||||
|
||||
int
|
||||
reexec_userns_join (int userns)
|
||||
reexec_userns_join (int userns, int mountns)
|
||||
{
|
||||
pid_t ppid = getpid ();
|
||||
char uid[16];
|
||||
|
@ -131,6 +131,13 @@ reexec_userns_join (int userns)
|
|||
}
|
||||
close (userns);
|
||||
|
||||
if (mountns >= 0 && setns (mountns, 0) < 0)
|
||||
{
|
||||
fprintf (stderr, "cannot setns: %s\n", strerror (errno));
|
||||
_exit (EXIT_FAILURE);
|
||||
}
|
||||
close (userns);
|
||||
|
||||
if (syscall_setresgid (0, 0, 0) < 0)
|
||||
{
|
||||
fprintf (stderr, "cannot setresgid: %s\n", strerror (errno));
|
||||
|
|
|
@ -25,7 +25,7 @@ import (
|
|||
/*
|
||||
extern int reexec_in_user_namespace(int ready);
|
||||
extern int reexec_in_user_namespace_wait(int pid);
|
||||
extern int reexec_userns_join(int userns);
|
||||
extern int reexec_userns_join(int userns, int mountns);
|
||||
*/
|
||||
import "C"
|
||||
|
||||
|
@ -112,7 +112,40 @@ func JoinNS(pid uint) (bool, int, error) {
|
|||
}
|
||||
defer userNS.Close()
|
||||
|
||||
pidC := C.reexec_userns_join(C.int(userNS.Fd()))
|
||||
pidC := C.reexec_userns_join(C.int(userNS.Fd()), -1)
|
||||
if int(pidC) < 0 {
|
||||
return false, -1, errors.Errorf("cannot re-exec process")
|
||||
}
|
||||
|
||||
ret := C.reexec_in_user_namespace_wait(pidC)
|
||||
if ret < 0 {
|
||||
return false, -1, errors.New("error waiting for the re-exec process")
|
||||
}
|
||||
|
||||
return true, int(ret), nil
|
||||
}
|
||||
|
||||
// JoinDirectUserAndMountNS re-exec podman in a new userNS and join the user and mount
|
||||
// namespace of the specified PID without looking up its parent. Useful to join directly
|
||||
// the conmon process.
|
||||
func JoinDirectUserAndMountNS(pid uint) (bool, int, error) {
|
||||
if os.Geteuid() == 0 || os.Getenv("_LIBPOD_USERNS_CONFIGURED") != "" {
|
||||
return false, -1, nil
|
||||
}
|
||||
|
||||
userNS, err := os.Open(fmt.Sprintf("/proc/%d/ns/user", pid))
|
||||
if err != nil {
|
||||
return false, -1, err
|
||||
}
|
||||
defer userNS.Close()
|
||||
|
||||
mountNS, err := os.Open(fmt.Sprintf("/proc/%d/ns/mnt", pid))
|
||||
if err != nil {
|
||||
return false, -1, err
|
||||
}
|
||||
defer userNS.Close()
|
||||
|
||||
pidC := C.reexec_userns_join(C.int(userNS.Fd()), C.int(mountNS.Fd()))
|
||||
if int(pidC) < 0 {
|
||||
return false, -1, errors.Errorf("cannot re-exec process")
|
||||
}
|
||||
|
@ -138,7 +171,7 @@ func JoinNSPath(path string) (bool, int, error) {
|
|||
}
|
||||
defer userNS.Close()
|
||||
|
||||
pidC := C.reexec_userns_join(C.int(userNS.Fd()))
|
||||
pidC := C.reexec_userns_join(C.int(userNS.Fd()), -1)
|
||||
if int(pidC) < 0 {
|
||||
return false, -1, errors.Errorf("cannot re-exec process")
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
. "github.com/containers/libpod/test/utils"
|
||||
|
@ -245,6 +246,22 @@ var _ = Describe("Podman rootless", func() {
|
|||
cmd.WaitWithDefaultTimeout()
|
||||
Expect(cmd.ExitCode()).To(Equal(0))
|
||||
Expect(cmd.LineInOutputContains("hello")).To(BeTrue())
|
||||
|
||||
cmd = rootlessTest.PodmanAsUser([]string{"ps", "-l", "-q"}, 1000, 1000, env)
|
||||
cmd.WaitWithDefaultTimeout()
|
||||
Expect(cmd.ExitCode()).To(Equal(0))
|
||||
cid := cmd.OutputToString()
|
||||
|
||||
cmd = rootlessTest.PodmanAsUser([]string{"exec", "-l", "sh", "-c", "echo SeCreTMessage > /file"}, 1000, 1000, env)
|
||||
cmd.WaitWithDefaultTimeout()
|
||||
Expect(cmd.ExitCode()).To(Equal(0))
|
||||
|
||||
path := filepath.Join(home, "export.tar")
|
||||
cmd = rootlessTest.PodmanAsUser([]string{"export", "-o", path, cid}, 1000, 1000, env)
|
||||
cmd.WaitWithDefaultTimeout()
|
||||
content, err := ioutil.ReadFile(path)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(strings.Contains(string(content), "SeCreTMessage")).To(BeTrue())
|
||||
}
|
||||
runInRootlessContext(f)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue