[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH v4] run QEMU as non-root



On Thu, 25 Jun 2015, Ian Campbell wrote:
> On Mon, 2015-06-01 at 17:46 +0100, Stefano Stabellini wrote:
> > Try to use "xen-qemudepriv-$domname" first, then
> > "xen-qemudepriv-domid$domid", finally "xen-qemudepriv-shared" and root
> > if everything else fails.
> > 
> > The uids need to be manually created by the user or, more likely, by the
> > xen package maintainer.
> > 
> > To actually secure QEMU when running in Dom0, we need at least to
> > deprivilege the privcmd and xenstore interfaces, this is just the first
> > step in that direction.
> > 
> > Signed-off-by: Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>
> > 
> > ---
> > Changes in v4:
> > - rename qemu-deprivilege to qemu-deprivilege.txt
> > - add a note about qemu-deprivilege.txt to INSTALL
> > - instead of xen-qemudepriv-base + $domid, try xen-qemudepriv-domid$domid
> > - introduce libxl__dm_runas_helper to make the code nicer
> > 
> > Changes in v3:
> > - clarify doc
> > - handle errno == ERANGE
> > ---
> >  INSTALL                        |    7 ++++++
> >  docs/misc/qemu-deprivilege.txt |   34 +++++++++++++++++++++++++
> >  tools/libxl/libxl_dm.c         |   54 
> > ++++++++++++++++++++++++++++++++++++++++
> >  tools/libxl/libxl_internal.h   |    4 +++
> >  4 files changed, 99 insertions(+)
> >  create mode 100644 docs/misc/qemu-deprivilege.txt
> > 
> > diff --git a/INSTALL b/INSTALL
> > index a0f2e7b..3286a5f 100644
> > --- a/INSTALL
> > +++ b/INSTALL
> > @@ -297,6 +297,13 @@ systemctl enable xendomains.service
> >  systemctl enable xen-watchdog.service
> >  
> > 
> > +QEMU Deprivilege
> > +================
> > +It is recommended to run QEMU as non-root.
> > +See docs/misc/qemu-deprivilege.txt for an explanation on what you need
> > +to do at installation time to run QEMU as a regular user.
> 
> I'd be tempted to say something like "as a dedicated user" or something,
> "regular user" sounds like I should be running it as my normal login
> user or something.

OK


> > +
> > +
> >  History of options
> >  ==================
> >  
> > diff --git a/docs/misc/qemu-deprivilege.txt b/docs/misc/qemu-deprivilege.txt
> > new file mode 100644
> > index 0000000..db61aaf
> > --- /dev/null
> > +++ b/docs/misc/qemu-deprivilege.txt
> > @@ -0,0 +1,34 @@
> > +For security reasons, libxl tries to create QEMU as non-root.
> > +Libxl looks for the following users in this order:
> > +
> > +1) a user named "xen-qemuuser-$domname"
> > +Where $domname is the name of the domain being created.
> > +To use this, you just need to create a user with the appropriate name
> > +for each domain. For example, if your virtual machine is named "windows":
> > +
> > +adduser --system xen-qemuuser-windows
> 
> I just had an annoying thought: On migration (with xl at least) the
> receive side appends "-incoming" to the domain name for the duration and
> then renames ones everything is done, which is suddenly not going to
> match here :-(
> 
> Since this is managed at the xl level I don't see any way libxl could
> cope without being told separately the domain's "real" name.
> 
> I think this reduces the utility of this option quite substantially (or
> at least presents an enormous caveat), perhaps to the point where we may
> as well not bother to offer it?

I think we can detect the "--incoming" and remove it. The only problem
is that "--incoming" is actually set by xl (xl_cmdimpl.c), not libxl.
Could we break the abstraction layer just this time and in libxl_dm.c
have something like:


     if ((strlen(c_info->name) > strlen("--incoming")) &&
         (!strcmp(c_info->name + strlen(c_info->name) - strlen("--incoming"), 
"--incoming"))) {
         name = libxl__strdup(gc, c_info->name);
         name[strlen(c_info->name) - strlen("--incoming")] = '\0';
     } else {
         name = c_info->name;
     }
     user = libxl__sprintf(gc, "%s-%s", LIBXL_QEMU_USER_PREFIX, name);


This is ugly but it was only meant to demonstrate the idea.


> > +
> > +
> > +2) a user named "xen-qemuuser-domid$domid", 
> > +Where $domid is the domid of the domain being created.
> > +This requires the reservation of 65536 uids from xen-qemuuser-domid0
> 
> Is xen-qemuuser-domid0 actually useful?

All right, it can be 1-65535 inclusive.


> > +to xen-qemuuser-domid65535. To use this mechanism, you might want to
> > +create a large number of users at installation time. For example:
> > +
> > +for i in '' $(seq 0 65335)
> 
> This creates a user with no $i on it too, which I think is a left over
> from the previous scheme and no longer useful.
 
You are right. I'll turn it into the more bash-like:

for ((i=1; i<65336; i++))
do


