github.com/containers/podman/v5@v5.1.0-rc1/test/e2e/run_privileged_test.go (about) 1 package integration 2 3 import ( 4 "os" 5 "strconv" 6 "strings" 7 8 . "github.com/containers/podman/v5/test/utils" 9 . "github.com/onsi/ginkgo/v2" 10 . "github.com/onsi/gomega" 11 "github.com/syndtr/gocapability/capability" 12 ) 13 14 // helper function for confirming that container capabilities are equal 15 // to those of the host, but only to the extent of caps we (podman) 16 // know about at compile time. That is: the kernel may have more caps 17 // available than we are aware of, leading to host=FFF... and ctr=3FF... 18 // because the latter is all we request. Accept that. 19 func containerCapMatchesHost(ctrCap string, hostCap string) { 20 if isRootless() { 21 return 22 } 23 ctrCapN, err := strconv.ParseUint(ctrCap, 16, 64) 24 Expect(err).NotTo(HaveOccurred(), "Error parsing %q as hex", ctrCap) 25 26 hostCapN, err := strconv.ParseUint(hostCap, 16, 64) 27 Expect(err).NotTo(HaveOccurred(), "Error parsing %q as hex", hostCap) 28 29 // host caps can never be zero (except rootless). 30 // and host caps must always be a superset (inclusive) of container 31 Expect(hostCapN).To(BeNumerically(">", 0), "host cap %q should be nonzero", hostCap) 32 Expect(hostCapN).To(BeNumerically(">=", ctrCapN), "host cap %q should never be less than container cap %q", hostCap, ctrCap) 33 hostCapMasked := hostCapN & (1<<len(capability.List()) - 1) 34 Expect(ctrCapN).To(Equal(hostCapMasked), "container cap %q is not a subset of host cap %q", ctrCap, hostCap) 35 } 36 37 var _ = Describe("Podman privileged container tests", func() { 38 39 It("podman privileged make sure sys is mounted rw", func() { 40 session := podmanTest.Podman([]string{"run", "--privileged", BB, "mount"}) 41 session.WaitWithDefaultTimeout() 42 Expect(session).Should(ExitCleanly()) 43 Expect(session.OutputToString()).To(ContainSubstring("sysfs (rw,")) 44 }) 45 46 It("podman privileged CapEff", func() { 47 hostCap := SystemExec("awk", []string{"/^CapEff/ { print $2 }", "/proc/self/status"}) 48 Expect(hostCap).Should(ExitCleanly()) 49 50 session := podmanTest.Podman([]string{"run", "--privileged", BB, "awk", "/^CapEff/ { print $2 }", "/proc/self/status"}) 51 session.WaitWithDefaultTimeout() 52 Expect(session).Should(ExitCleanly()) 53 54 containerCapMatchesHost(session.OutputToString(), hostCap.OutputToString()) 55 }) 56 57 It("podman cap-add CapEff", func() { 58 // Get caps of current process 59 hostCap := SystemExec("awk", []string{"/^CapEff/ { print $2 }", "/proc/self/status"}) 60 Expect(hostCap).Should(ExitCleanly()) 61 62 session := podmanTest.Podman([]string{"run", "--cap-add", "all", BB, "awk", "/^CapEff/ { print $2 }", "/proc/self/status"}) 63 session.WaitWithDefaultTimeout() 64 Expect(session).Should(ExitCleanly()) 65 66 containerCapMatchesHost(session.OutputToString(), hostCap.OutputToString()) 67 }) 68 69 It("podman cap-add CapEff with --user", func() { 70 // Get caps of current process 71 hostCap := SystemExec("awk", []string{"/^CapEff/ { print $2 }", "/proc/self/status"}) 72 Expect(hostCap).Should(ExitCleanly()) 73 74 session := podmanTest.Podman([]string{"run", "--user=bin", "--cap-add", "all", BB, "awk", "/^CapEff/ { print $2 }", "/proc/self/status"}) 75 session.WaitWithDefaultTimeout() 76 Expect(session).Should(ExitCleanly()) 77 78 containerCapMatchesHost(session.OutputToString(), hostCap.OutputToString()) 79 }) 80 81 It("podman cap-drop CapEff", func() { 82 session := podmanTest.Podman([]string{"run", "--cap-drop", "all", BB, "grep", "CapEff", "/proc/self/status"}) 83 session.WaitWithDefaultTimeout() 84 Expect(session).Should(ExitCleanly()) 85 capEff := strings.Split(session.OutputToString(), " ") 86 Expect("0000000000000000").To(Equal(capEff[1])) 87 }) 88 89 It("podman privileged should disable seccomp by default", func() { 90 hostSeccomp := SystemExec("grep", []string{"-Ei", "^Seccomp:\\s+0$", "/proc/self/status"}) 91 Expect(hostSeccomp).Should(ExitCleanly()) 92 93 session := podmanTest.Podman([]string{"run", "--privileged", ALPINE, "grep", "-Ei", "^Seccomp:\\s+0$", "/proc/self/status"}) 94 session.WaitWithDefaultTimeout() 95 Expect(session).Should(ExitCleanly()) 96 }) 97 98 It("podman non-privileged should have very few devices", func() { 99 session := podmanTest.Podman([]string{"run", "-t", BB, "ls", "-l", "/dev"}) 100 session.WaitWithDefaultTimeout() 101 Expect(session).Should(ExitCleanly()) 102 Expect(session.OutputToStringArray()).To(HaveLen(17)) 103 }) 104 105 It("podman privileged should inherit host devices", func() { 106 session := podmanTest.Podman([]string{"run", "--privileged", ALPINE, "ls", "-l", "/dev"}) 107 session.WaitWithDefaultTimeout() 108 Expect(session).Should(ExitCleanly()) 109 Expect(len(session.OutputToStringArray())).To(BeNumerically(">", 20)) 110 }) 111 112 It("podman privileged should restart after host devices change", func() { 113 containerName := "privileged-restart-test" 114 SkipIfRootless("Cannot create devices in /dev in rootless mode") 115 // path must be unique to this test, not used anywhere else 116 devdir := "/dev/devdirprivrestart" 117 Expect(os.MkdirAll(devdir, os.ModePerm)).To(Succeed()) 118 defer os.RemoveAll(devdir) 119 120 mknod := SystemExec("mknod", []string{devdir + "/null", "c", "1", "3"}) 121 mknod.WaitWithDefaultTimeout() 122 Expect(mknod).Should(ExitCleanly()) 123 124 session := podmanTest.Podman([]string{"run", "--name=" + containerName, "--privileged", fedoraMinimal, "ls", "/dev"}) 125 session.WaitWithDefaultTimeout() 126 Expect(session).Should(ExitCleanly()) 127 128 deviceFiles := session.OutputToStringArray() 129 130 os.RemoveAll(devdir) 131 session = podmanTest.Podman([]string{"start", "--attach", containerName}) 132 session.WaitWithDefaultTimeout() 133 Expect(session).Should(ExitCleanly()) 134 135 deviceFilesAfterRemoval := session.OutputToStringArray() 136 Expect(deviceFiles).To(Not(Equal(deviceFilesAfterRemoval))) 137 }) 138 139 It("run no-new-privileges test", func() { 140 // Check if our kernel is new enough 141 k, err := IsKernelNewerThan("4.14") 142 Expect(err).ToNot(HaveOccurred()) 143 if !k { 144 Skip("Kernel is not new enough to test this feature") 145 } 146 147 cap := SystemExec("grep", []string{"NoNewPrivs", "/proc/self/status"}) 148 if cap.ExitCode() != 0 { 149 Skip("Can't determine NoNewPrivs") 150 } 151 152 session := podmanTest.Podman([]string{"run", BB, "grep", "NoNewPrivs", "/proc/self/status"}) 153 session.WaitWithDefaultTimeout() 154 Expect(session).Should(ExitCleanly()) 155 156 privs := strings.Split(session.OutputToString(), ":") 157 session = podmanTest.Podman([]string{"run", "--security-opt", "no-new-privileges", BB, "grep", "NoNewPrivs", "/proc/self/status"}) 158 session.WaitWithDefaultTimeout() 159 Expect(session).Should(ExitCleanly()) 160 161 noprivs := strings.Split(session.OutputToString(), ":") 162 Expect(privs[1]).To(Not(Equal(noprivs[1]))) 163 }) 164 165 })