diff mbox series

virtiofsd: Drop membership of all supplementary groups (CVE-2022-0358)

Message ID YfBGoriS38eBQrAb@redhat.com
State New
Headers show
Series virtiofsd: Drop membership of all supplementary groups (CVE-2022-0358) | expand

Commit Message

Vivek Goyal Jan. 25, 2022, 6:51 p.m. UTC
At the start, drop membership of all supplementary groups. This is
not required.

If we have membership of "root" supplementary group and when we switch
uid/gid using setresuid/setsgid, we still retain membership of existing
supplemntary groups. And that can allow some operations which are not
normally allowed.

For example, if root in guest creates a dir as follows.

$ mkdir -m 03777 test_dir

This sets SGID on dir as well as allows unprivileged users to write into
this dir. 

And now as unprivileged user open file as follows.

$ su test
$ fd = open("test_dir/priviledge_id", O_RDWR|O_CREAT|O_EXCL, 02755);

This will create SGID set executable in test_dir/.

And that's a problem because now an unpriviliged user can execute it,
get egid=0 and get access to resources owned by "root" group. This is
privilege escalation.

Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2044863
Fixes: CVE-2022-0358
Reported-by: JIETAO XIAO <shawtao1125@gmail.com>
Suggested-by: Miklos Szeredi <mszeredi@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
---
 tools/virtiofsd/passthrough_ll.c |   26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

Comments

