diff --git a/CVE-2021-20188-pre1.patch b/CVE-2021-20188-pre1.patch new file mode 100644 index 0000000000000000000000000000000000000000..ed59904f8fa4fc4e456e8ea9b1338b4ba83aa219 --- /dev/null +++ b/CVE-2021-20188-pre1.patch @@ -0,0 +1,181 @@ +From 867669374c3fdd39f2629e53cbe7430f1bc3e085 Mon Sep 17 00:00:00 2001 +From: Debarshi Ray +Date: Tue, 8 Jan 2019 12:53:50 +0100 +Subject: [PATCH] Add a --workdir option to 'podman exec' + +Signed-off-by: Debarshi Ray +--- + cmd/podman/common.go | 9 +++++---- + cmd/podman/exec.go | 3 ++- + completions/bash/podman | 2 ++ + docs/podman-exec.1.md | 8 ++++++++ + libpod/container_api.go | 4 ++-- + libpod/oci.go | 6 ++++-- + test/e2e/exec_test.go | 32 ++++++++++++++++++++++++++++++++ + 7 files changed, 55 insertions(+), 9 deletions(-) + +diff --git a/cmd/podman/common.go b/cmd/podman/common.go +index 0fc9a6accfd..d934c869946 100644 +--- a/cmd/podman/common.go ++++ b/cmd/podman/common.go +@@ -28,6 +28,10 @@ var ( + Name: "latest, l", + Usage: "act on the latest pod podman is aware of", + } ++ WorkDirFlag = cli.StringFlag{ ++ Name: "workdir, w", ++ Usage: "Working directory inside the container", ++ } + ) + + const ( +@@ -522,10 +526,7 @@ var createFlags = []cli.Flag{ + Name: "volumes-from", + Usage: "Mount volumes from the specified container(s) (default [])", + }, +- cli.StringFlag{ +- Name: "workdir, w", +- Usage: "Working `directory inside the container", +- }, ++ WorkDirFlag, + } + + func getFormat(c *cli.Context) (string, error) { +diff --git a/cmd/podman/exec.go b/cmd/podman/exec.go +index c03834dea23..073e72e6404 100644 +--- a/cmd/podman/exec.go ++++ b/cmd/podman/exec.go +@@ -34,6 +34,7 @@ var ( + Usage: "Sets the username or UID used and optionally the groupname or GID for the specified command", + }, + LatestFlag, ++ WorkDirFlag, + } + execDescription = ` + podman exec +@@ -108,5 +109,5 @@ func execCmd(c *cli.Context) error { + envs = append(envs, fmt.Sprintf("%s=%s", k, v)) + } + +- return ctr.Exec(c.Bool("tty"), c.Bool("privileged"), envs, cmd, c.String("user")) ++ return ctr.Exec(c.Bool("tty"), c.Bool("privileged"), envs, cmd, c.String("user"), c.String("workdir")) + } +diff --git a/completions/bash/podman b/completions/bash/podman +index d65f54690e3..e23615d5256 100644 +--- a/completions/bash/podman ++++ b/completions/bash/podman +@@ -1111,6 +1111,8 @@ _podman_exec() { + --env + --user + -u ++ --workdir ++ -w + " + local boolean_options=" + --latest +diff --git a/docs/podman-exec.1.md b/docs/podman-exec.1.md +index 284fa5a4a29..77317b0cabd 100644 +--- a/docs/podman-exec.1.md ++++ b/docs/podman-exec.1.md +@@ -38,6 +38,14 @@ Sets the username or UID used and optionally the groupname or GID for the specif + The following examples are all valid: + --user [user | user:group | uid | uid:gid | user:gid | uid:group ] + ++**--workdir**, **-w**="" ++ ++Working directory inside the container ++ ++The default working directory for running binaries within a container is the root directory (/). ++The image developer can set a different default with the WORKDIR instruction, which can be overridden ++when creating the container. ++ + ## SEE ALSO + podman(1), podman-run(1) + +diff --git a/libpod/container_api.go b/libpod/container_api.go +index 09bc46905ae..4eaf737b09a 100644 +--- a/libpod/container_api.go ++++ b/libpod/container_api.go +@@ -262,7 +262,7 @@ func (c *Container) Kill(signal uint) error { + // Exec starts a new process inside the container + // TODO allow specifying streams to attach to + // TODO investigate allowing exec without attaching +-func (c *Container) Exec(tty, privileged bool, env, cmd []string, user string) error { ++func (c *Container) Exec(tty, privileged bool, env, cmd []string, user, workDir string) error { + var capList []string + + locked := false +@@ -324,7 +324,7 @@ func (c *Container) Exec(tty, privileged bool, env, cmd []string, user string) e + + 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, hostUser, sessionID) ++ execCmd, err := c.runtime.ociRuntime.execContainer(c, cmd, capList, env, tty, workDir, hostUser, sessionID) + if err != nil { + return errors.Wrapf(err, "error exec %s", c.ID()) + } +diff --git a/libpod/oci.go b/libpod/oci.go +index 093bfdd3573..31c1a7e8514 100644 +--- a/libpod/oci.go ++++ b/libpod/oci.go +@@ -728,7 +728,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, user, sessionID string) (*exec.Cmd, error) { ++func (r *OCIRuntime) execContainer(c *Container, cmd, capAdd, env []string, tty bool, cwd, user, sessionID string) (*exec.Cmd, error) { + if len(cmd) == 0 { + return nil, errors.Wrapf(ErrInvalidArg, "must provide a command to execute") + } +@@ -749,7 +749,9 @@ func (r *OCIRuntime) execContainer(c *Container, cmd, capAdd, env []string, tty + + args = append(args, "exec") + +- args = append(args, "--cwd", c.config.Spec.Process.Cwd) ++ if cwd != "" { ++ args = append(args, "--cwd", cwd) ++ } + + args = append(args, "--pid-file", c.execPidPath(sessionID)) + +diff --git a/test/e2e/exec_test.go b/test/e2e/exec_test.go +index fec80717fa2..a181501a5ff 100644 +--- a/test/e2e/exec_test.go ++++ b/test/e2e/exec_test.go +@@ -127,4 +127,36 @@ var _ = Describe("Podman exec", func() { + Expect(session2.ExitCode()).To(Equal(0)) + Expect(session2.OutputToString()).To(Equal(testUser)) + }) ++ ++ It("podman exec simple working directory test", func() { ++ setup := podmanTest.RunTopContainer("test1") ++ setup.WaitWithDefaultTimeout() ++ Expect(setup.ExitCode()).To(Equal(0)) ++ ++ session := podmanTest.Podman([]string{"exec", "-l", "--workdir", "/tmp", "pwd"}) ++ session.WaitWithDefaultTimeout() ++ Expect(session.ExitCode()).To(Equal(0)) ++ match, _ := session.GrepString("/tmp") ++ Expect(match).Should(BeTrue()) ++ ++ session = podmanTest.Podman([]string{"exec", "-l", "-w", "/tmp", "pwd"}) ++ session.WaitWithDefaultTimeout() ++ Expect(session.ExitCode()).To(Equal(0)) ++ match, _ = session.GrepString("/tmp") ++ Expect(match).Should(BeTrue()) ++ }) ++ ++ It("podman exec missing working directory test", func() { ++ setup := podmanTest.RunTopContainer("test1") ++ setup.WaitWithDefaultTimeout() ++ Expect(setup.ExitCode()).To(Equal(0)) ++ ++ session := podmanTest.Podman([]string{"exec", "-l", "--workdir", "/missing", "pwd"}) ++ session.WaitWithDefaultTimeout() ++ Expect(session.ExitCode()).To(Equal(1)) ++ ++ session = podmanTest.Podman([]string{"exec", "-l", "-w", "/missing", "pwd"}) ++ session.WaitWithDefaultTimeout() ++ Expect(session.ExitCode()).To(Equal(1)) ++ }) + }) diff --git a/CVE-2021-20188-pre2.patch b/CVE-2021-20188-pre2.patch new file mode 100644 index 0000000000000000000000000000000000000000..492e7d264d5c318f7ac062f1f1b7dee0ce96bbf5 --- /dev/null +++ b/CVE-2021-20188-pre2.patch @@ -0,0 +1,181 @@ +From 1dd7f13dfbc1dd377eabace0239b1c05cd60b144 Mon Sep 17 00:00:00 2001 +From: baude +Date: Thu, 25 Oct 2018 13:39:25 -0500 +Subject: [PATCH] get user and group information using securejoin and runc's + user library + +for the purposes of performance and security, we use securejoin to contstruct +the root fs's path so that symlinks are what they appear to be and no pointing +to something naughty. + +then instead of chrooting to parse /etc/passwd|/etc/group, we now use the runc user/group +methods which saves us quite a bit of performance. + +Signed-off-by: baude +--- + pkg/lookup/lookup.go | 156 +++++++++++++++++++++++++++++ + 1 files changed, 156 insertions(+) + create mode 100644 pkg/lookup/lookup.go + +diff --git a/pkg/lookup/lookup.go b/pkg/lookup/lookup.go +new file mode 100644 +index 00000000000..b27e2a724bc +--- /dev/null ++++ b/pkg/lookup/lookup.go +@@ -0,0 +1,156 @@ ++package lookup ++ ++import ( ++ "github.com/cyphar/filepath-securejoin" ++ "github.com/opencontainers/runc/libcontainer/user" ++ "github.com/sirupsen/logrus" ++ "strconv" ++) ++ ++const ( ++ etcpasswd = "/etc/passwd" ++ etcgroup = "/etc/group" ++) ++ ++// Overrides allows you to override defaults in GetUserGroupInfo ++type Overrides struct { ++ DefaultUser *user.ExecUser ++ ContainerEtcPasswdPath string ++ ContainerEtcGroupPath string ++} ++ ++// GetUserGroupInfo takes string forms of the the container's mount path and the container user and ++// returns a ExecUser with uid, gid, sgids, and home. And override can be provided for defaults. ++func GetUserGroupInfo(containerMount, containerUser string, override *Overrides) (*user.ExecUser, error) { ++ var ( ++ passwdDest, groupDest string ++ defaultExecUser *user.ExecUser ++ err error ++ ) ++ passwdPath := etcpasswd ++ groupPath := etcgroup ++ ++ if override != nil { ++ // Check for an override /etc/passwd path ++ if override.ContainerEtcPasswdPath != "" { ++ passwdPath = override.ContainerEtcPasswdPath ++ } ++ // Check for an override for /etc/group path ++ if override.ContainerEtcGroupPath != "" { ++ groupPath = override.ContainerEtcGroupPath ++ } ++ } ++ ++ // Check for an override default user ++ if override != nil && override.DefaultUser != nil { ++ defaultExecUser = override.DefaultUser ++ } else { ++ // Define a default container user ++ //defaultExecUser = &user.ExecUser{ ++ // Uid: 0, ++ // Gid: 0, ++ // Home: "/", ++ defaultExecUser = nil ++ ++ } ++ ++ // Make sure the /etc/group and /etc/passwd destinations are not a symlink to something naughty ++ if passwdDest, err = securejoin.SecureJoin(containerMount, passwdPath); err != nil { ++ logrus.Debug(err) ++ return nil, err ++ } ++ if groupDest, err = securejoin.SecureJoin(containerMount, groupPath); err != nil { ++ logrus.Debug(err) ++ return nil, err ++ } ++ return user.GetExecUserPath(containerUser, defaultExecUser, passwdDest, groupDest) ++} ++ ++// GetContainerGroups uses securejoin to get a list of numerical groupids from a container. Per the runc ++// function it calls: If a group name cannot be found, an error will be returned. If a group id cannot be found, ++// or the given group data is nil, the id will be returned as-is provided it is in the legal range. ++func GetContainerGroups(groups []string, containerMount string, override *Overrides) ([]uint32, error) { ++ var ( ++ groupDest string ++ err error ++ uintgids []uint32 ++ ) ++ ++ groupPath := etcgroup ++ if override != nil && override.ContainerEtcGroupPath != "" { ++ groupPath = override.ContainerEtcGroupPath ++ } ++ ++ if groupDest, err = securejoin.SecureJoin(containerMount, groupPath); err != nil { ++ logrus.Debug(err) ++ return nil, err ++ } ++ ++ gids, err := user.GetAdditionalGroupsPath(groups, groupDest) ++ if err != nil { ++ return nil, err ++ } ++ // For libpod, we want []uint32s ++ for _, gid := range gids { ++ uintgids = append(uintgids, uint32(gid)) ++ } ++ return uintgids, nil ++} ++ ++// GetUser takes a containermount path and user name or id and returns ++// a matching User structure from /etc/passwd. If it cannot locate a user ++// with the provided information, an ErrNoPasswdEntries is returned. ++func GetUser(containerMount, userIDorName string) (*user.User, error) { ++ var inputIsName bool ++ uid, err := strconv.Atoi(userIDorName) ++ if err != nil { ++ inputIsName = true ++ } ++ passwdDest, err := securejoin.SecureJoin(containerMount, etcpasswd) ++ if err != nil { ++ return nil, err ++ } ++ users, err := user.ParsePasswdFileFilter(passwdDest, func(u user.User) bool { ++ if inputIsName { ++ return u.Name == userIDorName ++ } ++ return u.Uid == uid ++ }) ++ if err != nil { ++ return nil, err ++ } ++ if len(users) > 0 { ++ return &users[0], nil ++ } ++ return nil, user.ErrNoPasswdEntries ++} ++ ++// GetGroup takes ac ontainermount path and a group name or id and returns ++// a match Group struct from /etc/group. if it cannot locate a group, ++// an ErrNoGroupEntries error is returned. ++func GetGroup(containerMount, groupIDorName string) (*user.Group, error) { ++ var inputIsName bool ++ gid, err := strconv.Atoi(groupIDorName) ++ if err != nil { ++ inputIsName = true ++ } ++ ++ groupDest, err := securejoin.SecureJoin(containerMount, etcgroup) ++ if err != nil { ++ return nil, err ++ } ++ ++ groups, err := user.ParseGroupFileFilter(groupDest, func(g user.Group) bool { ++ if inputIsName { ++ return g.Name == groupIDorName ++ } ++ return g.Gid == gid ++ }) ++ if err != nil { ++ return nil, err ++ } ++ if len(groups) > 0 { ++ return &groups[0], nil ++ } ++ return nil, user.ErrNoGroupEntries ++} diff --git a/CVE-2021-20188.patch b/CVE-2021-20188.patch new file mode 100644 index 0000000000000000000000000000000000000000..f7a780a01c8a0bac76dbea5ba4244173829306d5 --- /dev/null +++ b/CVE-2021-20188.patch @@ -0,0 +1,321 @@ +From 69daa67c436a8fdeb0149aa5cb0112f03fdb699f Mon Sep 17 00:00:00 2001 +From: Matthew Heon +Date: Mon, 25 Jan 2021 14:18:07 -0500 +Subject: [PATCH] Correct handling of capabilities + +Ensure that capabilities are properly handled for non-root users +in privileged containers. We do not want to give full caps, but +instead only CapInh and CapEff (others should be all-zeroes). + +Fixing `podman run` is easy - the same code as the Podman 1.6 fix +works there. The `podman exec` command is far more challenging. +Exec received a complete rewrite to use Conmon at some point +before Podman 1.6, and gained many capabilities in the process. +One of those was the ability to actually tweak the capabilities +of the exec process - 1.0 did not have that. Since it was needed +to resolve this CVE, I was forced to backport a large bit of the +1.0 -> 1.6 exec changes (passing a Process block to the OCI +runtime, and using `prepareProcessExec()` to prepare said block). +I am honestly uncomfortable with the size and scope of this +change but I don't see another way around this. + +Fixes CVE-2021-20188 + +Signed-off-by: Matthew Heon +--- + libpod/container_api.go | 24 +------ + libpod/oci.go | 148 ++++++++++++++++++++++++++++++++-------- + pkg/spec/spec.go | 8 +++ + 3 files changed, 132 insertions(+), 48 deletions(-) + +diff --git a/libpod/container_api.go b/libpod/container_api.go +index fe66abf7a8f..b10596f6228 100644 +--- a/libpod/container_api.go ++++ b/libpod/container_api.go +@@ -2,7 +2,6 @@ package libpod + + import ( + "context" +- "fmt" + "io/ioutil" + "os" + "strconv" +@@ -10,10 +9,8 @@ import ( + "time" + + "github.com/containers/libpod/libpod/driver" +- "github.com/containers/libpod/pkg/chrootuser" + "github.com/containers/libpod/pkg/inspect" + "github.com/containers/storage/pkg/stringid" +- "github.com/docker/docker/daemon/caps" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "k8s.io/apimachinery/pkg/util/wait" +@@ -260,8 +258,6 @@ func (c *Container) Kill(signal uint) er + // TODO allow specifying streams to attach to + // TODO investigate allowing exec without attaching + func (c *Container) Exec(tty, privileged bool, env, cmd []string, user, workDir string) error { +- var capList []string +- + locked := false + if !c.batched { + locked = true +@@ -284,22 +280,8 @@ func (c *Container) Exec(tty, privileged + if conState != ContainerStateRunning { + return errors.Errorf("cannot exec into container that is not running") + } +- if privileged || c.config.Privileged { +- capList = caps.GetAllCapabilities() +- } +- +- // If user was set, look it up in the container to get a UID to use on +- // the host +- hostUser := "" +- if user != "" { +- uid, gid, err := chrootuser.GetUser(c.state.Mountpoint, user) +- if err != nil { +- return errors.Wrapf(err, "error getting user to launch exec session as") +- } + +- // runc expects user formatted as uid:gid +- hostUser = fmt.Sprintf("%d:%d", uid, gid) +- } ++ isPrivileged := privileged || c.config.Privileged + + // Generate exec session ID + // Ensure we don't conflict with an existing session ID +@@ -321,10 +303,11 @@ func (c *Container) Exec(tty, privileged + + 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) ++ execCmd, processFile, err := c.runtime.ociRuntime.execContainer(c, cmd, env, tty, workDir, user, sessionID, isPrivileged) + if err != nil { + return errors.Wrapf(err, "error exec %s", c.ID()) + } ++ defer os.Remove(processFile) + + pidFile := c.execPidPath(sessionID) + // 1 second seems a reasonable time to wait +diff --git a/libpod/oci.go b/libpod/oci.go +index a1894b52fbe..79217dced5d 100644 +--- a/libpod/oci.go ++++ b/libpod/oci.go +@@ -15,10 +15,12 @@ import ( + "syscall" + "time" + ++ "github.com/containers/libpod/pkg/lookup" + "github.com/containers/libpod/pkg/ctime" + "github.com/containers/libpod/pkg/rootless" + "github.com/coreos/go-systemd/activation" + "github.com/cri-o/ocicni/pkg/ocicni" ++ "github.com/docker/docker/daemon/caps" + spec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/opencontainers/selinux/go-selinux" + "github.com/opencontainers/selinux/go-selinux/label" +@@ -689,18 +691,23 @@ func (r *OCIRuntime) unpauseContainer(ct + // 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) (*exec.Cmd, error) { ++func (r *OCIRuntime) execContainer(c *Container, cmd, env []string, tty bool, cwd, user, sessionID string, privileged bool) (*exec.Cmd, string, error) { + if len(cmd) == 0 { +- return nil, errors.Wrapf(ErrInvalidArg, "must provide a command to execute") ++ return nil, "", errors.Wrapf(ErrInvalidArg, "must provide a command to execute") + } + + if sessionID == "" { +- return nil, errors.Wrapf(ErrEmptyID, "must provide a session ID for exec") ++ return nil, "", errors.Wrapf(ErrEmptyID, "must provide a session ID for exec") + } + + runtimeDir, err := GetRootlessRuntimeDir() + if err != nil { +- return nil, err ++ return nil, "", err ++ } ++ ++ processFile, err := prepareProcessExec(c, cmd, env, tty, cwd, user, sessionID, privileged) ++ if err != nil { ++ return nil, "", err + } + + args := []string{} +@@ -710,32 +717,14 @@ func (r *OCIRuntime) execContainer(c *Co + + args = append(args, "exec") + +- if cwd != "" { +- args = append(args, "--cwd", cwd) +- } ++ args = append(args, "--process", processFile) + + args = append(args, "--pid-file", c.execPidPath(sessionID)) + +- if tty { +- args = append(args, "--tty") +- } +- +- if user != "" { +- args = append(args, "--user", user) +- } +- + if c.config.Spec.Process.NoNewPrivileges { + args = append(args, "--no-new-privs") + } + +- for _, cap := range capAdd { +- args = append(args, "--cap", cap) +- } +- +- for _, envVar := range env { +- args = append(args, "--env", envVar) +- } +- + // Append container ID and command + args = append(args, c.ID()) + args = append(args, cmd...) +@@ -749,10 +738,10 @@ func (r *OCIRuntime) execContainer(c *Co + execCmd.Env = append(execCmd.Env, fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir)) + + if err := execCmd.Start(); err != nil { +- return nil, errors.Wrapf(err, "cannot start container %s", c.ID()) ++ return nil, "", errors.Wrapf(err, "cannot start container %s", c.ID()) + } + +- return execCmd, nil ++ return execCmd, processFile, nil + } + + // execStopContainer stops all active exec sessions in a container +@@ -831,3 +820,110 @@ func (r *OCIRuntime) checkpointContainer + return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, nil, r.path, "checkpoint", + "--image-path", imagePath, "--work-path", workPath, ctr.ID()) + } ++ ++// prepareProcessExec returns the path of the process.json used in runc exec -p. ++// Returns path to the created exec process file. This will need to be removed ++// by the caller when they're done, best effort. ++func prepareProcessExec(c *Container, cmd, env []string, tty bool, cwd, user, sessionID string, privileged bool) (string, error) { ++ filename := filepath.Join(c.bundlePath(), fmt.Sprintf("exec-process-%s", sessionID)) ++ f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY, 0600) ++ if err != nil { ++ return "", err ++ } ++ defer f.Close() ++ ++ pspec := c.config.Spec.Process ++ pspec.SelinuxLabel = c.config.ProcessLabel ++ pspec.Args = cmd ++ // We need to default this to false else it will inherit terminal as true ++ // from the container. ++ pspec.Terminal = false ++ if tty { ++ pspec.Terminal = true ++ } ++ if len(env) > 0 { ++ pspec.Env = append(pspec.Env, env...) ++ } ++ ++ if cwd != "" { ++ pspec.Cwd = cwd ++ ++ } ++ ++ var addGroups []string ++ var sgids []uint32 ++ ++ // if the user is empty, we should inherit the user that the container is currently running with ++ if user == "" { ++ user = c.config.User ++ addGroups = c.config.Groups ++ } ++ ++ execUser, err := lookup.GetUserGroupInfo(c.state.Mountpoint, user, nil) ++ if err != nil { ++ return "", err ++ } ++ ++ if len(addGroups) > 0 { ++ sgids, err = lookup.GetContainerGroups(addGroups, c.state.Mountpoint, nil) ++ if err != nil { ++ return "", errors.Wrapf(err, "error looking up supplemental groups for container %s exec session %s", c.ID(), sessionID) ++ } ++ } ++ ++ // If user was set, look it up in the container to get a UID to use on ++ // the host ++ if user != "" || len(sgids) > 0 { ++ if user != "" { ++ for _, sgid := range execUser.Sgids { ++ sgids = append(sgids, uint32(sgid)) ++ } ++ } ++ processUser := spec.User{ ++ UID: uint32(execUser.Uid), ++ GID: uint32(execUser.Gid), ++ AdditionalGids: sgids, ++ } ++ ++ pspec.User = processUser ++ } ++ ++ allCaps := caps.GetAllCapabilities() ++ pspec.Capabilities.Effective = []string{} ++ if privileged { ++ pspec.Capabilities.Bounding = allCaps ++ } else { ++ pspec.Capabilities.Bounding = []string{} ++ } ++ pspec.Capabilities.Inheritable = pspec.Capabilities.Bounding ++ if execUser.Uid == 0 { ++ pspec.Capabilities.Effective = pspec.Capabilities.Bounding ++ pspec.Capabilities.Permitted = pspec.Capabilities.Bounding ++ pspec.Capabilities.Ambient = pspec.Capabilities.Bounding ++ } else { ++ pspec.Capabilities.Permitted = pspec.Capabilities.Effective ++ pspec.Capabilities.Ambient = pspec.Capabilities.Effective ++ } ++ ++ hasHomeSet := false ++ for _, s := range pspec.Env { ++ if strings.HasPrefix(s, "HOME=") { ++ hasHomeSet = true ++ break ++ } ++ } ++ if !hasHomeSet { ++ pspec.Env = append(pspec.Env, fmt.Sprintf("HOME=%s", execUser.Home)) ++ } ++ ++ processJSON, err := json.Marshal(pspec) ++ if err != nil { ++ return "", err ++ } ++ ++ if err := ioutil.WriteFile(filename, processJSON, 0644); err != nil { ++ return "", err ++ } ++ ++ return filename, nil ++} +diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go +index 46105af4aef..d4f13711859 100644 +--- a/pkg/spec/spec.go ++++ b/pkg/spec/spec.go +@@ -325,6 +325,14 @@ func CreateConfigToOCISpec(config *CreateConfig) (*spec.Spec, error) { //nolint + } + } else { + g.SetupPrivileged(true) ++ if config.User != "" { ++ user := strings.SplitN(config.User, ":", 2)[0] ++ if user != "root" && user != "0" { ++ g.Spec().Process.Capabilities.Effective = []string{} ++ g.Spec().Process.Capabilities.Permitted = []string{} ++ g.Spec().Process.Capabilities.Ambient = []string{} ++ } ++ } + } + + // HANDLE SECCOMP diff --git a/builtin-remove-some-unused-functions.patch b/builtin-remove-some-unused-functions.patch new file mode 100644 index 0000000000000000000000000000000000000000..422a1370b0abf6c1a2a5b7e25b2a293e8183f7b5 --- /dev/null +++ b/builtin-remove-some-unused-functions.patch @@ -0,0 +1,56 @@ +From 7af23efc78cbcbf462ae58e30fc4b94e99f09436 Mon Sep 17 00:00:00 2001 +From: Giuseppe Scrivano +Date: Mon, 12 Nov 2018 18:07:21 +0100 +Subject: [PATCH] builtin.go.h: remove some unused functions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +it helps to solve a warning with cgo: + +In file included from /usr/include/glib-2.0/glib/glist.h:32, + from /usr/include/glib-2.0/glib/ghash.h:33, + from /usr/include/glib-2.0/glib.h:50, + from vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/commit.go:16: +vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/builtin.go.h: In function ‘_g_clear_object’: +/usr/include/glib-2.0/glib/gmem.h:121:18: warning: passing argument 1 of ‘g_object_unref’ discards ‘volatile’ qualifier from pointer target type [-Wdiscarded-qualifiers] + (destroy) (_ptr); \ + ^~~~ +/usr/include/glib-2.0/gobject/gobject.h:6 + +Closes: https://github.com/ostreedev/ostree-go/issues/23 + +Signed-off-by: Giuseppe Scrivano +--- + vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/builtin.go.h | 12 ------------ + 1 file changed, 12 deletions(-) + +diff --git a/pkg/otbuiltin/builtin.go.h b/pkg/otbuiltin/builtin.go.h +index 734de98..7617155 100644 +--- a/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/builtin.go.h ++++ b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/builtin.go.h +@@ -33,24 +33,12 @@ _ostree_repo_file(GFile *file) + return OSTREE_REPO_FILE (file); + } + +-static guint +-_gpointer_to_uint (gpointer ptr) +-{ +- return GPOINTER_TO_UINT (ptr); +-} +- + static gpointer + _guint_to_pointer (guint u) + { + return GUINT_TO_POINTER (u); + } + +-static void +-_g_clear_object (volatile GObject **object_ptr) +-{ +- g_clear_object(object_ptr); +-} +- + static const GVariantType* + _g_variant_type (char *type) + { diff --git a/podman.spec b/podman.spec index e5cb6d87a5db00f0de021072686177502c15406a..0f911bfb6fc2d70f57e542be2d8054d619f1d94f 100644 --- a/podman.spec +++ b/podman.spec @@ -1,12 +1,13 @@ Name: podman Version: 0.10.1 -Release: 7 +Release: 8 Summary: A daemonless container engine for managing Containers Epoch: 1 License: ASL 2.0 URL: https://podman.io/ Source0: https://github.com/containers/libpod/archive/e4a155328fb88590fafd3d4e845f9bca49133f62/libpod-e4a1553.tar.gz Source1: https://github.com/cpuguy83/go-md2man/archive/v1.0.10.tar.gz +Source2: https://github.com/cyphar/filepath-securejoin/archive/v0.2.1.tar.gz BuildRequires: golang btrfs-progs-devel glib2-devel glibc-devel glibc-static BuildRequires: git gpgme-devel libassuan-devel libgpg-error-devel libseccomp-devel BuildRequires: libselinux-devel ostree-devel pkgconfig make @@ -110,6 +111,10 @@ Provides: bundled(golang(k8s.io/kube-openapi)) = 275e2ce91dec4c05a4094a7b1daee55 Provides: bundled(golang(k8s.io/utils)) = 258e2a2fa64568210fbd6267cf1d8fd87c3cb86e Patch1: 0001-podman-patch-for-local-search.patch +Patch2: builtin-remove-some-unused-functions.patch +Patch3: CVE-2021-20188-pre1.patch +Patch4: CVE-2021-20188-pre2.patch +Patch5: CVE-2021-20188.patch %description Podman manages the entire container ecosystem which includes pods, @@ -157,8 +162,12 @@ sed -i 's/0.0.0/%{version}/' contrib/python/%{name}/setup.py sed -i 's/0.0.0/%{version}/' contrib/python/py%{name}/setup.py mv pkg/hooks/README.md pkg/hooks/README-hooks.md tar -xf %SOURCE1 +tar -xf %SOURCE2 +rm -rf filepath-securejoin-0.2.1/vendor %build +mkdir -p vendor/github.com/cyphar/filepath-securejoin +cp filepath-securejoin-0.2.1/* vendor/github.com/cyphar/filepath-securejoin mkdir -p _build/bin _output/bin cd go-md2man-* go build -mod=vendor -o ../_build/bin/go-md2man . @@ -218,6 +227,10 @@ install -Dp -m644 libpod.conf %{buildroot}%{_datadir}/containers/libpod.conf %{_mandir}/man5/*.5* %changelog +* Wed Mar 3 2021 wangxiao - 1:0.10.1-8 +- Add missing bundled(golang(github.com/cyphar/filepath-securejoin) +- Fix CVE-2021-20188 + * Thu Feb 18 2021 lingsheng - 1:0.10.1-7 - Resolve go-md2man dependency diff --git a/v0.2.1.tar.gz b/v0.2.1.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..b5d847ed64022ce6c20a7cecbc18585eeacde38f Binary files /dev/null and b/v0.2.1.tar.gz differ