From 7d9fcc2bf6869993e5f38d5eb183fb59e8a52816 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 30 Dec 2014 09:09:41 +0100 Subject: [PATCH] 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. --- src/libsystemd/sd-bus/bus-creds.c | 31 +++++++++++++++++------------- src/libsystemd/sd-bus/bus-creds.h | 2 +- src/libsystemd/sd-bus/bus-kernel.c | 2 +- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/libsystemd/sd-bus/bus-creds.c b/src/libsystemd/sd-bus/bus-creds.c index 55d6fb6b4..54e76ab6c 100644 --- a/src/libsystemd/sd-bus/bus-creds.c +++ b/src/libsystemd/sd-bus/bus-creds.c @@ -20,6 +20,7 @@ ***/ #include +#include #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 2480a4a0b..3b337efa3 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 eeb4a518d..6ee3f9283 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; -- 2.30.2