From dfc689efc9a5746b0c31147562c5051c45874002 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 23 Oct 2018 22:06:14 +0200 Subject: create: fix writing cidfile when using rootless prevent opening the same file twice, since we re-exec podman in rootless mode. While at it, also solve a possible race between the check for the file and writing to it. Another process could have created the file in the meanwhile and we would just end up overwriting it. Signed-off-by: Giuseppe Scrivano --- cmd/podman/create.go | 29 ++++++++++++++++++----------- cmd/podman/pod_create.go | 18 +++++++++++------- libpod/util.go | 15 ++++----------- 3 files changed, 33 insertions(+), 29 deletions(-) diff --git a/cmd/podman/create.go b/cmd/podman/create.go index 248ff1b7d..9f6825c95 100644 --- a/cmd/podman/create.go +++ b/cmd/podman/create.go @@ -95,15 +95,6 @@ func createInit(c *cli.Context) error { return err } - if c.String("cidfile") != "" { - if _, err := os.Stat(c.String("cidfile")); err == nil { - return errors.Errorf("container id file exists. ensure another container is not using it or delete %s", c.String("cidfile")) - } - if err := libpod.WriteFile("", c.String("cidfile")); err != nil { - return errors.Wrapf(err, "unable to write cidfile %s", c.String("cidfile")) - } - } - if len(c.Args()) < 1 { return errors.Errorf("image name or ID is required") } @@ -119,6 +110,20 @@ func createContainer(c *cli.Context, runtime *libpod.Runtime) (*libpod.Container rootfs = c.Args()[0] } + var err error + var cidFile *os.File + if c.IsSet("cidfile") && os.Geteuid() == 0 { + cidFile, err = libpod.OpenExclusiveFile(c.String("cidfile")) + if err != nil && os.IsExist(err) { + return nil, nil, errors.Errorf("container id file exists. Ensure another container is not using it or delete %s", c.String("cidfile")) + } + if err != nil { + return nil, nil, errors.Errorf("error opening cidfile %s", c.String("cidfile")) + } + defer cidFile.Close() + defer cidFile.Sync() + } + imageName := "" var data *inspect.ImageData = nil @@ -171,12 +176,14 @@ func createContainer(c *cli.Context, runtime *libpod.Runtime) (*libpod.Container return nil, nil, err } - if c.String("cidfile") != "" { - err := libpod.WriteFile(ctr.ID(), c.String("cidfile")) + if cidFile != nil { + _, err = cidFile.WriteString(ctr.ID()) if err != nil { logrus.Error(err) } + } + logrus.Debugf("New container created %q", ctr.ID()) return ctr, createConfig, nil } diff --git a/cmd/podman/pod_create.go b/cmd/podman/pod_create.go index c3a45a093..63fa6b294 100644 --- a/cmd/podman/pod_create.go +++ b/cmd/podman/pod_create.go @@ -90,13 +90,17 @@ func podCreateCmd(c *cli.Context) error { } defer runtime.Shutdown(false) - if c.IsSet("pod-id-file") { - if _, err = os.Stat(c.String("pod-id-file")); err == nil { - return errors.Errorf("pod id file exists. ensure another pod is not using it or delete %s", c.String("pod-id-file")) + var podIdFile *os.File + if c.IsSet("pod-id-file") && os.Geteuid() == 0 { + podIdFile, err = libpod.OpenExclusiveFile(c.String("pod-id-file")) + if err != nil && os.IsExist(err) { + return errors.Errorf("pod id file exists. Ensure another pod is not using it or delete %s", c.String("pod-id-file")) } - if err = libpod.WriteFile("", c.String("pod-id-file")); err != nil { - return errors.Wrapf(err, "unable to write pod id file %s", c.String("pod-id-file")) + if err != nil { + return errors.Errorf("error opening pod-id-file %s", c.String("pod-id-file")) } + defer podIdFile.Close() + defer podIdFile.Sync() } if !c.BoolT("infra") && c.IsSet("share") && c.String("share") != "none" && c.String("share") != "" { return errors.Errorf("You cannot share kernel namespaces on the pod level without an infra container") @@ -137,8 +141,8 @@ func podCreateCmd(c *cli.Context) error { return err } - if c.IsSet("pod-id-file") { - err = libpod.WriteFile(pod.ID(), c.String("pod-id-file")) + if podIdFile != nil { + _, err = podIdFile.WriteString(pod.ID()) if err != nil { logrus.Error(err) } diff --git a/libpod/util.go b/libpod/util.go index 3b51e4fcc..7007b29cd 100644 --- a/libpod/util.go +++ b/libpod/util.go @@ -24,22 +24,15 @@ const ( DefaultTransport = "docker://" ) -// WriteFile writes a provided string to a provided path -func WriteFile(content string, path string) error { +// OpenExclusiveFile opens a file for writing and ensure it doesn't already exist +func OpenExclusiveFile(path string) (*os.File, error) { baseDir := filepath.Dir(path) if baseDir != "" { if _, err := os.Stat(baseDir); err != nil { - return err + return nil, err } } - f, err := os.Create(path) - if err != nil { - return err - } - defer f.Close() - f.WriteString(content) - f.Sync() - return nil + return os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666) } // FuncTimer helps measure the execution time of a function -- cgit v1.2.3-54-g00ecf