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

[Xen-changelog] [xen-4.1-testing] tools/ocaml: oxenstored: Be more paranoid about ring reading

  • To: xen-changelog@xxxxxxxxxxxxxxxxxxx
  • From: Xen patchbot-4.1-testing <patchbot@xxxxxxx>
  • Date: Fri, 08 Feb 2013 18:55:10 +0000
  • Delivery-date: Fri, 08 Feb 2013 18:55:22 +0000
  • List-id: "Change log for Mercurial \(receive only\)" <xen-changelog.lists.xen.org>

# HG changeset patch
# User Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
# Date 1360247189 0
# Node ID 47c7b85319235bc52518d025f22931bd20686ce3
# Parent  e5ed73d172eb8941bee2e632c5a243c3fe8c0d46
tools/ocaml: oxenstored: Be more paranoid about ring reading

oxenstored makes use of the OCaml Xenbus bindings, in which the
function xs_ring_read in tools/ocaml/libs/xb/xs_ring_stubs.c is used
to read from the shared memory Xenstore ring.

This function does not correctly handle all possible (prod, cons)
states when MASK_XENSTORE_IDX(prod) > MASK_XENSTORE_IDX(cons).

The root cause is the use of the unmasked values of prod and cons to
calculate to_read.  If prod is set to an out-of-range value, the ring
peer can cause to_read to be too large or even negative.  This allows
the ring peer to force oxenstored to read and write out of range for
the buffers leading to a crash or possibly to privilege escalation.

Correct this by masking the values of cons and prod at the start, so
we only deal with masked values.  This makes the logic simpler, as
semantically inappropriate values of the upper bits of the ring
pointers are simply ignored.

The same vulnerability does not exist in the ring writer because the
only use made of the unmasked value is the check which prevents the
prod pointer overtaking the cons pointer.  A ring peer which defeats
this check will suffer only lost data.

However, additionally, precautions need to be taken to ensure that
req_cons and req_prod are only read once in each function.  Without
the use of volatile or some asm construct, the compiler can "prove"
that req_cons and req_prod do not change unexpectedly and is permitted
to "amplify" the read of (say) req_cons into two reads at different
times, giving two different values for use as cons, and then use the
two sources of cons interchangeably.  (The use of xen_mb() does not
forbid this.)

Therefore do the reads of req_cons and req_prod through a volatile
pointer in both xs_ring_read and xs_ring_write.

This is currently believed to be a theoretical vulnerability as we are
not aware of any compilers which amplify reads in this way.

This is a security issue, part of XSA-38 / CVE-2013-0215.

Signed-off-by: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
Tested-by: Matthew Daley <mattjd@xxxxxxxxx>
Committed-by: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>

xen-unstable changeset: 26521:2c0fd406f02c
Backport-requested-by: security@xxxxxxx
Committed-by: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>

diff -r e5ed73d172eb -r 47c7b8531923 tools/ocaml/libs/xb/xs_ring_stubs.c
--- a/tools/ocaml/libs/xb/xs_ring_stubs.c       Tue Feb 05 15:36:34 2013 +0100
+++ b/tools/ocaml/libs/xb/xs_ring_stubs.c       Thu Feb 07 14:26:29 2013 +0000
@@ -43,21 +43,23 @@ static int xs_ring_read(struct mmap_inte
                              char *buffer, int len)
        struct xenstore_domain_interface *intf = interface->addr;
-       XENSTORE_RING_IDX cons, prod;
+       XENSTORE_RING_IDX cons, prod; /* offsets only */
        int to_read;
-       cons = intf->req_cons;
-       prod = intf->req_prod;
+       cons = *(volatile uint32*)&intf->req_cons;
+       prod = *(volatile uint32*)&intf->req_prod;
+       cons = MASK_XENSTORE_IDX(cons);
+       prod = MASK_XENSTORE_IDX(prod);
        if (prod == cons)
                return 0;
-       if (MASK_XENSTORE_IDX(prod) > MASK_XENSTORE_IDX(cons)) 
+       if (prod > cons)
                to_read = prod - cons;
-               to_read = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons);
+               to_read = XENSTORE_RING_SIZE - cons;
        if (to_read < len)
                len = to_read;
-       memcpy(buffer, intf->req + MASK_XENSTORE_IDX(cons), len);
+       memcpy(buffer, intf->req + cons, len);
        intf->req_cons += len;
        return len;
@@ -70,8 +72,8 @@ static int xs_ring_write(struct mmap_int
        XENSTORE_RING_IDX cons, prod;
        int can_write;
-       cons = intf->rsp_cons;
-       prod = intf->rsp_prod;
+       cons = *(volatile uint32*)&intf->rsp_cons;
+       prod = *(volatile uint32*)&intf->rsp_prod;
        if ( (prod - cons) >= XENSTORE_RING_SIZE )
                return 0;

Xen-changelog mailing list



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