chiark / gitweb /
bus: fix capabilities on big-endian
authorDavid Herrmann <dh.herrmann@gmail.com>
Tue, 30 Dec 2014 08:09:41 +0000 (09:09 +0100)
committerDavid Herrmann <dh.herrmann@gmail.com>
Tue, 30 Dec 2014 08:09:41 +0000 (09:09 +0100)
The kernel provides capabilities as a u32 array, sd-bus uses an u8 array.
This works fine on little-endian as both are encoded the same way.
However, this fails on big-endian if we do not perform sufficient
byte-swapping on each u32 entry.

This patch makes sd-bus use u32, too. We avoid changing any kernel
provided data so we can keep pointing into kdbus pool buffers which
contain u32 arrays.

src/libsystemd/sd-bus/bus-creds.c
src/libsystemd/sd-bus/bus-creds.h
src/libsystemd/sd-bus/bus-kernel.c

index 55d6fb6..54e76ab 100644 (file)
@@ -20,6 +20,7 @@
 ***/
 
 #include <stdlib.h>
+#include <linux/capability.h>
 
 #include "util.h"
 #include "capability.h"
@@ -592,11 +593,11 @@ static int has_cap(sd_bus_creds *c, unsigned offset, int capability) {
         assert(capability >= 0);
         assert(c->capability);
 
-        sz = DIV_ROUND_UP(cap_last_cap(), 32U) * 4;
+        sz = DIV_ROUND_UP(cap_last_cap(), 32U);
         if ((unsigned)capability > cap_last_cap())
                 return 0;
 
-        return !!(c->capability[offset * sz + (capability / 8)] & (1 << (capability % 8)));
+        return !!(c->capability[offset * sz + CAP_TO_INDEX(capability)] & CAP_TO_MASK(capability));
 }
 
 _public_ int sd_bus_creds_has_effective_cap(sd_bus_creds *c, int capability) {
@@ -641,38 +642,42 @@ _public_ int sd_bus_creds_has_bounding_cap(sd_bus_creds *c, int capability) {
 
 static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
         size_t sz, max;
-        unsigned i;
+        unsigned i, j;
 
         assert(c);
         assert(p);
 
-        max = DIV_ROUND_UP(cap_last_cap(), 32U) * 4;
+        max = DIV_ROUND_UP(cap_last_cap(), 32U);
         p += strspn(p, WHITESPACE);
 
         sz = strlen(p);
-        if (sz % 2 != 0)
+        if (sz % 8 != 0)
                 return -EINVAL;
 
-        sz /= 2;
+        sz /= 8;
         if (sz > max)
                 return -EINVAL;
 
         if (!c->capability) {
-                c->capability = new0(uint8_t, max * 4);
+                c->capability = new0(uint32_t, max * 4);
                 if (!c->capability)
                         return -ENOMEM;
         }
 
         for (i = 0; i < sz; i ++) {
-                int x, y;
+                uint32_t v = 0;
 
-                x = unhexchar(p[i*2]);
-                y = unhexchar(p[i*2+1]);
+                for (j = 0; j < 8; ++j) {
+                        int t;
 
-                if (x < 0 || y < 0)
-                        return -EINVAL;
+                        t = unhexchar(*p++);
+                        if (t < 0)
+                                return -EINVAL;
 
-                c->capability[offset * max + (sz - i - 1)] = (uint8_t) x << 4 | (uint8_t) y;
+                        v = (v << 4) | t;
+                }
+
+                c->capability[offset * max + (sz - i - 1)] = v;
         }
 
         return 0;
index 2480a4a..3b337ef 100644 (file)
@@ -60,7 +60,7 @@ struct sd_bus_creds {
         char *user_unit;
         char *slice;
 
-        uint8_t *capability;
+        uint32_t *capability;
 
         uint32_t audit_session_id;
         uid_t audit_login_uid;
index eeb4a51..6ee3f92 100644 (file)
@@ -680,7 +680,7 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
                                 goto fail;
                         }
 
-                        m->creds.capability = (uint8_t *) d->caps.caps;
+                        m->creds.capability = d->caps.caps;
                         m->creds.mask |= (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS) & bus->creds_mask;
                         break;