[lxc-devel] [lxd/master] seccomp: ensure correct owner on __NR_mknod{at}
brauner on Github
lxc-bot at linuxcontainers.org
Thu Jun 27 22:53:43 UTC 2019
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 417 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20190627/85fb3744/attachment.bin>
-------------- next part --------------
From cd21241f20074f9a4f1200577f6e1e4e7fd791a3 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Thu, 27 Jun 2019 23:40:06 +0200
Subject: [PATCH] seccomp: ensure correct owner on __NR_mknod{at}
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Reported-by: Stéphane Graber <stgraber at ubuntu.com>
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
lxd/container_lxc.go | 8 ++++
lxd/main_forkmknod.go | 100 +++++++++++++++++++++++++-----------------
lxd/seccomp.go | 60 ++++++++++++++++++++++++-
3 files changed, 126 insertions(+), 42 deletions(-)
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index c9ed8937e8..552673091f 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -7578,6 +7578,14 @@ func (c *containerLXC) InsertSeccompUnixDevice(prefix string, m types.Device, pi
return err
}
+ err, uid, gid := taskUidGid(pid)
+ if err != nil {
+ return err
+ }
+
+ m["uid"] = fmt.Sprintf("%d", uid)
+ m["gid"] = fmt.Sprintf("%d", gid)
+
prefixPath = strings.TrimPrefix(prefixPath, rootPath)
m["path"] = filepath.Join(rootPath, prefixPath, m["path"])
paths, err := c.createUnixDevice(prefix, m, true)
diff --git a/lxd/main_forkmknod.go b/lxd/main_forkmknod.go
index 8196df0c2e..f1f9403a84 100644
--- a/lxd/main_forkmknod.go
+++ b/lxd/main_forkmknod.go
@@ -26,66 +26,60 @@ import (
extern char* advance_arg(bool required);
extern int dosetns(int pid, char *nstype);
-static uid_t get_root_uid(pid_t pid)
+static uid_t get_host_uid(uid_t uid, pid_t pid)
{
- char *line = NULL;
- size_t sz = 0;
- uid_t nsid, hostid, range;
- FILE *f;
+ __do_free char *line = NULL;
+ __do_fclose FILE *f = NULL;
+ size_t sz = 0;
char path[256];
+ uid_t nsid, hostid, range;
snprintf(path, sizeof(path), "/proc/%d/uid_map", pid);
f = fopen(path, "re");
if (!f)
return -1;
- while (getline(&line, &sz, f) != -1) {
- if (sscanf(line, "%u %u %u", &nsid, &hostid, &range) != 3)
- continue;
+ while (getline(&line, &sz, f) != -1) {
+ if (sscanf(line, "%u %u %u", &nsid, &hostid, &range) != 3)
+ continue;
- if (nsid == 0)
+ if (nsid <= uid && nsid + range > uid) {
+ hostid += uid - nsid;
return hostid;
- }
-
- nsid = -1;
+ }
+ }
-found:
- fclose(f);
- free(line);
- return nsid;
+ return -1;
}
-static gid_t get_root_gid(pid_t pid)
+static gid_t get_host_gid(uid_t gid, pid_t pid)
{
- char *line = NULL;
- size_t sz = 0;
- gid_t nsid, hostid, range;
- FILE *f;
+ __do_free char *line = NULL;
+ __do_fclose FILE *f = NULL;
+ size_t sz = 0;
char path[256];
+ uid_t nsid, hostid, range;
snprintf(path, sizeof(path), "/proc/%d/gid_map", pid);
f = fopen(path, "re");
if (!f)
return -1;
- while (getline(&line, &sz, f) != -1) {
- if (sscanf(line, "%u %u %u", &nsid, &hostid, &range) != 3)
- continue;
+ while (getline(&line, &sz, f) != -1) {
+ if (sscanf(line, "%u %u %u", &nsid, &hostid, &range) != 3)
+ continue;
- if (nsid == 0)
+ if (nsid <= gid && nsid + range > gid) {
+ hostid += gid - nsid;
return hostid;
- }
-
- nsid = -1;
+ }
+ }
-found:
- fclose(f);
- free(line);
- return nsid;
+ return -1;
}
static int chowmknod(const char *path, mode_t mode, dev_t dev,
- uid_t uid, gid_t gid)
+ uid_t uid, gid_t gid)
{
int ret;
@@ -93,7 +87,25 @@ static int chowmknod(const char *path, mode_t mode, dev_t dev,
if (ret)
return -1;
- return chown(path, uid, gid);
+ ret = chown(path, uid, gid);
+ if (ret)
+ (void)unlink(path);
+ return ret;
+}
+
+static int fchowmknodat(int fd, const char *path, mode_t mode, dev_t dev,
+ uid_t uid, gid_t gid)
+{
+ int ret;
+
+ ret = mknodat(fd, path, mode, dev);
+ if (ret)
+ return -1;
+
+ ret = fchownat(fd, path, uid, gid, 0);
+ if (ret)
+ (void)unlinkat(fd, path, 0);
+ return ret;
}
static int chdirchroot(pid_t pid)
@@ -170,14 +182,20 @@ void forkmknod()
mode = atoi(advance_arg(true));
dev = atoi(advance_arg(true));
target_host = advance_arg(true);
+ uid = atoi(advance_arg(true));
+ gid = atoi(advance_arg(true));
- uid = get_root_uid(pid);
- if (uid < 0)
- fprintf(stderr, "No root uid found (%d)\n", uid);
+ if (uid < 0) {
+ uid = get_host_uid(0, pid);
+ if (uid < 0)
+ fprintf(stderr, "No root uid found (%d)\n", uid);
+ }
- gid = get_root_gid(pid);
- if (gid < 0)
- fprintf(stderr, "No root gid found (%d)\n", gid);
+ if (gid < 0) {
+ gid = get_host_gid(0, pid);
+ if (gid < 0)
+ fprintf(stderr, "No root gid found (%d)\n", gid);
+ }
// dirname() can modify its argument
target_host_dup = strdup(target_host);
@@ -216,7 +234,7 @@ void forkmknod()
// basename() can modify its argument so accessing target_host is
// invalid from now on.
- ret = mknodat(target_fd, basename(target_host), mode, dev);
+ ret = fchowmknodat(target_fd, basename(target_host), mode, dev, uid, gid);
if (ret) {
if (errno == EEXIST) {
fprintf(stderr, "%d", errno);
diff --git a/lxd/seccomp.go b/lxd/seccomp.go
index 9c4d9cf60c..c83f697b3c 100644
--- a/lxd/seccomp.go
+++ b/lxd/seccomp.go
@@ -11,6 +11,7 @@ import (
"os"
"path"
"path/filepath"
+ "regexp"
"strconv"
"strings"
"unsafe"
@@ -445,6 +446,57 @@ func NewSeccompServer(d *Daemon, path string) (*SeccompServer, error) {
return &s, nil
}
+func taskUidGid(pid int) (error, int32, int32) {
+ status, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/status", pid))
+ if err != nil {
+ return err, -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
+ uidFound := false
+ gidFound := false
+ for _, line := range strings.Split(string(status), "\n") {
+ if uidFound && gidFound {
+ break
+ }
+
+ if !uidFound {
+ m := reUid.FindStringSubmatch(line)
+ if m != nil && len(m) > 2 {
+ // effective uid
+ result, err := strconv.Atoi(m[2])
+ if err != nil {
+ return err, -1, -1
+ }
+
+ uid = int32(result)
+ uidFound = true
+ continue
+ }
+ }
+
+ if !gidFound {
+ m := reGid.FindStringSubmatch(line)
+ if m != nil && len(m) > 2 {
+ // effective gid
+ result, err := strconv.Atoi(m[2])
+ if err != nil {
+ return err, -1, -1
+ }
+
+ gid = int32(result)
+ gidFound = true
+ continue
+ }
+ }
+ }
+
+ return nil, uid, gid
+}
+
func doMknod(c container, dev types.Device, requestPID int) (error, int) {
goErrno := int(-C.EPERM)
@@ -460,11 +512,17 @@ func doMknod(c container, dev types.Device, requestPID int) (error, int) {
return err, goErrno
}
+ err, uid, gid := taskUidGid(requestPID)
+ if err != nil {
+ return err, goErrno
+ }
+
prefixPath = strings.TrimPrefix(prefixPath, rootPath)
dev["hostpath"] = filepath.Join(c.RootfsPath(), rootPath, prefixPath, dev["path"])
errnoMsg, err := shared.RunCommand(util.GetExecPath(),
"forkmknod", dev["pid"], dev["path"],
- dev["mode_t"], dev["dev_t"], dev["hostpath"])
+ dev["mode_t"], dev["dev_t"], dev["hostpath"],
+ fmt.Sprintf("%d", uid), fmt.Sprintf("%d", gid))
if err != nil {
tmp, err2 := strconv.Atoi(errnoMsg)
if err2 == nil {
More information about the lxc-devel
mailing list