Merge pull request #27634 from justincormack/user-cap-test
Test that non root user cannot use default capabilities
This commit is contained in:
commit
190a96131c
7 changed files with 245 additions and 1 deletions
|
@ -6,4 +6,8 @@ WORKDIR /usr/src/
|
|||
|
||||
RUN gcc -g -Wall -static userns.c -o /usr/bin/userns-test \
|
||||
&& gcc -g -Wall -static ns.c -o /usr/bin/ns-test \
|
||||
&& gcc -g -Wall -static acct.c -o /usr/bin/acct-test
|
||||
&& gcc -g -Wall -static acct.c -o /usr/bin/acct-test \
|
||||
&& gcc -g -Wall -static setuid.c -o /usr/bin/setuid-test \
|
||||
&& gcc -g -Wall -static setgid.c -o /usr/bin/setgid-test \
|
||||
&& gcc -g -Wall -static socket.c -o /usr/bin/socket-test \
|
||||
&& gcc -g -Wall -static raw.c -o /usr/bin/raw-test
|
||||
|
|
14
contrib/syscall-test/raw.c
Normal file
14
contrib/syscall-test/raw.c
Normal file
|
@ -0,0 +1,14 @@
|
|||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/udp.h>
|
||||
|
||||
int main() {
|
||||
if (socket(PF_INET, SOCK_RAW, IPPROTO_UDP) == -1) {
|
||||
perror("socket");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
11
contrib/syscall-test/setgid.c
Normal file
11
contrib/syscall-test/setgid.c
Normal file
|
@ -0,0 +1,11 @@
|
|||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
if (setgid(1) == -1) {
|
||||
perror("setgid");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
11
contrib/syscall-test/setuid.c
Normal file
11
contrib/syscall-test/setuid.c
Normal file
|
@ -0,0 +1,11 @@
|
|||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
if (setuid(1) == -1) {
|
||||
perror("setuid");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
30
contrib/syscall-test/socket.c
Normal file
30
contrib/syscall-test/socket.c
Normal file
|
@ -0,0 +1,30 @@
|
|||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
int main() {
|
||||
int s;
|
||||
struct sockaddr_in sin;
|
||||
|
||||
s = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (s == -1) {
|
||||
perror("socket");
|
||||
return 1;
|
||||
}
|
||||
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr.s_addr = INADDR_ANY;
|
||||
sin.sin_port = htons(80);
|
||||
|
||||
if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
|
||||
perror("bind");
|
||||
return 1;
|
||||
}
|
||||
|
||||
close(s);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -9,6 +9,10 @@ if [ "$DOCKER_ENGINE_GOOS" = "linux" ]; then
|
|||
gcc -g -Wall -static contrib/syscall-test/userns.c -o "${tmpdir}/userns-test"
|
||||
gcc -g -Wall -static contrib/syscall-test/ns.c -o "${tmpdir}/ns-test"
|
||||
gcc -g -Wall -static contrib/syscall-test/acct.c -o "${tmpdir}/acct-test"
|
||||
gcc -g -Wall -static contrib/syscall-test/setuid.c -o "${tmpdir}/setuid-test"
|
||||
gcc -g -Wall -static contrib/syscall-test/setgid.c -o "${tmpdir}/setgid-test"
|
||||
gcc -g -Wall -static contrib/syscall-test/socket.c -o "${tmpdir}/socket-test"
|
||||
gcc -g -Wall -static contrib/syscall-test/raw.c -o "${tmpdir}/raw-test"
|
||||
|
||||
dockerfile="${tmpdir}/Dockerfile"
|
||||
cat <<-EOF > "$dockerfile"
|
||||
|
|
|
@ -1138,6 +1138,176 @@ func (s *DockerSuite) TestRunNoNewPrivSetuid(c *check.C) {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestUserNoEffectiveCapabilitiesChown(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
// test that a root user has default capability CAP_CHOWN
|
||||
runCmd := exec.Command(dockerBinary, "run", "busybox", "chown", "100", "/tmp")
|
||||
_, _, err := runCommandWithOutput(runCmd)
|
||||
c.Assert(err, check.IsNil)
|
||||
// test that non root user does not have default capability CAP_CHOWN
|
||||
runCmd = exec.Command(dockerBinary, "run", "--user", "1000:1000", "busybox", "chown", "100", "/tmp")
|
||||
out, _, err := runCommandWithOutput(runCmd)
|
||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "Operation not permitted")
|
||||
// test that root user can drop default capability CAP_CHOWN
|
||||
runCmd = exec.Command(dockerBinary, "run", "--cap-drop", "chown", "busybox", "chown", "100", "/tmp")
|
||||
out, _, err = runCommandWithOutput(runCmd)
|
||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "Operation not permitted")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestUserNoEffectiveCapabilitiesDacOverride(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
// test that a root user has default capability CAP_DAC_OVERRIDE
|
||||
runCmd := exec.Command(dockerBinary, "run", "busybox", "sh", "-c", "echo test > /etc/passwd")
|
||||
_, _, err := runCommandWithOutput(runCmd)
|
||||
c.Assert(err, check.IsNil)
|
||||
// test that non root user does not have default capability CAP_DAC_OVERRIDE
|
||||
runCmd = exec.Command(dockerBinary, "run", "--user", "1000:1000", "busybox", "sh", "-c", "echo test > /etc/passwd")
|
||||
out, _, err := runCommandWithOutput(runCmd)
|
||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "Permission denied")
|
||||
// TODO test that root user can drop default capability CAP_DAC_OVERRIDE
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestUserNoEffectiveCapabilitiesFowner(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
// test that a root user has default capability CAP_FOWNER
|
||||
runCmd := exec.Command(dockerBinary, "run", "busybox", "chmod", "777", "/etc/passwd")
|
||||
_, _, err := runCommandWithOutput(runCmd)
|
||||
c.Assert(err, check.IsNil)
|
||||
// test that non root user does not have default capability CAP_FOWNER
|
||||
runCmd = exec.Command(dockerBinary, "run", "--user", "1000:1000", "busybox", "chmod", "777", "/etc/passwd")
|
||||
out, _, err := runCommandWithOutput(runCmd)
|
||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "Operation not permitted")
|
||||
// TODO test that root user can drop default capability CAP_FOWNER
|
||||
}
|
||||
|
||||
// TODO CAP_KILL
|
||||
|
||||
func (s *DockerSuite) TestUserNoEffectiveCapabilitiesSetuid(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
// test that a root user has default capability CAP_SETUID
|
||||
runCmd := exec.Command(dockerBinary, "run", "syscall-test", "setuid-test")
|
||||
_, _, err := runCommandWithOutput(runCmd)
|
||||
c.Assert(err, check.IsNil)
|
||||
// test that non root user does not have default capability CAP_SETUID
|
||||
runCmd = exec.Command(dockerBinary, "run", "--user", "1000:1000", "syscall-test", "setuid-test")
|
||||
out, _, err := runCommandWithOutput(runCmd)
|
||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "Operation not permitted")
|
||||
// test that root user can drop default capability CAP_SETUID
|
||||
runCmd = exec.Command(dockerBinary, "run", "--cap-drop", "setuid", "syscall-test", "setuid-test")
|
||||
out, _, err = runCommandWithOutput(runCmd)
|
||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "Operation not permitted")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestUserNoEffectiveCapabilitiesSetgid(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
// test that a root user has default capability CAP_SETGID
|
||||
runCmd := exec.Command(dockerBinary, "run", "syscall-test", "setgid-test")
|
||||
_, _, err := runCommandWithOutput(runCmd)
|
||||
c.Assert(err, check.IsNil)
|
||||
// test that non root user does not have default capability CAP_SETGID
|
||||
runCmd = exec.Command(dockerBinary, "run", "--user", "1000:1000", "syscall-test", "setgid-test")
|
||||
out, _, err := runCommandWithOutput(runCmd)
|
||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "Operation not permitted")
|
||||
// test that root user can drop default capability CAP_SETGID
|
||||
runCmd = exec.Command(dockerBinary, "run", "--cap-drop", "setgid", "syscall-test", "setgid-test")
|
||||
out, _, err = runCommandWithOutput(runCmd)
|
||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "Operation not permitted")
|
||||
}
|
||||
|
||||
// TODO CAP_SETPCAP
|
||||
|
||||
func (s *DockerSuite) TestUserNoEffectiveCapabilitiesNetBindService(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
// test that a root user has default capability CAP_NET_BIND_SERVICE
|
||||
runCmd := exec.Command(dockerBinary, "run", "syscall-test", "socket-test")
|
||||
_, _, err := runCommandWithOutput(runCmd)
|
||||
c.Assert(err, check.IsNil)
|
||||
// test that non root user does not have default capability CAP_NET_BIND_SERVICE
|
||||
runCmd = exec.Command(dockerBinary, "run", "--user", "1000:1000", "syscall-test", "socket-test")
|
||||
out, _, err := runCommandWithOutput(runCmd)
|
||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "Permission denied")
|
||||
// test that root user can drop default capability CAP_NET_BIND_SERVICE
|
||||
runCmd = exec.Command(dockerBinary, "run", "--cap-drop", "net_bind_service", "syscall-test", "socket-test")
|
||||
out, _, err = runCommandWithOutput(runCmd)
|
||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "Permission denied")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestUserNoEffectiveCapabilitiesNetRaw(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
// test that a root user has default capability CAP_NET_RAW
|
||||
runCmd := exec.Command(dockerBinary, "run", "syscall-test", "raw-test")
|
||||
_, _, err := runCommandWithOutput(runCmd)
|
||||
c.Assert(err, check.IsNil)
|
||||
// test that non root user does not have default capability CAP_NET_RAW
|
||||
runCmd = exec.Command(dockerBinary, "run", "--user", "1000:1000", "syscall-test", "raw-test")
|
||||
out, _, err := runCommandWithOutput(runCmd)
|
||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "Operation not permitted")
|
||||
// test non root can drop default capability CAP_NET_RAW
|
||||
runCmd = exec.Command(dockerBinary, "run", "--cap-drop", "net_raw", "syscall-test", "raw-test")
|
||||
out, _, err = runCommandWithOutput(runCmd)
|
||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "Operation not permitted")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestUserNoEffectiveCapabilitiesChroot(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
// test that a root user has default capability CAP_SYS_CHROOT
|
||||
runCmd := exec.Command(dockerBinary, "run", "busybox", "chroot", "/", "/bin/true")
|
||||
_, _, err := runCommandWithOutput(runCmd)
|
||||
c.Assert(err, check.IsNil)
|
||||
// test that non root user does not have default capability CAP_SYS_CHROOT
|
||||
runCmd = exec.Command(dockerBinary, "run", "--user", "1000:1000", "busybox", "chroot", "/", "/bin/true")
|
||||
out, _, err := runCommandWithOutput(runCmd)
|
||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "Operation not permitted")
|
||||
// test that root user can drop default capability CAP_SYS_CHROOT
|
||||
runCmd = exec.Command(dockerBinary, "run", "--cap-drop", "sys_chroot", "busybox", "chroot", "/", "/bin/true")
|
||||
out, _, err = runCommandWithOutput(runCmd)
|
||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "Operation not permitted")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestUserNoEffectiveCapabilitiesMknod(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
// test that a root user has default capability CAP_MKNOD
|
||||
runCmd := exec.Command(dockerBinary, "run", "busybox", "mknod", "/tmp/node", "b", "1", "2")
|
||||
_, _, err := runCommandWithOutput(runCmd)
|
||||
c.Assert(err, check.IsNil)
|
||||
// test that non root user does not have default capability CAP_MKNOD
|
||||
runCmd = exec.Command(dockerBinary, "run", "--user", "1000:1000", "busybox", "mknod", "/tmp/node", "b", "1", "2")
|
||||
out, _, err := runCommandWithOutput(runCmd)
|
||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "Operation not permitted")
|
||||
// test that root user can drop default capability CAP_MKNOD
|
||||
runCmd = exec.Command(dockerBinary, "run", "--cap-drop", "mknod", "busybox", "mknod", "/tmp/node", "b", "1", "2")
|
||||
out, _, err = runCommandWithOutput(runCmd)
|
||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "Operation not permitted")
|
||||
}
|
||||
|
||||
// TODO CAP_AUDIT_WRITE
|
||||
// TODO CAP_SETFCAP
|
||||
|
||||
func (s *DockerSuite) TestRunApparmorProcDirectory(c *check.C) {
|
||||
testRequires(c, SameHostDaemon, Apparmor)
|
||||
|
||||
|
|
Loading…
Reference in a new issue