> > +do
> > +    adduser --system xen-qemuuser-domid$i
> > +done
> > +
> > +
> > +3) a user named "xen-qemuuser-shared"
> > +As a fall back if both 1) and 2) fail, libxl will use a single user for
> > +all QEMU instances. The user is named xen-qemuuser-shared. This is
> > +less secure but still better than running QEMU as root. Using this is as
> > +simple as creating just one more user on your host:
> > +
> > +adduser --system xen-qemuuser-shared
> > +
> > +
> > +4) root
> > +As a last resort, libxl will start QEMU as root.
> > diff --git a/tools/libxl/libxl_dm.c b/tools/libxl/libxl_dm.c
> > index 0c6408d..79a9a22 100644
> > --- a/tools/libxl/libxl_dm.c
> > +++ b/tools/libxl/libxl_dm.c
> > @@ -19,6 +19,8 @@
> >  
> >  #include "libxl_internal.h"
> >  #include <xen/hvm/e820.h>
> > +#include <sys/types.h>
> > +#include <pwd.h>
> >  
> >  static const char *libxl_tapif_script(libxl__gc *gc)
> >  {
> > @@ -418,6 +420,32 @@ static char *dm_spice_options(libxl__gc *gc,
> >      return opt;
> >  }
> >  
> > +/* return 1 if the user was found, 0 if it was not, -1 on error */
> > +static int libxl__dm_runas_helper(libxl__gc *gc, char *username)
> > +{
> > +    struct passwd pwd, *user = NULL;
> > +    char *buf = NULL;
> > +    long buf_size;
> > +
> > +    buf_size = sysconf(_SC_GETPW_R_SIZE_MAX);
> > +    if (buf_size < 0) {
> > +        LOGE(ERROR, "sysconf(_SC_GETPW_R_SIZE_MAX) returned error %ld", 
> > buf_size);
> 
> This line is slightly too long. Wrapping buf_size would suffice.

OK


> > +        return -1;
> > +    }
> > +
> > +retry:
> > +    buf = libxl__realloc(gc, buf, buf_size);
> > +    errno = 0;
> > +    getpwnam_r(username, &pwd, buf, buf_size, &user);
> > +    if (user != NULL)
> > +        return 1;
> > +    if (errno == ERANGE) {
> > +        buf_size += 128;
> > +        goto retry;
> > +    }
> > +    return 0;
> > +}
> > +
> >  static char ** libxl__build_device_model_args_new(libxl__gc *gc,
> >                                          const char *dm, int guest_domid,
> >                                          const libxl_domain_config 
> > *guest_config,
> > @@ -439,6 +467,7 @@ static char ** 
> > libxl__build_device_model_args_new(libxl__gc *gc,
> >      int i, connection, devid;
> >      uint64_t ram_size;
> >      const char *path, *chardev;
> > +    char *user;
> >  
> >      dm_args = flexarray_make(gc, 16, 1);
> >  
> > @@ -878,6 +907,31 @@ static char ** 
> > libxl__build_device_model_args_new(libxl__gc *gc,
> >          default:
> >              break;
> >          }
> > +
> > +        user = libxl__sprintf(gc, "%s-%s", LIBXL_QEMU_USER_PREFIX, 
> > c_info->name);
> > +        if (libxl__dm_runas_helper(gc, user) > 0)
> > +            goto end_search;
> > +
> > +        user = libxl__sprintf(gc, "%s%d", LIBXL_QEMU_USER_BASE, 
> > guest_domid);
> > +        if (libxl__dm_runas_helper(gc, user) > 0)
> > +            goto end_search;
> > +
> > +        user = LIBXL_QEMU_USER_SHARED;
> > +        if (libxl__dm_runas_helper(gc, user) > 0) {
> > +            LOG(WARN, "Could not find user %s-%s or user %s (+domid %d), 
> > falling back to %s",
> 
> This message ("+domid %d)" seems to refer to the old way of doing
> things.

OK


> > +                    LIBXL_QEMU_USER_PREFIX, c_info->name, 
> > LIBXL_QEMU_USER_BASE,
> > +                    guest_domid, LIBXL_QEMU_USER_SHARED);
> > +            goto end_search;
> > +        }
> > +
> > +        user = NULL;
> > +        LOG(WARN, "Could not find user %s, starting QEMU as root", 
> > LIBXL_QEMU_USER_SHARED);
> > +
> > +end_search:
> > +        if (user) {
> > +            flexarray_append(dm_args, "-runas");
> > +            flexarray_append(dm_args, user);
> > +        }
> >      }
> >      flexarray_append(dm_args, NULL);
> >      return (char **) flexarray_contents(dm_args);
> > diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
> > index 8eb38aa..7d0af40 100644
> > --- a/tools/libxl/libxl_internal.h
> > +++ b/tools/libxl/libxl_internal.h
> > @@ -3692,6 +3692,10 @@ static inline void 
> > libxl__update_config_vtpm(libxl__gc *gc,
> >   */
> >  void libxl__bitmap_copy_best_effort(libxl__gc *gc, libxl_bitmap *dptr,
> >                                      const libxl_bitmap *sptr);
> > +
> > +#define LIBXL_QEMU_USER_PREFIX "xen-qemuuser"
> > +#define LIBXL_QEMU_USER_BASE   LIBXL_QEMU_USER_PREFIX"-domid"
> > +#define LIBXL_QEMU_USER_SHARED LIBXL_QEMU_USER_PREFIX"-shared"
> >  #endif
> >  
> >  /*
> 
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.