432cb7
From 2754dc2c7def01d7dd1bb39f3e86ef444652d397 Mon Sep 17 00:00:00 2001
432cb7
From: Vivek Goyal <vgoyal@redhat.com>
432cb7
Date: Tue, 25 Jan 2022 13:51:14 -0500
432cb7
Subject: [PATCH 1/6] virtiofsd: Drop membership of all supplementary groups
432cb7
 (CVE-2022-0358)
432cb7
432cb7
RH-Author: Dr. David Alan Gilbert <dgilbert@redhat.com>
432cb7
RH-MergeRequest: 102: virtiofsd: Drop membership of all supplementary groups (CVE-2022-0358)
432cb7
RH-Commit: [1/1] 93e56c88277fec8e42559a899d32b80fac4a923f
432cb7
RH-Bugzilla: 2046198
432cb7
RH-Acked-by: Greg Kurz <gkurz@redhat.com>
432cb7
RH-Acked-by: Sergio Lopez <None>
432cb7
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
432cb7
432cb7
At the start, drop membership of all supplementary groups. This is
432cb7
not required.
432cb7
432cb7
If we have membership of "root" supplementary group and when we switch
432cb7
uid/gid using setresuid/setsgid, we still retain membership of existing
432cb7
supplemntary groups. And that can allow some operations which are not
432cb7
normally allowed.
432cb7
432cb7
For example, if root in guest creates a dir as follows.
432cb7
432cb7
$ mkdir -m 03777 test_dir
432cb7
432cb7
This sets SGID on dir as well as allows unprivileged users to write into
432cb7
this dir.
432cb7
432cb7
And now as unprivileged user open file as follows.
432cb7
432cb7
$ su test
432cb7
$ fd = open("test_dir/priviledge_id", O_RDWR|O_CREAT|O_EXCL, 02755);
432cb7
432cb7
This will create SGID set executable in test_dir/.
432cb7
432cb7
And that's a problem because now an unpriviliged user can execute it,
432cb7
get egid=0 and get access to resources owned by "root" group. This is
432cb7
privilege escalation.
432cb7
432cb7
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2044863
432cb7
Fixes: CVE-2022-0358
432cb7
Reported-by: JIETAO XIAO <shawtao1125@gmail.com>
432cb7
Suggested-by: Miklos Szeredi <mszeredi@redhat.com>
432cb7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
432cb7
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
432cb7
Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
432cb7
Message-Id: <YfBGoriS38eBQrAb@redhat.com>
432cb7
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
432cb7
  dgilbert: Fixed missing {}'s style nit
432cb7
(cherry picked from commit 449e8171f96a6a944d1f3b7d3627ae059eae21ca)
432cb7
---
432cb7
 tools/virtiofsd/passthrough_ll.c | 27 +++++++++++++++++++++++++++
432cb7
 1 file changed, 27 insertions(+)
432cb7
432cb7
diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
432cb7
index 64b5b4fbb1..b3d0674f6d 100644
432cb7
--- a/tools/virtiofsd/passthrough_ll.c
432cb7
+++ b/tools/virtiofsd/passthrough_ll.c
432cb7
@@ -54,6 +54,7 @@
432cb7
 #include <sys/wait.h>
432cb7
 #include <sys/xattr.h>
432cb7
 #include <syslog.h>
432cb7
+#include <grp.h>
432cb7
 
432cb7
 #include "qemu/cutils.h"
432cb7
 #include "passthrough_helpers.h"
432cb7
@@ -1161,6 +1162,30 @@ static void lo_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
432cb7
 #define OURSYS_setresuid SYS_setresuid
432cb7
 #endif
432cb7
 
432cb7
+static void drop_supplementary_groups(void)
432cb7
+{
432cb7
+    int ret;
432cb7
+
432cb7
+    ret = getgroups(0, NULL);
432cb7
+    if (ret == -1) {
432cb7
+        fuse_log(FUSE_LOG_ERR, "getgroups() failed with error=%d:%s\n",
432cb7
+                 errno, strerror(errno));
432cb7
+        exit(1);
432cb7
+    }
432cb7
+
432cb7
+    if (!ret) {
432cb7
+        return;
432cb7
+    }
432cb7
+
432cb7
+    /* Drop all supplementary groups. We should not need it */
432cb7
+    ret = setgroups(0, NULL);
432cb7
+    if (ret == -1) {
432cb7
+        fuse_log(FUSE_LOG_ERR, "setgroups() failed with error=%d:%s\n",
432cb7
+                 errno, strerror(errno));
432cb7
+        exit(1);
432cb7
+    }
432cb7
+}
432cb7
+
432cb7
 /*
432cb7
  * Change to uid/gid of caller so that file is created with
432cb7
  * ownership of caller.
432cb7
@@ -3926,6 +3951,8 @@ int main(int argc, char *argv[])
432cb7
 
432cb7
     qemu_init_exec_dir(argv[0]);
432cb7
 
432cb7
+    drop_supplementary_groups();
432cb7
+
432cb7
     pthread_mutex_init(&lo.mutex, NULL);
432cb7
     lo.inodes = g_hash_table_new(lo_key_hash, lo_key_equal);
432cb7
     lo.root.fd = -1;
432cb7
-- 
432cb7
2.27.0
432cb7