[systemd-commits] 2 commits - src/libsystemd

David Herrmann dvdhrm at kemper.freedesktop.org
Tue Dec 30 00:11:36 PST 2014


 src/libsystemd/sd-bus/bus-control.c |    8 ++++--
 src/libsystemd/sd-bus/bus-creds.c   |   44 +++++++++++++++++++++---------------
 src/libsystemd/sd-bus/bus-creds.h   |    3 --
 src/libsystemd/sd-bus/bus-kernel.c  |   10 ++++++--
 4 files changed, 41 insertions(+), 24 deletions(-)

New commits:
commit 7d9fcc2bf6869993e5f38d5eb183fb59e8a52816
Author: David Herrmann <dh.herrmann at gmail.com>
Date:   Tue Dec 30 09:09:41 2014 +0100

    bus: fix capabilities on big-endian
    
    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.

diff --git a/src/libsystemd/sd-bus/bus-creds.c b/src/libsystemd/sd-bus/bus-creds.c
index 55d6fb6..54e76ab 100644
--- a/src/libsystemd/sd-bus/bus-creds.c
+++ b/src/libsystemd/sd-bus/bus-creds.c
@@ -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;
diff --git a/src/libsystemd/sd-bus/bus-creds.h b/src/libsystemd/sd-bus/bus-creds.h
index 2480a4a..3b337ef 100644
--- a/src/libsystemd/sd-bus/bus-creds.h
+++ b/src/libsystemd/sd-bus/bus-creds.h
@@ -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;
diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c
index eeb4a51..6ee3f92 100644
--- a/src/libsystemd/sd-bus/bus-kernel.c
+++ b/src/libsystemd/sd-bus/bus-kernel.c
@@ -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;
 

commit 34a5d5e52661212c7a145cbab45e70a6df7ba284
Author: David Herrmann <dh.herrmann at gmail.com>
Date:   Tue Dec 30 08:42:53 2014 +0100

    bus: drop creds->capability_size
    
    The number of available caps can be read from
    /proc/sys/kernel/cap_last_cap during runtime. Our helper cap_last_cap()
    does that, so there's no reason to remember the size of any capability
    cache. We can just pre-allocate arrays with a suitable size for all
    available caps and reject any higher caps.
    
    The kernel capability API uses u32 as base so make sure we do the same.
    Note that this is specified by POSIX, so it's unlikely to change.

diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c
index e86546c..b2394db 100644
--- a/src/libsystemd/sd-bus/bus-control.c
+++ b/src/libsystemd/sd-bus/bus-control.c
@@ -33,6 +33,7 @@
 #include "bus-control.h"
 #include "bus-bloom.h"
 #include "bus-util.h"
+#include "capability.h"
 #include "cgroup-util.h"
 
 _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
@@ -520,8 +521,11 @@ static int bus_populate_creds_from_items(
                              SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask;
 
                         if (m) {
-                                c->capability_size = item->size - offsetof(struct kdbus_item, caps.caps);
-                                c->capability = memdup(item->caps.caps, c->capability_size);
+                                if (item->caps.last_cap != cap_last_cap() ||
+                                    item->size - offsetof(struct kdbus_item, caps.caps) < DIV_ROUND_UP(item->caps.last_cap, 32U) * 4 * 4)
+                                        return -EBADMSG;
+
+                                c->capability = memdup(item->caps.caps, item->size - offsetof(struct kdbus_item, caps.caps));
                                 if (!c->capability)
                                         return -ENOMEM;
 
diff --git a/src/libsystemd/sd-bus/bus-creds.c b/src/libsystemd/sd-bus/bus-creds.c
index 9978ddf..55d6fb6 100644
--- a/src/libsystemd/sd-bus/bus-creds.c
+++ b/src/libsystemd/sd-bus/bus-creds.c
@@ -22,6 +22,7 @@
 #include <stdlib.h>
 
 #include "util.h"
+#include "capability.h"
 #include "cgroup-util.h"
 #include "fileio.h"
 #include "audit.h"
@@ -588,10 +589,11 @@ static int has_cap(sd_bus_creds *c, unsigned offset, int capability) {
         size_t sz;
 
         assert(c);
+        assert(capability >= 0);
         assert(c->capability);
 
-        sz = c->capability_size / 4;
-        if ((size_t) capability >= sz*8)
+        sz = DIV_ROUND_UP(cap_last_cap(), 32U) * 4;
+        if ((unsigned)capability > cap_last_cap())
                 return 0;
 
         return !!(c->capability[offset * sz + (capability / 8)] & (1 << (capability % 8)));
@@ -638,12 +640,13 @@ _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;
+        size_t sz, max;
         unsigned i;
 
         assert(c);
         assert(p);
 
+        max = DIV_ROUND_UP(cap_last_cap(), 32U) * 4;
         p += strspn(p, WHITESPACE);
 
         sz = strlen(p);
@@ -651,12 +654,13 @@ static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
                 return -EINVAL;
 
         sz /= 2;
+        if (sz > max)
+                return -EINVAL;
+
         if (!c->capability) {
-                c->capability = new0(uint8_t, sz * 4);
+                c->capability = new0(uint8_t, max * 4);
                 if (!c->capability)
                         return -ENOMEM;
-
-                c->capability_size = sz * 4;
         }
 
         for (i = 0; i < sz; i ++) {
@@ -668,7 +672,7 @@ static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
                 if (x < 0 || y < 0)
                         return -EINVAL;
 
-                c->capability[offset * sz + (sz - i - 1)] = (uint8_t) x << 4 | (uint8_t) y;
+                c->capability[offset * max + (sz - i - 1)] = (uint8_t) x << 4 | (uint8_t) y;
         }
 
         return 0;
@@ -1073,11 +1077,10 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret)
         }
 
         if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) {
-                n->capability = memdup(c->capability, c->capability_size);
+                n->capability = memdup(c->capability, DIV_ROUND_UP(cap_last_cap(), 32U) * 4 * 4);
                 if (!n->capability)
                         return -ENOMEM;
 
-                n->capability_size = c->capability_size;
                 n->mask |= c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS);
         }
 
diff --git a/src/libsystemd/sd-bus/bus-creds.h b/src/libsystemd/sd-bus/bus-creds.h
index 48453e2..2480a4a 100644
--- a/src/libsystemd/sd-bus/bus-creds.h
+++ b/src/libsystemd/sd-bus/bus-creds.h
@@ -61,7 +61,6 @@ struct sd_bus_creds {
         char *slice;
 
         uint8_t *capability;
-        size_t capability_size;
 
         uint32_t audit_session_id;
         uid_t audit_login_uid;
diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c
index d9252b2..eeb4a51 100644
--- a/src/libsystemd/sd-bus/bus-kernel.c
+++ b/src/libsystemd/sd-bus/bus-kernel.c
@@ -32,6 +32,7 @@
 #include "util.h"
 #include "strv.h"
 #include "memfd-util.h"
+#include "capability.h"
 #include "cgroup-util.h"
 #include "fileio.h"
 
@@ -673,8 +674,13 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
                         break;
 
                 case KDBUS_ITEM_CAPS:
+                        if (d->caps.last_cap != cap_last_cap() ||
+                            d->size - offsetof(struct kdbus_item, caps.caps) < DIV_ROUND_UP(d->caps.last_cap, 32U) * 4 * 4) {
+                                r = -EBADMSG;
+                                goto fail;
+                        }
+
                         m->creds.capability = (uint8_t *) d->caps.caps;
-                        m->creds.capability_size = d->size - offsetof(struct kdbus_item, 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;
 



More information about the systemd-commits mailing list