On 02/07/2013 02:37 PM, Laine Stump wrote: > Normally when a process' uid is changed to non-0, all the capabilities > bits are cleared, even those explicitly set with calls to > capng_update()/capng_apply() made immediately before setuid. And > *after* the process' uid has been changed, it no longer has the > necessary privileges to add capabilities back to the process. > > In order to set a non-0 uid while still maintaining any capabilities > bits, it is necessary to either call capng_change_id() (which > unfortunately doesn't not currently call initgroups to setup auxiliary s/doesn't not/doesn't/ > group membership), or to perform the small amount of calisthenics > contained in the new utility function virSetUIDGIDWithCaps(). > > > Note that, due to the way that effective capabilities are computed (at > time of execve) for a process that has uid != 0, the *file* > capabilities of the binary being executed must also have the desired > capabilities bit(s) set (see "man 7 capabilities"). This can be done > with the "filecap" command > (e.g. "filecap /usr/bin/qemu-kvm sys_rawio"). Sheesh - does that mean that we have to fix up qemu packaging for Fedora to include that capability by default? > > +#if WITH_CAPNG > +/* Set the real and effective uid and gid to the given values, while > + * maintaining the capabilities indicated by bits in @capBits. return > + * 0 on success, -1 on failure (the original system error remains in > + * errno). > + */ > +int > +virSetUIDGIDWithCaps(uid_t uid, gid_t gid, unsigned long long capBits) > +{ > + int ii, capng_ret, ret = -1; > + bool need_setgid = false, need_setuid = false; > + bool need_prctl = false, need_setpcap = false; > + > + /* First drop all caps except those in capBits + the extra ones we > + * need to change uid/gid and change the capabilities bounding > + * set. > + */ > + > + capng_clear(CAPNG_SELECT_BOTH); > + > + for (ii = 0; ii <= CAP_LAST_CAP; ii++) { > + if (capBits & (1ULL << ii)) { > + capng_update(CAPNG_ADD, > + CAPNG_EFFECTIVE|CAPNG_INHERITABLE| > + CAPNG_PERMITTED|CAPNG_BOUNDING_SET, > + ii); > + } > + } > + > + if (gid != -1 && gid > 0 && !capng_have_capability(CAPNG_EFFECTIVE, CAP_SETGID)) { Another site that needs casting (gid != (gid_t) -1); and do we really want to short-circuit the gid>0 case? > + need_setgid = true; > + capng_update(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, CAP_SETGID); > + } > + if (uid != -1 && uid > 0 && !capng_have_capability(CAPNG_EFFECTIVE, CAP_SETUID)) { > + need_setuid = true; > + capng_update(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, CAP_SETUID); > + } > +# ifdef PR_CAPBSET_DROP > + // If newer kernel, we need also need setpcap to change the bounding set Prefer /**/ comment style, please. > + if ((capBits || need_setgid || need_setuid) && > + !capng_have_capability(CAPNG_EFFECTIVE, CAP_SETPCAP)) { > + need_setpcap = true; > + } > + if (need_setpcap) > + capng_update(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, CAP_SETPCAP); Odd spacing. > +# endif > + > + need_prctl = capBits || need_setgid || need_setuid || need_setpcap; > + > + // Tell system we want to keep caps across uid change More comment style. > + if (need_prctl && prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) { > + virReportSystemError(errno, "%s", > + _("prctl failed to set KEEPCAPS")); > + goto cleanup; > + } > + > + // Change to the temp capabilities And again. > + if ((capng_ret = capng_apply(CAPNG_SELECT_BOTH)) < 0) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("cannot apply process capabilities %d"), capng_ret); > + goto cleanup; > + } > + > + /* Set UID/GID */ > + if (virSetUIDGID(uid, gid) < 0) > + goto cleanup; > + > + // Tell it we are done keeping capabilities and again > +} > + > +#else > +/* > + * On platforms without libcapng, the capabilities setting is treated > + * as a NOP. > + */ > + > +int > +virSetUIDGIDWithCaps(uid_t uid, gid_t gid, unsigned long long capBits) Need ATTRIBUTE_UNUSED on capBits. > +{ > + return virSetUIDGID(uid, gid); > +} > +#endif > + > > #if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R > /* search /proc/mounts for mount point of *type; return pointer to > diff --git a/src/util/virutil.h b/src/util/virutil.h > index 4201aa1..2dc3403 100644 > --- a/src/util/virutil.h > +++ b/src/util/virutil.h > @@ -54,6 +54,7 @@ int virPipeReadUntilEOF(int outfd, int errfd, > char **outbuf, char **errbuf); > > int virSetUIDGID(uid_t uid, gid_t gid); > +int virSetUIDGIDWithCaps(uid_t uid, gid_t gid, unsigned long long capBits); > > int virFileReadLimFD(int fd, int maxlen, char **buf) ATTRIBUTE_RETURN_CHECK; > > -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
Attachment:
signature.asc
Description: OpenPGP digital signature
-- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list