Skip to content

Commit

Permalink
Merge pull request containers#8823 from giuseppe/exec-honor-privileged
Browse files Browse the repository at this point in the history
exec: honor --privileged
  • Loading branch information
openshift-merge-robot authored Jan 4, 2021
2 parents 142b4ac + b3bd37b commit 23f25b8
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 24 deletions.
2 changes: 1 addition & 1 deletion libpod/oci_conmon_exec_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ func (r *ConmonOCIRuntime) startExec(c *Container, sessionID string, options *Ex
finalEnv = append(finalEnv, fmt.Sprintf("%s=%s", k, v))
}

processFile, err := prepareProcessExec(c, options.Cmd, finalEnv, options.Terminal, options.Cwd, options.User, sessionID)
processFile, err := prepareProcessExec(c, options, finalEnv, sessionID)
if err != nil {
return nil, nil, err
}
Expand Down
18 changes: 13 additions & 5 deletions libpod/oci_conmon_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -1185,33 +1185,41 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co

// prepareProcessExec returns the path of the process.json used in runc exec -p
// caller is responsible to close the returned *os.File if needed.
func prepareProcessExec(c *Container, cmd, env []string, tty bool, cwd, user, sessionID string) (*os.File, error) {
func prepareProcessExec(c *Container, options *ExecOptions, env []string, sessionID string) (*os.File, error) {
f, err := ioutil.TempFile(c.execBundlePath(sessionID), "exec-process-")
if err != nil {
return nil, err
}
pspec := c.config.Spec.Process
pspec.SelinuxLabel = c.config.ProcessLabel
pspec.Args = cmd
pspec.Args = options.Cmd
for _, cap := range options.CapAdd {
pspec.Capabilities.Bounding = append(pspec.Capabilities.Bounding, cap)
pspec.Capabilities.Effective = append(pspec.Capabilities.Effective, cap)
pspec.Capabilities.Inheritable = append(pspec.Capabilities.Inheritable, cap)
pspec.Capabilities.Permitted = append(pspec.Capabilities.Permitted, cap)
pspec.Capabilities.Ambient = append(pspec.Capabilities.Ambient, cap)
}
// We need to default this to false else it will inherit terminal as true
// from the container.
pspec.Terminal = false
if tty {
if options.Terminal {
pspec.Terminal = true
}
if len(env) > 0 {
pspec.Env = append(pspec.Env, env...)
}

if cwd != "" {
pspec.Cwd = cwd
if options.Cwd != "" {
pspec.Cwd = options.Cwd

}

var addGroups []string
var sgids []uint32

// if the user is empty, we should inherit the user that the container is currently running with
user := options.User
if user == "" {
user = c.config.User
addGroups = c.config.Groups
Expand Down
15 changes: 15 additions & 0 deletions test/e2e/exec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,21 @@ var _ = Describe("Podman exec", func() {
Expect(session.ExitCode()).To(Equal(100))
})

It("podman exec --privileged", func() {
hostCap := SystemExec("awk", []string{"/^CapEff/ { print $2 }", "/proc/self/status"})
Expect(hostCap.ExitCode()).To(Equal(0))

setup := podmanTest.RunTopContainer("test-privileged")
setup.WaitWithDefaultTimeout()
Expect(setup.ExitCode()).To(Equal(0))

session := podmanTest.Podman([]string{"exec", "--privileged", "test-privileged", "sh", "-c", "grep ^CapEff /proc/self/status | cut -f 2"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))

containerCapMatchesHost(session.OutputToString(), hostCap.OutputToString())
})

It("podman exec terminal doesn't hang", func() {
setup := podmanTest.Podman([]string{"run", "-dti", "--name", "test1", fedoraMinimal, "sleep", "+Inf"})
setup.WaitWithDefaultTimeout()
Expand Down
36 changes: 18 additions & 18 deletions test/e2e/run_privileged_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,22 @@ import (
// know about at compile time. That is: the kernel may have more caps
// available than we are aware of, leading to host=FFF... and ctr=3FF...
// because the latter is all we request. Accept that.
func containerCapMatchesHost(ctr_cap string, host_cap string) {
func containerCapMatchesHost(ctrCap string, hostCap string) {
if isRootless() {
return
}
ctr_cap_n, err := strconv.ParseUint(ctr_cap, 16, 64)
Expect(err).NotTo(HaveOccurred(), "Error parsing %q as hex", ctr_cap)
ctrCap_n, err := strconv.ParseUint(ctrCap, 16, 64)
Expect(err).NotTo(HaveOccurred(), "Error parsing %q as hex", ctrCap)

host_cap_n, err := strconv.ParseUint(host_cap, 16, 64)
Expect(err).NotTo(HaveOccurred(), "Error parsing %q as hex", host_cap)
hostCap_n, err := strconv.ParseUint(hostCap, 16, 64)
Expect(err).NotTo(HaveOccurred(), "Error parsing %q as hex", hostCap)

// host caps can never be zero (except rootless).
// and host caps must always be a superset (inclusive) of container
Expect(host_cap_n).To(BeNumerically(">", 0), "host cap %q should be nonzero", host_cap)
Expect(host_cap_n).To(BeNumerically(">=", ctr_cap_n), "host cap %q should never be less than container cap %q", host_cap, ctr_cap)
host_cap_masked := host_cap_n & (1<<len(capability.List()) - 1)
Expect(ctr_cap_n).To(Equal(host_cap_masked), "container cap %q is not a subset of host cap %q", ctr_cap, host_cap)
Expect(hostCap_n).To(BeNumerically(">", 0), "host cap %q should be nonzero", hostCap)
Expect(hostCap_n).To(BeNumerically(">=", ctrCap_n), "host cap %q should never be less than container cap %q", hostCap, ctrCap)
hostCap_masked := hostCap_n & (1<<len(capability.List()) - 1)
Expect(ctrCap_n).To(Equal(hostCap_masked), "container cap %q is not a subset of host cap %q", ctrCap, hostCap)
}

var _ = Describe("Podman privileged container tests", func() {
Expand Down Expand Up @@ -68,38 +68,38 @@ var _ = Describe("Podman privileged container tests", func() {
})

It("podman privileged CapEff", func() {
host_cap := SystemExec("awk", []string{"/^CapEff/ { print $2 }", "/proc/self/status"})
Expect(host_cap.ExitCode()).To(Equal(0))
hostCap := SystemExec("awk", []string{"/^CapEff/ { print $2 }", "/proc/self/status"})
Expect(hostCap.ExitCode()).To(Equal(0))

session := podmanTest.Podman([]string{"run", "--privileged", "busybox", "awk", "/^CapEff/ { print $2 }", "/proc/self/status"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))

containerCapMatchesHost(session.OutputToString(), host_cap.OutputToString())
containerCapMatchesHost(session.OutputToString(), hostCap.OutputToString())
})

It("podman cap-add CapEff", func() {
// Get caps of current process
host_cap := SystemExec("awk", []string{"/^CapEff/ { print $2 }", "/proc/self/status"})
Expect(host_cap.ExitCode()).To(Equal(0))
hostCap := SystemExec("awk", []string{"/^CapEff/ { print $2 }", "/proc/self/status"})
Expect(hostCap.ExitCode()).To(Equal(0))

session := podmanTest.Podman([]string{"run", "--cap-add", "all", "busybox", "awk", "/^CapEff/ { print $2 }", "/proc/self/status"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))

containerCapMatchesHost(session.OutputToString(), host_cap.OutputToString())
containerCapMatchesHost(session.OutputToString(), hostCap.OutputToString())
})

It("podman cap-add CapEff with --user", func() {
// Get caps of current process
host_cap := SystemExec("awk", []string{"/^CapEff/ { print $2 }", "/proc/self/status"})
Expect(host_cap.ExitCode()).To(Equal(0))
hostCap := SystemExec("awk", []string{"/^CapEff/ { print $2 }", "/proc/self/status"})
Expect(hostCap.ExitCode()).To(Equal(0))

session := podmanTest.Podman([]string{"run", "--user=bin", "--cap-add", "all", "busybox", "awk", "/^CapEff/ { print $2 }", "/proc/self/status"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))

containerCapMatchesHost(session.OutputToString(), host_cap.OutputToString())
containerCapMatchesHost(session.OutputToString(), hostCap.OutputToString())
})

It("podman cap-drop CapEff", func() {
Expand Down

0 comments on commit 23f25b8

Please sign in to comment.