4c4c1b
From b41c864d569357a102ee2335a4947e59e5e2b08a Mon Sep 17 00:00:00 2001
4c4c1b
From: Matthew Heon <matthew.heon@pm.me>
4c4c1b
Date: Thu, 27 Feb 2020 16:08:29 -0500
4c4c1b
Subject: [PATCH] Ensure that exec sessions inherit supplemental groups
4c4c1b
4c4c1b
This corrects a regression from Podman 1.4.x where container exec
4c4c1b
sessions inherited supplemental groups from the container, iff
4c4c1b
the exec session did not specify a user.
4c4c1b
4c4c1b
Signed-off-by: Matthew Heon <matthew.heon@pm.me>
4c4c1b
---
4c4c1b
 libpod/container_api.go            |  5 -----
4c4c1b
 libpod/container_internal_linux.go |  5 ++++-
4c4c1b
 libpod/oci_conmon_linux.go         | 25 +++++++++++++++++++++----
4c4c1b
 test/e2e/exec_test.go              | 24 ++++++++++++++++++++++++
4c4c1b
 4 files changed, 49 insertions(+), 10 deletions(-)
4c4c1b
4c4c1b
diff --git a/libpod/container_api.go b/libpod/container_api.go
4c4c1b
index d612341bce..dabbe27dcd 100644
4c4c1b
--- a/libpod/container_api.go
4c4c1b
+++ b/libpod/container_api.go
4c4c1b
@@ -270,11 +270,6 @@ func (c *Container) Exec(tty, privileged bool, env map[string]string, cmd []stri
4c4c1b
 		}
4c4c1b
 	}()
4c4c1b
 
4c4c1b
-	// if the user is empty, we should inherit the user that the container is currently running with
4c4c1b
-	if user == "" {
4c4c1b
-		user = c.config.User
4c4c1b
-	}
4c4c1b
-
4c4c1b
 	opts := new(ExecOptions)
4c4c1b
 	opts.Cmd = cmd
4c4c1b
 	opts.CapAdd = capList
4c4c1b
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
4c4c1b
index 7390262647..63968918cb 100644
4c4c1b
--- a/libpod/container_internal_linux.go
4c4c1b
+++ b/libpod/container_internal_linux.go
4c4c1b
@@ -330,7 +330,10 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
4c4c1b
 
4c4c1b
 	// Add addition groups if c.config.GroupAdd is not empty
