[systemd-commits] src/bus-proxyd

Daniel Mack zonque at kemper.freedesktop.org
Tue Nov 11 07:51:54 PST 2014


 src/bus-proxyd/bus-proxyd.c |  126 +++++++++++++++++++++++++++++++++++---------
 1 file changed, 103 insertions(+), 23 deletions(-)

New commits:
commit ed6d629a3487105e31415db9e175dd698ac20125
Author: Daniel Mack <daniel at zonque.org>
Date:   Thu Oct 23 13:06:38 2014 +0200

    bus-proxyd: explicitly address messages to unique and well-known name
    
    In order to check for matching policy entries at message transfers, we
    have to consider the following:
    
    * check the currently owned names of both the sending and the receiving
    peer. If the sending peer is connected via kdbus, the currently owned
    names are already attached to the message. If it was originated by the
    connection we're proxying for, we store the owned names in our own strv
    so we can check against them.
    
    * Walk the list of names to check which name would allow the message to
    pass, and explicitly use that name as destination of the message. If the
    destination is on kdbus, store both the connection's unique name and the
    chosen well-known-name in the message. That way, the kernel will make sure
    the supplied name is owned by the supplied unique name, at the time of
    sending, and return -EREMCHG otherwise.
    
    * Make the policy checks optional by retrieving the bus owner creds, and
    when the uid matches the current user's uid and is non-null, don't check
    the bus policy.

diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c
index 3fc341e..d6607ed 100644
--- a/src/bus-proxyd/bus-proxyd.c
+++ b/src/bus-proxyd/bus-proxyd.c
@@ -469,12 +469,18 @@ static int peer_is_privileged(sd_bus *bus, sd_bus_message *m) {
 
 static int process_policy(sd_bus *a, sd_bus *b, sd_bus_message *m, Policy *policy, const struct ucred *ucred) {
         int r;
+        char **name;
         char **names_strv;
+        bool granted = false;
+        Iterator i;
 
         assert(a);
         assert(b);
         assert(m);
 
+        if (!policy)
+                return 0;
+
         if (b->is_kernel) {
 
                 /* The message came from the kernel, and is sent to our legacy client. */
@@ -482,18 +488,68 @@ static int process_policy(sd_bus *a, sd_bus *b, sd_bus_message *m, Policy *polic
                 if (r < 0)
                         return r;
 
-/*
-                if (!policy_check_recv(policy, ucred, names_hash, m->header->type, m->path, m->interface, m->member))
-                        return -EPERM;
+                STRV_FOREACH(name, names_strv) {
+                        if (policy_check_send(policy, ucred, m->header->type, *name, m->path, m->interface, m->member)) {
+                                r = free_and_strdup(&m->destination_ptr, *name);
+                                if (r < 0)
+                                        break;
 
-                if (!policy_check_send(policy, ucred, names_strv, m->header->type, m->path, m->interface, m->member))
+                                granted = true;
+                                break;
+                        }
+                }
+
+                if (r < 0)
+                        return r;
+
+                if (!granted)
                         return -EPERM;
-*/
+
+                granted = false;
+
+                HASHMAP_FOREACH(name, names_hash, i) {
+                        if (policy_check_recv(policy, ucred, m->header->type, *name, m->path, m->interface, m->member))
+                                return 0;
+                }
+
+                return -EPERM;
         } else {
+                sd_bus_creds *bus_creds;
+
+                /* The message came from the legacy client, and is sent to kdbus. */
+                r = sd_bus_get_name_creds(a, m->destination, SD_BUS_CREDS_WELL_KNOWN_NAMES, &bus_creds);
+                if (r < 0)
+                        return r;
+
+                STRV_FOREACH(name, names_strv) {
+                        if (policy_check_send(policy, ucred, m->header->type, *name, m->path, m->interface, m->member)) {
+                                r = free_and_strdup(&m->destination_ptr, *name);
+                                if (r < 0)
+                                        break;
+
+                                r = bus_kernel_parse_unique_name(m->sender, &m->verify_destination_id);
+                                if (r < 0)
+                                        break;
+
+                                granted = true;
+                                break;
+                        }
+                }
 
+                if (r < 0)
+                        return r;
 
+                if (!granted)
+                        return -EPERM;
 
+                granted = false;
 
+                HASHMAP_FOREACH(name, names_hash, i) {
+                        if (policy_check_recv(policy, ucred, m->header->type, *name, m->path, m->interface, m->member))
+                                return 0;
+                }
+
+                return -EPERM;
         }
 
         return 0;
@@ -849,7 +905,7 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m, Policy *polic
                 if (r < 0)
                         return synthetic_reply_method_errno(m, r, NULL);
 
-                if (!policy_check_own(policy, ucred, name))
+                if (policy && !policy_check_own(policy, ucred, name))
                         return synthetic_reply_method_errno(m, -EPERM, NULL);
 
                 if (!service_name_is_valid(name))
@@ -1022,7 +1078,7 @@ static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, Policy *policy
                 return -EIO;
         }
 
-        if (!policy_check_hello(policy, ucred)) {
+        if (policy && !policy_check_hello(policy, ucred)) {
                 log_error("Policy denied HELLO");
                 return -EPERM;
         }
@@ -1133,6 +1189,7 @@ static int patch_sender(sd_bus *a, sd_bus_message *m) {
 
 int main(int argc, char *argv[]) {
 
+        _cleanup_bus_creds_unref_ sd_bus_creds *bus_creds = NULL;
         _cleanup_bus_close_unref_ sd_bus *a = NULL, *b = NULL;
         sd_id128_t server_id;
         int r, in_fd, out_fd;
@@ -1251,6 +1308,12 @@ int main(int argc, char *argv[]) {
                 goto finish;
         }
 
+        r = sd_bus_get_owner_creds(a, SD_BUS_CREDS_UID, &bus_creds);
+        if (r < 0) {
+                log_error("Failed to get bus creds: %s", strerror(-r));
+                goto finish;
+        }
+
         r = sd_bus_new(&b);
         if (r < 0) {
                 log_error("Failed to allocate bus: %s", strerror(-r));
@@ -1410,13 +1473,21 @@ int main(int argc, char *argv[]) {
                 }
 
                 if (m) {
+                        Policy *p = NULL;
+                        uid_t uid;
+
+                        assert_se(sd_bus_creds_get_uid(bus_creds, &uid) == 0);
+
+                        if (uid == 0 || uid != ucred.uid)
+                                p = &policy;
+
                         /* We officially got EOF, let's quit */
                         if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
                                 r = 0;
                                 goto finish;
                         }
 
-                        k = process_hello(a, b, m, &policy, &ucred, &got_hello);
+                        k = process_hello(a, b, m, p, &ucred, &got_hello);
                         if (k < 0) {
                                 r = k;
                                 log_error("Failed to process HELLO: %s", strerror(-r));
@@ -1426,7 +1497,7 @@ int main(int argc, char *argv[]) {
                         if (k > 0)
                                 r = k;
                         else {
-                                k = process_driver(a, b, m, &policy, &ucred);
+                                k = process_driver(a, b, m, p, &ucred);
                                 if (k < 0) {
                                         r = k;
                                         log_error("Failed to process driver calls: %s", strerror(-r));
@@ -1436,24 +1507,33 @@ int main(int argc, char *argv[]) {
                                 if (k > 0)
                                         r = k;
                                 else {
-                                        k = process_policy(a, b, m, &policy, &ucred);
-                                        if (k < 0) {
-                                                r = k;
-                                                log_error("Failed to process policy: %s", strerror(-r));
-                                                goto finish;
-                                        }
+                                        bool retry;
+
+                                        do {
+                                                retry = false;
 
-                                        k = sd_bus_send(a, m, NULL);
-                                        if (k < 0) {
-                                                if (k == -ECONNRESET)
-                                                        r = 0;
-                                                else {
+                                                k = process_policy(a, b, m, p, &ucred);
+                                                if (k < 0) {
                                                         r = k;
-                                                        log_error("Failed to send message: %s", strerror(-r));
+                                                        log_error("Failed to process policy: %s", strerror(-r));
+                                                        goto finish;
                                                 }
 
-                                                goto finish;
-                                        }
+                                                k = sd_bus_send(a, m, NULL);
+                                                if (k < 0) {
+                                                        if (k == -ECONNRESET)
+                                                                r = 0;
+                                                        else if (k == -EREMCHG)
+                                                                retry = true;
+                                                        else {
+                                                                r = k;
+                                                                log_error("Failed to send message: %s", strerror(-r));
+                                                        }
+
+                                                        if (!retry)
+                                                                goto finish;
+                                                }
+                                        } while (retry);
                                 }
                         }
                 }



More information about the systemd-commits mailing list