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

Re: [Xen-devel] [PATCH 8/9] libxl: Kill QEMU by uid when possible



George Dunlap writes ("[PATCH 8/9] libxl: Kill QEMU by uid when possible"):
> The privcmd fd that a dm_restrict'ed QEMU has gives it permission to
> one specific domain ID.  This domain ID will probably eventually be
> used again.  It is therefore necessary to make absolutely sure that a
> rogue QEMU process cannot hang around after its domain has exited.

Thanks.  This looks roughly right but I have some coding style
quibbles, and I am not convinced the error handling is right.
                                  
> @@ -2382,6 +2389,15 @@ void libxl__spawn_local_dm(libxl__egc *egc, 
> libxl__dm_spawn_state *dmss)
>  
>      const char *dom_path = libxl__xs_get_dompath(gc, domid);
>  
> +    /* 
> +     * If we're stating the dm with a non-root UID, save the UID so

Typo for `starting'.

> +     * that we can reliably kill it and any subprocesses
> +     */
...
> +static void kill_device_model_uid_cb(libxl__egc *egc,
> +                                     libxl__ev_child *destroyer,
> +                                     pid_t pid, int status);
> +
>  void libxl__destroy_device_model(libxl__egc *egc,
>                                   libxl__destroy_devicemodel_state *ddms)
>  {
> @@ -2658,15 +2678,103 @@ void libxl__destroy_device_model(libxl__egc *egc,
>      int rc;
>      int domid = ddms->domid;
>      char *path = DEVICE_MODEL_XS_PATH(gc, LIBXL_TOOLSTACK_DOMID, domid, "");
> +    const char * dm_uid_str;
> +    uid_t dm_uid;
> +    int reaper_pid;
> +    int ret;
>      
>      if (!xs_rm(CTX->xsh, XBT_NULL, path))
>          LOGD(ERROR, domid, "xs_rm failed for %s", path);
>      
> -    /* We should try to destroy the device model anyway. */
> -    rc = kill_device_model(gc,
> -              GCSPRINTF("/local/domain/%d/image/device-model-pid", domid));
> +    /* 
> +     * We should try to destroy the device model anyway.  Check to see
> +     * if we can kill by UID
> +     */
> +    ret = libxl__xs_read_checked(gc, XBT_NULL,
> +                                
> GCSPRINTF("/local/domain/%d/image/device-model-uid",
> +                                           domid),
> +                                 &dm_uid_str);

I know this function is bad in its use of `rc' for syscall return but
please don't make it worse by introducing `ret' for what should be
`rc'.  Would you mind adding a pre-patch to change `rc' to `r' and
then you can use `rc' ?

> +    if (ret || !dm_uid_str) {

Shouldn't we fail if libxl__xs_read_checked fails ?
Otherwise we risk leaving fragments of domain behind even if we fail.
(Possibly we should carry on, but accumulate errors in rc.)

> +        /* No uid in xenstore; just kill the pid we have */
> +        LOGD(DEBUG, domid, "Didn't find dm UID; destroying by pid");
> +        
> +        rc = kill_device_model(gc,
> +                               
> GCSPRINTF("/local/domain/%d/image/device-model-pid", domid));
> +    
> +        libxl__qmp_cleanup(gc, domid);
> +
> +        ddms->callback(egc, ddms, rc);
> +        return;

Can you please break out this little exit code fragment

  +        libxl__qmp_cleanup(gc, domid);
  +        ddms->callback(egc, ddms, rc);

into a sub-function ?  It occurs twice and it is easier to reason
about things if the operation has a single exit path.

> +    /* QEMU has its own uid; kill all processes with that UID */
> +    LOGD(DEBUG, domid, "Found DM uid %s, destroying by uid", dm_uid_str);
> +    
> +    dm_uid = atoi(dm_uid_str);

I am tempted to suggest a more robust use of strtoul here but since
this came from our own xenstore node, fine.

> +    reaper_pid = libxl__ev_child_fork(gc, &ddms->destroyer,
> +                                      kill_device_model_uid_cb);
> +    if (reaper_pid < 0)
> +        ddms->callback(egc, ddms, ERROR_FAIL);
> +    }
> +

And, voila!  Didn't you mean to call libxl__qmp_cleanup ?  You're
missing the exit path.  And maybe the call to it should be an `out'
block in this function.

Also, amazingly, you don't return or anything here.  This is only not
a bug because the rest is all the child process.

> +    if (!reaper_pid) { /* child */
> +        const char * call;
> +
> +        /* 
> +         * FIXME: the second uid needs to be distinct to avoid being
> +         * killed by a potential rogue process
> +         */

This is a bit of a funny way of introducing this but fine.

> +        ret = setresuid(dm_uid, dm_uid, 0);
> +        if (ret) {
> +            call = "setresuid";
> +            goto badchild;
> +        }
> +
> +        /* And kill everyone but me */
> +        ret = kill(-1, 9);
> +        if (ret) {
> +            call = "kill";
> +            goto badchild;
> +        }
> +        _exit(0);
> +        
> +    badchild:
> +        if (errno > 0  && errno < 126) {
> +            _exit(errno);
> +        } else {
> +            LOGED(ERROR, domid,
> +                  "Call %s failed (with difficult errno value %d)",
> +                  call, errno);
> +            _exit(-1);
> +        }
> +    }

I don't much like these gotos either.  Maybe a subfunction is called
for.

Furthermore, once again please see CODING_STYLE re conventional
variable names `r' and `rc'·

> +out:
> +    libxl__qmp_cleanup(gc, ddms->domid);

>      ddms->callback(egc, ddms, rc);

Here's that finish fragment again.

> index 899a86e84b..59eac0662a 100644
> --- a/tools/libxl/libxl_internal.h
> +++ b/tools/libxl/libxl_internal.h
> @@ -1135,7 +1135,7 @@ typedef struct {
>      const char * shim_cmdline;
>      const char * pv_cmdline;
>  
> -    char * dm_runas;
> +    char * dm_runas,  *dm_uid;

It would be nice to drop the spurious space before dm_runas while you
are here, and then presumably the double space before *dm_uid would
not be needed.

Thanks,
Ian.

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

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