[lxc-devel] [lxd/master] seccomp: improvements

brauner on Github lxc-bot at linuxcontainers.org
Wed Jul 17 09:10:21 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 364 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20190717/f3b4e2ae/attachment.bin>
-------------- next part --------------
From c3859c27f4fc711662da1eb05341d6e4d6076fc4 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Wed, 17 Jul 2019 10:42:20 +0200
Subject: [PATCH 1/2] forksyscall: add and use setnsat()

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/main_forksyscall.go | 58 +++++++++++++----------------------------
 1 file changed, 18 insertions(+), 40 deletions(-)

diff --git a/lxd/main_forksyscall.go b/lxd/main_forksyscall.go
index 18cf6bc7c6..2f2c8c0712 100644
--- a/lxd/main_forksyscall.go
+++ b/lxd/main_forksyscall.go
@@ -250,56 +250,34 @@ static void forkmknod()
 	}
 }
 
-static bool change_creds(int ns_fd, cap_t caps, uid_t nsuid, gid_t nsgid)
-{
-	__do_close_prot_errno int fd = -EBADF;
-
-	if (prctl(PR_SET_KEEPCAPS, 1))
-		return false;
-
-	fd = openat(ns_fd, "user", O_RDONLY | O_CLOEXEC);
-	if (setns(fd, CLONE_NEWUSER))
-		return false;
-	close(fd);
-
-	fd = openat(ns_fd, "mnt", O_RDONLY | O_CLOEXEC);
-	if (setns(fd, CLONE_NEWNS))
-		return false;
-	close(fd);
-
 #ifndef CLONE_NEWCGROUP
 #define CLONE_NEWCGROUP	0x02000000
 #endif
 
-	fd = openat(ns_fd, "cgroup", O_RDONLY | O_CLOEXEC);
-	if (fd < 0) {
-		if (errno != ENOENT)
-			return false;
-	} else {
-		if (setns(fd, CLONE_NEWCGROUP) && errno != EINVAL)
-			return false;
-		close(fd);
-	}
+const char *ns_names[] = { "user", "mnt", "pid", "uts", "ipc", "net", "cgroup", NULL };
 
-	fd = openat(ns_fd, "ipc", O_RDONLY | O_CLOEXEC);
-	if (setns(fd, CLONE_NEWIPC))
-		return false;
-	close(fd);
+static bool setnsat(int ns_fd, const char *ns)
+{
+	__do_close_prot_errno int fd = -EBADF;
 
-	fd = openat(ns_fd, "net", O_RDONLY | O_CLOEXEC);
-	if (setns(fd, CLONE_NEWNET))
+	fd = openat(ns_fd, ns, O_RDONLY | O_CLOEXEC);
+	if (fd < 0)
 		return false;
-	close(fd);
 
-	fd = openat(ns_fd, "pid", O_RDONLY | O_CLOEXEC);
-	if (setns(fd, CLONE_NEWPID))
-		return false;
-	close(fd);
+	return setns(fd, CLONE_NEWUSER) == 0;
+}
+
+static bool change_creds(int ns_fd, cap_t caps, uid_t nsuid, gid_t nsgid)
+{
+	__do_close_prot_errno int fd = -EBADF;
 
-	fd = openat(ns_fd, "uts", O_RDONLY | O_CLOEXEC);
-	if (setns(fd, CLONE_NEWUTS))
+	if (prctl(PR_SET_KEEPCAPS, 1))
 		return false;
-	// compiler taking care of fd again now
+
+	for (const char **ns = ns_names; ns && *ns; ns++) {
+		if (!setnsat(ns_fd, *ns))
+			return false;
+	}
 
 	if (setegid(nsgid))
 		return false;

From ded98488fca5fa41cc23ef11fa59974282b7c053 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Wed, 17 Jul 2019 11:09:22 +0200
Subject: [PATCH 2/2] seccomp: retrieve fs{g,u}id when handling syscalls

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/container_lxc.go    |  2 +-
 lxd/main_forksyscall.go | 24 +++++++------
 lxd/seccomp.go          | 74 +++++++++++++++++++++++++++++------------
 3 files changed, 68 insertions(+), 32 deletions(-)

diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 6f1b5dcfba..98f28fd511 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -7603,7 +7603,7 @@ func (c *containerLXC) InsertSeccompUnixDevice(prefix string, m types.Device, pi
 		return err
 	}
 
-	err, uid, gid := taskUidGid(pid)
+	err, uid, gid, _, _ := taskIds(pid)
 	if err != nil {
 		return err
 	}
diff --git a/lxd/main_forksyscall.go b/lxd/main_forksyscall.go
index 2f2c8c0712..1b7f2e35ac 100644
--- a/lxd/main_forksyscall.go
+++ b/lxd/main_forksyscall.go
@@ -126,8 +126,8 @@ static void forkmknod()
 	mode_t mode = 0;
 	dev_t dev = 0;
 	pid_t pid = 0;
-	uid_t uid = -1;
-	gid_t gid = -1;
+	uid_t fsuid = -1, uid = -1;
+	gid_t fsgid = -1, gid = -1;
 	struct stat s1, s2;
 	struct statfs sfs1, sfs2;
 	cap_t caps;
@@ -140,6 +140,8 @@ static void forkmknod()
 	target_host = advance_arg(true);
 	uid = atoi(advance_arg(true));
 	gid = atoi(advance_arg(true));
+	fsuid = atoi(advance_arg(true));
+	fsgid = atoi(advance_arg(true));
 	chk_perm_only = atoi(advance_arg(true));
 
 	if (*target == '/') {
@@ -198,7 +200,7 @@ static void forkmknod()
 		_exit(EXIT_FAILURE);
 	}
 
-	setfsgid(gid);
+	setfsgid(fsgid);
 
 	ret = seteuid(uid);
 	if (ret) {
@@ -206,7 +208,7 @@ static void forkmknod()
 		_exit(EXIT_FAILURE);
 	}
 
-	setfsuid(uid);
+	setfsuid(fsuid);
 
 	ret = cap_set_proc(caps);
 	if (ret) {
@@ -267,7 +269,7 @@ static bool setnsat(int ns_fd, const char *ns)
 	return setns(fd, CLONE_NEWUSER) == 0;
 }
 
-static bool change_creds(int ns_fd, cap_t caps, uid_t nsuid, gid_t nsgid)
+static bool change_creds(int ns_fd, cap_t caps, uid_t nsuid, gid_t nsgid, uid_t nsfsuid, gid_t nsfsgid)
 {
 	__do_close_prot_errno int fd = -EBADF;
 
@@ -282,12 +284,12 @@ static bool change_creds(int ns_fd, cap_t caps, uid_t nsuid, gid_t nsgid)
 	if (setegid(nsgid))
 		return false;
 
-	setfsgid(nsgid);
+	setfsgid(nsfsgid);
 
 	if (seteuid(nsuid))
 		return false;
 
-	setfsuid(nsuid);
+	setfsuid(nsfsuid);
 
 	if (cap_set_proc(caps))
 		return false;
@@ -301,8 +303,8 @@ static void forksetxattr()
 	int flags = 0;
 	char *name, *path;
 	char ns_path[PATH_MAX];
-	uid_t nsuid;
-	gid_t nsgid;
+	uid_t nsfsuid, nsuid;
+	gid_t nsfsgid, nsgid;
 	pid_t pid = 0;
 	cap_t caps;
 	cap_flag_value_t flag;
@@ -313,6 +315,8 @@ static void forksetxattr()
 	pid = atoi(advance_arg(true));
 	nsuid = atoi(advance_arg(true));
 	nsgid = atoi(advance_arg(true));
+	nsfsuid = atoi(advance_arg(true));
+	nsfsgid = atoi(advance_arg(true));
 	name = advance_arg(true);
 	path = advance_arg(true);
 	flags = atoi(advance_arg(true));
@@ -362,7 +366,7 @@ static void forksetxattr()
 			_exit(EXIT_FAILURE);
 		}
 	} else {
-		if (!change_creds(ns_fd, caps, nsuid, nsgid)) {
+		if (!change_creds(ns_fd, caps, nsuid, nsgid, nsfsuid, nsfsgid)) {
 			fprintf(stderr, "%d", EFAULT);
 			_exit(EXIT_FAILURE);
 		}
diff --git a/lxd/seccomp.go b/lxd/seccomp.go
index e0830c7aa1..0f9e1e0ca9 100644
--- a/lxd/seccomp.go
+++ b/lxd/seccomp.go
@@ -788,16 +788,18 @@ func NewSeccompServer(d *Daemon, path string) (*SeccompServer, error) {
 	return &s, nil
 }
 
-func taskUidGid(pid int) (error, int32, int32) {
+func taskIds(pid int) (error, int32, int32, int32, int32) {
 	status, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/status", pid))
 	if err != nil {
-		return err, -1, -1
+		return err, -1, -1, -1, -1
 	}
 
-	reUid := regexp.MustCompile("Uid:\\s*([0-9]*)\\s*([0-9]*)")
-	reGid := regexp.MustCompile("Gid:\\s*([0-9]*)\\s*([0-9]*)")
-	var gid int32
-	var uid int32
+	reUid := regexp.MustCompile("Uid:\\s*([0-9]*)\\s*([0-9]*)\\s*([0-9]*)\\s*([0-9]*)")
+	reGid := regexp.MustCompile("Gid:\\s*([0-9]*)\\s*([0-9]*)\\s*([0-9]*)\\s*([0-9]*)")
+	var gid int32 = -1
+	var uid int32 = -1
+	var fsgid int32 = -1
+	var fsuid int32 = -1
 	uidFound := false
 	gidFound := false
 	for _, line := range strings.Split(string(status), "\n") {
@@ -811,13 +813,24 @@ func taskUidGid(pid int) (error, int32, int32) {
 				// effective uid
 				result, err := strconv.Atoi(m[2])
 				if err != nil {
-					return err, -1, -1
+					return err, -1, -1, -1, -1
 				}
 
 				uid = int32(result)
 				uidFound = true
-				continue
 			}
+
+			if m != nil && len(m) > 4 {
+				// fsuid
+				result, err := strconv.Atoi(m[4])
+				if err != nil {
+					return err, -1, -1, -1, -1
+				}
+
+				fsuid = int32(result)
+			}
+
+			continue
 		}
 
 		if !gidFound {
@@ -826,17 +839,28 @@ func taskUidGid(pid int) (error, int32, int32) {
 				// effective gid
 				result, err := strconv.Atoi(m[2])
 				if err != nil {
-					return err, -1, -1
+					return err, -1, -1, -1, -1
 				}
 
 				gid = int32(result)
 				gidFound = true
-				continue
 			}
+
+			if m != nil && len(m) > 4 {
+				// fsgid
+				result, err := strconv.Atoi(m[4])
+				if err != nil {
+					return err, -1, -1, -1, -1
+				}
+
+				fsgid = int32(result)
+			}
+
+			continue
 		}
 	}
 
-	return nil, uid, gid
+	return nil, uid, gid, fsuid, fsgid
 }
 
 func CallForkmknod(c container, dev types.Device, requestPID int, permissionsOnly int) int {
@@ -846,7 +870,7 @@ func CallForkmknod(c container, dev types.Device, requestPID int, permissionsOnl
 		return int(-C.EPERM)
 	}
 
-	err, uid, gid := taskUidGid(requestPID)
+	err, uid, gid, fsuid, fsgid := taskIds(requestPID)
 	if err != nil {
 		return int(-C.EPERM)
 	}
@@ -868,6 +892,7 @@ func CallForkmknod(c container, dev types.Device, requestPID int, permissionsOnl
 		"forksyscall", "mknod", dev["pid"], dev["path"],
 		dev["mode_t"], dev["dev_t"], dev["hostpath"],
 		fmt.Sprintf("%d", uid), fmt.Sprintf("%d", gid),
+		fmt.Sprintf("%d", fsuid), fmt.Sprintf("%d", fsgid),
 		fmt.Sprintf("%d", permissionsOnly))
 	if err != nil {
 		errno, err := strconv.Atoi(stderr)
@@ -1011,14 +1036,16 @@ func (s *SeccompServer) HandleMknodatSyscall(c container, siov *SeccompIovec) in
 }
 
 type SetxattrArgs struct {
-	nsuid int
-	nsgid int
-	size  int
-	pid   int
-	path  string
-	name  string
-	value []byte
-	flags C.int
+	nsuid   int
+	nsgid   int
+	nsfsuid int
+	nsfsgid int
+	size    int
+	pid     int
+	path    string
+	name    string
+	value   []byte
+	flags   C.int
 }
 
 func (s *SeccompServer) HandleSetxattrSyscall(c container, siov *SeccompIovec) int {
@@ -1034,12 +1061,15 @@ func (s *SeccompServer) HandleSetxattrSyscall(c container, siov *SeccompIovec) i
 	args := SetxattrArgs{}
 
 	args.pid = int(siov.req.pid)
-	err, uid, gid := taskUidGid(args.pid)
+	err, uid, gid, fsuid, fsgid := taskIds(args.pid)
 	if err != nil {
 		return int(-C.EPERM)
 	}
+
 	args.nsuid = GetNSUid(uint(uid), args.pid)
 	args.nsgid = GetNSGid(uint(gid), args.pid)
+	args.nsfsuid = GetNSUid(uint(fsuid), args.pid)
+	args.nsfsgid = GetNSGid(uint(fsgid), args.pid)
 
 	// const char *path
 	cBuf := [unix.PathMax]C.char{}
@@ -1083,6 +1113,8 @@ func (s *SeccompServer) HandleSetxattrSyscall(c container, siov *SeccompIovec) i
 		fmt.Sprintf("%d", args.pid),
 		fmt.Sprintf("%d", args.nsuid),
 		fmt.Sprintf("%d", args.nsgid),
+		fmt.Sprintf("%d", args.nsfsuid),
+		fmt.Sprintf("%d", args.nsfsgid),
 		args.name,
 		args.path,
 		fmt.Sprintf("%d", args.flags),


More information about the lxc-devel mailing list