4c4c1b
 	if len(c.config.Groups) > 0 {
4c4c1b
-		gids, _ := lookup.GetContainerGroups(c.config.Groups, c.state.Mountpoint, nil)
4c4c1b
+		gids, err := lookup.GetContainerGroups(c.config.Groups, c.state.Mountpoint, overrides)
4c4c1b
+		if err != nil {
4c4c1b
+			return nil, errors.Wrapf(err, "error looking up supplemental groups for container %s", c.ID())
4c4c1b
+		}
4c4c1b
 		for _, gid := range gids {
4c4c1b
 			g.AddProcessAdditionalGid(gid)
4c4c1b
 		}
4c4c1b
diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go
4c4c1b
index 07d38693f0..800f896036 100644
4c4c1b
--- a/libpod/oci_conmon_linux.go
4c4c1b
+++ b/libpod/oci_conmon_linux.go
4c4c1b
@@ -1252,18 +1252,35 @@ func prepareProcessExec(c *Container, cmd, env []string, tty bool, cwd, user, se
4c4c1b
 
4c4c1b
 	}
4c4c1b
 
4c4c1b
+	var addGroups []string
4c4c1b
+	var sgids []uint32
4c4c1b
+
4c4c1b
+	// if the user is empty, we should inherit the user that the container is currently running with
4c4c1b
+	if user == "" {
4c4c1b
+		user = c.config.User
4c4c1b
+		addGroups = c.config.Groups
4c4c1b
+	}
4c4c1b
+
4c4c1b
 	overrides := c.getUserOverrides()
4c4c1b
 	execUser, err := lookup.GetUserGroupInfo(c.state.Mountpoint, user, overrides)
4c4c1b
 	if err != nil {
4c4c1b
 		return nil, err
4c4c1b
 	}
4c4c1b
 
4c4c1b
+	if len(addGroups) > 0 {
4c4c1b
+		sgids, err = lookup.GetContainerGroups(addGroups, c.state.Mountpoint, overrides)
4c4c1b
+		if err != nil {
4c4c1b
+			return nil, errors.Wrapf(err, "error looking up supplemental groups for container %s exec session %s", c.ID(), sessionID)
4c4c1b
+		}
4c4c1b
+	}
4c4c1b
+
4c4c1b
 	// If user was set, look it up in the container to get a UID to use on
4c4c1b
 	// the host
4c4c1b
-	if user != "" {
4c4c1b
-		sgids := make([]uint32, 0, len(execUser.Sgids))
4c4c1b
-		for _, sgid := range execUser.Sgids {
4c4c1b
-			sgids = append(sgids, uint32(sgid))
4c4c1b
+	if user != "" || len(sgids) > 0 {
4c4c1b
+		if user != "" {
4c4c1b
+			for _, sgid := range execUser.Sgids {
4c4c1b
+				sgids = append(sgids, uint32(sgid))
4c4c1b
+			}
4c4c1b
 		}
4c4c1b
 		processUser := spec.User{
4c4c1b
 			UID:            uint32(execUser.Uid),
4c4c1b
diff --git a/test/e2e/exec_test.go b/test/e2e/exec_test.go
4c4c1b
index ed4eb3335f..ab806f6831 100644
4c4c1b
--- a/test/e2e/exec_test.go
4c4c1b
+++ b/test/e2e/exec_test.go
4c4c1b
@@ -1,6 +1,7 @@
4c4c1b
 package integration
4c4c1b
 
4c4c1b
 import (
4c4c1b
+	"fmt"
4c4c1b
 	"os"
4c4c1b
 	"strings"
4c4c1b
 
4c4c1b
@@ -244,4 +245,27 @@ var _ = Describe("Podman exec", func() {
4c4c1b
 		Expect(session.ExitCode()).To(Equal(0))
4c4c1b
 	})
4c4c1b
 
4c4c1b
+	It("podman exec preserves --group-add groups", func() {
4c4c1b
+		groupName := "group1"
4c4c1b
+		gid := "4444"
4c4c1b
+		ctrName1 := "ctr1"
4c4c1b
+		ctr1 := podmanTest.Podman([]string{"run", "-ti", "--name", ctrName1, fedoraMinimal, "groupadd", "-g", gid, groupName})
4c4c1b
+		ctr1.WaitWithDefaultTimeout()
4c4c1b
+		Expect(ctr1.ExitCode()).To(Equal(0))
4c4c1b
+
4c4c1b
+		imgName := "img1"
4c4c1b
+		commit := podmanTest.Podman([]string{"commit", ctrName1, imgName})
4c4c1b
+		commit.WaitWithDefaultTimeout()
4c4c1b
+		Expect(commit.ExitCode()).To(Equal(0))
4c4c1b
+
4c4c1b
+		ctrName2 := "ctr2"
4c4c1b
+		ctr2 := podmanTest.Podman([]string{"run", "-d", "--name", ctrName2, "--group-add", groupName, imgName, "sleep", "300"})
4c4c1b
+		ctr2.WaitWithDefaultTimeout()
4c4c1b
+		Expect(ctr2.ExitCode()).To(Equal(0))
4c4c1b
+
4c4c1b
+		exec := podmanTest.Podman([]string{"exec", "-ti", ctrName2, "id"})
4c4c1b
+		exec.WaitWithDefaultTimeout()
4c4c1b
+		Expect(exec.ExitCode()).To(Equal(0))
4c4c1b
+		Expect(strings.Contains(exec.OutputToString(), fmt.Sprintf("%s(%s)", gid, groupName))).To(BeTrue())
4c4c1b
+	})
4c4c1b
 })