[libvirt] [PATCH 7/8] Honour current sensitivity and category ranges in SELinux label generation

Eric Blake eblake at redhat.com
Fri Aug 10 21:20:58 UTC 2012


On 08/10/2012 07:48 AM, Daniel P. Berrange wrote:
> From: "Daniel P. Berrange" <berrange at redhat.com>
> 
> Currently the dynamic label generation code will create labels
> with a sensitivity of s0, and a category pair in the range
> 0-1023. This is fine when running a standard MCS policy because
> libvirtd will run with a label
> 
>   system_u:system_r:virtd_t:s0-s0:c0.c1023
> 
> With custom policies though, it is possible for libvirtd to have
> a different sensitivity, or category range. For example
> 
>   system_u:system_r:virtd_t:s2-s3:c512.c1023
> 
> In this case we must assign the VM a sensitivity matching the
> current lower sensitivity value, and categories in the range
> 512-1023
> 
> Signed-off-by: Daniel P. Berrange <berrange at redhat.com>

> +++ b/src/security/security_selinux.c
> @@ -106,13 +106,90 @@ virSecuritySELinuxMCSFind(virSecurityManagerPtr mgr)
>      int c1 = 0;
>      int c2 = 0;
>      char *mcs = NULL;
> +    security_context_t curseccontext = NULL;

More of that fun naming.  Underscoresreallydomakeiteasiertoread.

> +    context_t curcontext = NULL;
> +    char *sens, *cat, *tmp;
> +    int catMin, catMax, catRange;

OK, so camel case would also make things easier to read.  I don't know
if we have a coding guideline which says which to use, but consistency
argues for the same type of separation for all local variables in a
single function.

> +
> +    if (getcon(&curseccontext) < 0) {
> +        virReportSystemError(errno, "%s",
> +                             _("Unable to get current process SELinux context"));
> +        goto cleanup;
> +    }
> +    if (!(curcontext = context_new(curseccontext))) {
> +        virReportSystemError(errno,
> +                             _("Unable to parse current SELinux context '%s'"),
> +                             curseccontext);
> +        goto cleanup;
> +    }
> +
> +    if (!(sens = strdup(context_range_get(curcontext)))) {

Just to make sure I'm following here, I'll assume two different strings
for sens at this point; one from your commit message (s2-s3:c512.c1023)
and one from a degenerate s0:c0 (as the previous patch showed that
libvirt will create a single context instead of a range if two random
numbers match).

> +        virReportOOMError();
> +        goto cleanup;
> +    }
> +
> +    /* Find and blank out the category part */
> +    if (!(tmp = strchr(sens, ':'))) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("Cannot parse sensitivity level in %s"),
> +                       sens);
> +        goto cleanup;
> +    }
> +    *tmp = '\0';
> +    cat = tmp + 1;

so here, with my examples, we would sens with s2-s3 (or s0), and cat
with c512.c1023 (or c0)

> +    /* Find and blank out the sensitivity upper bound */
> +    if ((tmp = strchr(sens, '-')))
> +        *tmp = '\0';

and here, sens is now shortened to s2 (or still s0)

> +
> +    /* sens now just contains the sensitivity lower bound */
> +    tmp = cat;

The spacing for this comment was awkward; it made me look for sens in
the next block of code, even though it is an assertion about the results
after the prior block of code.

> +    if (tmp[0] != 'c') {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("Cannot parse category in %s"),
> +                       cat);
> +        goto cleanup;
> +    }
> +    tmp++;
> +    if (virStrToLong_i(tmp, &tmp, 10, &catMin) < 0) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("Cannot parse category in %s"),
> +                       cat);
> +        goto cleanup;
> +    }

here, we've parsed out either 512 from c512.c1023, or 0 from c0

> +    if (tmp[0] != '.') {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("Cannot parse category in %s"),
> +                       cat);
> +        goto cleanup;

and here, we fall flat on our face if we were in the degenerate case of
a single category.  Oops.  You need to start:

if (!tmp[0]) {
    catMax = catMin;
} else if (tmp[0] != '.') {

> +    }
> +    tmp++;
> +    if (tmp[0] != 'c') {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("Cannot parse category in %s"),
> +                       cat);
> +        goto cleanup;
> +    }
> +    tmp++;
> +    if (virStrToLong_i(tmp, &tmp, 10, &catMax) < 0) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("Cannot parse category in %s"),
> +                       cat);
> +        goto cleanup;
> +    }

and this parsed out 1023 on the c512.c1023 example.

> +
> +    /* max is inclusive, hence the + 1 */
> +    catRange = (catMax - catMin) + 1;
> +
> +    VIR_DEBUG("Using sensitivity level '%s' cat min %d max %d range %d",
> +              sens, catMin, catMax, catRange);
>  
>      for (;;) {
> -        c1 = virRandomBits(10);
> -        c2 = virRandomBits(10);
> +        c1 = virRandom(catRange);
> +        c2 = virRandom(catRange);
> +        VIR_DEBUG("Try cat %s:c%d,c%d", sens, c1, c2);

This debug message would make more sense as c1+catMin, c2+catMin.

>  
>          if (c1 == c2) {
> -            if (virAsprintf(&mcs, "s0:c%d", c1) < 0) {
> +            if (virAsprintf(&mcs, "%s:c%d", sens, catMin + c1) < 0) {

If you fix the parsing of the degenerate case, then for the c0 input
case, you would always reach here, with catMin == 0 and c1 == 0 (since
virRandom(1) == 0 - actually, you need to make sure that we don't
trigger undefined behavior when calling virRandom(1), with whatever
algorithm we finally end up with for that function; but I do agree that
virRandom(0) should trigger an assertion failure.)

>                  virReportOOMError();
>                  return NULL;
>              }
> @@ -122,7 +199,7 @@ virSecuritySELinuxMCSFind(virSecurityManagerPtr mgr)
>                  c2 ^= c1;
>                  c1 ^= c2;
>              }
> -            if (virAsprintf(&mcs, "s0:c%d,c%d", c1, c2) < 0) {
> +            if (virAsprintf(&mcs, "%s:c%d,c%d", sens, catMin + c1, catMin + c2) < 0) {

and most of the time for the c512.c1023 case, you would get here with
two random numbers more or less evenly distributed.

>                  virReportOOMError();
>                  return NULL;
>              }
> @@ -136,6 +213,9 @@ virSecuritySELinuxMCSFind(virSecurityManagerPtr mgr)
>  
>  cleanup:
>      VIR_DEBUG("Found context '%s'", NULLSTR(mcs));
> +    VIR_FREE(sens);
> +    freecon(curseccontext);
> +    context_free(curcontext);
>      return mcs;
>  }
>  
> 

Looks mostly sane.  ACK if you clean up the degenerate context case.

-- 
Eric Blake   eblake at redhat.com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 620 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20120810/d225176e/attachment-0001.sig>


More information about the libvir-list mailing list