Stefan Hajnoczi Jan. 26, 2022, 10:03 a.m. UTC | #1
On Tue, Jan 25, 2022 at 01:51:14PM -0500, Vivek Goyal wrote:
> At the start, drop membership of all supplementary groups. This is
> not required.
> 
> If we have membership of "root" supplementary group and when we switch
> uid/gid using setresuid/setsgid, we still retain membership of existing
> supplemntary groups. And that can allow some operations which are not
> normally allowed.
> 
> For example, if root in guest creates a dir as follows.
> 
> $ mkdir -m 03777 test_dir
> 
> This sets SGID on dir as well as allows unprivileged users to write into
> this dir. 
> 
> And now as unprivileged user open file as follows.
> 
> $ su test
> $ fd = open("test_dir/priviledge_id", O_RDWR|O_CREAT|O_EXCL, 02755);
> 
> This will create SGID set executable in test_dir/.
> 
> And that's a problem because now an unpriviliged user can execute it,
> get egid=0 and get access to resources owned by "root" group. This is
> privilege escalation.
> 
> Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2044863
> Fixes: CVE-2022-0358
> Reported-by: JIETAO XIAO <shawtao1125@gmail.com>
> Suggested-by: Miklos Szeredi <mszeredi@redhat.com>
> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
> Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
> Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
> ---
>  tools/virtiofsd/passthrough_ll.c |   26 ++++++++++++++++++++++++++
>  1 file changed, 26 insertions(+)
> 
> Index: rhvgoyal-qemu/tools/virtiofsd/passthrough_ll.c
> ===================================================================
> --- rhvgoyal-qemu.orig/tools/virtiofsd/passthrough_ll.c	2022-01-25 13:38:59.349534531 -0500
> +++ rhvgoyal-qemu/tools/virtiofsd/passthrough_ll.c	2022-01-25 13:39:10.140177868 -0500
> @@ -54,6 +54,7 @@
>  #include <sys/wait.h>
>  #include <sys/xattr.h>
>  #include <syslog.h>
> +#include <grp.h>
>  
>  #include "qemu/cutils.h"
>  #include "passthrough_helpers.h"
> @@ -1161,6 +1162,29 @@ static void lo_lookup(fuse_req_t req, fu
>  #define OURSYS_setresuid SYS_setresuid
>  #endif
>  
> +static void drop_supplementary_groups(void)
> +{
> +    int ret;
> +
> +    ret = getgroups(0, NULL);
> +    if (ret == -1) {
> +        fuse_log(FUSE_LOG_ERR, "getgroups() failed with error=%d:%s\n",
> +                 errno, strerror(errno));
> +        exit(1);
> +    }
> +
> +    if (!ret)
> +        return;
> +
> +    /* Drop all supplementary groups. We should not need it */
> +    ret = setgroups(0, NULL);
> +    if (ret == -1) {
> +        fuse_log(FUSE_LOG_ERR, "setgroups() failed with error=%d:%s\n",
> +                 errno, strerror(errno));
> +        exit(1);
> +    }
> +}
> +
>  /*
>   * Change to uid/gid of caller so that file is created with
>   * ownership of caller.
> @@ -3926,6 +3950,8 @@ int main(int argc, char *argv[])
>  
>      qemu_init_exec_dir(argv[0]);
>  
> +    drop_supplementary_groups();
> +
>      pthread_mutex_init(&lo.mutex, NULL);
>      lo.inodes = g_hash_table_new(lo_key_hash, lo_key_equal);
>      lo.root.fd = -1;
> 

Thanks, applied to my block tree:
https://gitlab.com/stefanha/qemu/commits/block

Stefan
Dr. David Alan Gilbert Jan. 26, 2022, 10:51 a.m. UTC | #2
* Stefan Hajnoczi (stefanha@redhat.com) wrote:
> On Tue, Jan 25, 2022 at 01:51:14PM -0500, Vivek Goyal wrote:
> > At the start, drop membership of all supplementary groups. This is
> > not required.
> > 
> > If we have membership of "root" supplementary group and when we switch
> > uid/gid using setresuid/setsgid, we still retain membership of existing
> > supplemntary groups. And that can allow some operations which are not
> > normally allowed.
> > 
> > For example, if root in guest creates a dir as follows.
> > 
> > $ mkdir -m 03777 test_dir
> > 
> > This sets SGID on dir as well as allows unprivileged users to write into
> > this dir. 
> > 
> > And now as unprivileged user open file as follows.
> > 
> > $ su test
> > $ fd = open("test_dir/priviledge_id", O_RDWR|O_CREAT|O_EXCL, 02755);
> > 
> > This will create SGID set executable in test_dir/.
> > 
> > And that's a problem because now an unpriviliged user can execute it,
> > get egid=0 and get access to resources owned by "root" group. This is
> > privilege escalation.
> > 
> > Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2044863
> > Fixes: CVE-2022-0358
> > Reported-by: JIETAO XIAO <shawtao1125@gmail.com>
> > Suggested-by: Miklos Szeredi <mszeredi@redhat.com>
> > Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
> > Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
> > Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
> > ---
> >  tools/virtiofsd/passthrough_ll.c |   26 ++++++++++++++++++++++++++
> >  1 file changed, 26 insertions(+)
> > 
> > Index: rhvgoyal-qemu/tools/virtiofsd/passthrough_ll.c
> > ===================================================================
> > --- rhvgoyal-qemu.orig/tools/virtiofsd/passthrough_ll.c	2022-01-25 13:38:59.349534531 -0500
> > +++ rhvgoyal-qemu/tools/virtiofsd/passthrough_ll.c	2022-01-25 13:39:10.140177868 -0500
> > @@ -54,6 +54,7 @@
> >  #include <sys/wait.h>
> >  #include <sys/xattr.h>
> >  #include <syslog.h>
> > +#include <grp.h>
> >  
> >  #include "qemu/cutils.h"
> >  #include "passthrough_helpers.h"
> > @@ -1161,6 +1162,29 @@ static void lo_lookup(fuse_req_t req, fu
> >  #define OURSYS_setresuid SYS_setresuid
> >  #endif
> >  
> > +static void drop_supplementary_groups(void)
> > +{
> > +    int ret;
> > +
> > +    ret = getgroups(0, NULL);
> > +    if (ret == -1) {
> > +        fuse_log(FUSE_LOG_ERR, "getgroups() failed with error=%d:%s\n",
> > +                 errno, strerror(errno));
> > +        exit(1);
> > +    }
> > +
> > +    if (!ret)
> > +        return;
> > +
> > +    /* Drop all supplementary groups. We should not need it */
> > +    ret = setgroups(0, NULL);
> > +    if (ret == -1) {
> > +        fuse_log(FUSE_LOG_ERR, "setgroups() failed with error=%d:%s\n",
> > +                 errno, strerror(errno));
> > +        exit(1);
> > +    }
> > +}
> > +
> >  /*
> >   * Change to uid/gid of caller so that file is created with
> >   * ownership of caller.
> > @@ -3926,6 +3950,8 @@ int main(int argc, char *argv[])
> >  
> >      qemu_init_exec_dir(argv[0]);
> >  
> > +    drop_supplementary_groups();
> > +
> >      pthread_mutex_init(&lo.mutex, NULL);
> >      lo.inodes = g_hash_table_new(lo_key_hash, lo_key_equal);
> >      lo.root.fd = -1;
> > 
> 
> Thanks, applied to my block tree:
> https://gitlab.com/stefanha/qemu/commits/block

Actually, I just posted it as a separate pull by itself.

(I added {}'s around the if (!ret) { return; }  to meet Qemu
style guides).

Dave


> Stefan
diff mbox series

Patch

Index: rhvgoyal-qemu/tools/virtiofsd/passthrough_ll.c
===================================================================
--- rhvgoyal-qemu.orig/tools/virtiofsd/passthrough_ll.c	2022-01-25 13:38:59.349534531 -0500
+++ rhvgoyal-qemu/tools/virtiofsd/passthrough_ll.c	2022-01-25 13:39:10.140177868 -0500
@@ -54,6 +54,7 @@ 
 #include <sys/wait.h>
 #include <sys/xattr.h>
 #include <syslog.h>
+#include <grp.h>
 
 #include "qemu/cutils.h"
 #include "passthrough_helpers.h"
@@ -1161,6 +1162,29 @@  static void lo_lookup(fuse_req_t req, fu
 #define OURSYS_setresuid SYS_setresuid
 #endif
 
+static void drop_supplementary_groups(void)
+{
+    int ret;
+
+    ret = getgroups(0, NULL);
+    if (ret == -1) {
+        fuse_log(FUSE_LOG_ERR, "getgroups() failed with error=%d:%s\n",
+                 errno, strerror(errno));
+        exit(1);
+    }
+
+    if (!ret)
+        return;
+
+    /* Drop all supplementary groups. We should not need it */
+    ret = setgroups(0, NULL);
+    if (ret == -1) {
+        fuse_log(FUSE_LOG_ERR, "setgroups() failed with error=%d:%s\n",
+                 errno, strerror(errno));
+        exit(1);
+    }
+}
+
 /*
  * Change to uid/gid of caller so that file is created with
  * ownership of caller.
@@ -3926,6 +3950,8 @@  int main(int argc, char *argv[])
 
     qemu_init_exec_dir(argv[0]);
 
+    drop_supplementary_groups();
+
     pthread_mutex_init(&lo.mutex, NULL);
     lo.inodes = g_hash_table_new(lo_key_hash, lo_key_equal);
     lo.root.fd = -1;