[systemd-commits] 7 commits - Makefile.am man/systemd.service.xml src/core src/libsystemd src/shared src/test

Daniel Mack zonque at kemper.freedesktop.org
Mon Sep 8 05:20:57 PDT 2014


 Makefile.am                           |    4 +
 man/systemd.service.xml               |   40 +++++++++++++
 src/core/bus-common.c                 |   35 +++++++++++
 src/core/bus-common.h                 |   35 +++++++++++
 src/core/bus-endpoint.c               |   90 ++++++++++++++++++++++++++++++
 src/core/bus-endpoint.h               |   42 ++++++++++++++
 src/core/busname.c                    |    8 --
 src/core/busname.h                    |   16 +----
 src/core/execute.c                    |   26 ++++++++
 src/core/execute.h                    |    6 ++
 src/core/load-fragment-gperf.gperf.m4 |    3 +
 src/core/load-fragment.c              |   60 +++++++++++++++++++-
 src/core/load-fragment.h              |    1 
 src/core/namespace.c                  |   91 ++++++++++++++++++++++++++++++
 src/core/namespace.h                  |    1 
 src/core/service.c                    |   39 ++++++++++++-
 src/core/service.h                    |    2 
 src/libsystemd/sd-bus/bus-kernel.c    |  102 ++++++++++++++++++++++++++++++++--
 src/libsystemd/sd-bus/bus-kernel.h    |    6 +-
 src/shared/exit-status.c              |    3 +
 src/shared/exit-status.h              |    1 
 src/test/test-ns.c                    |    1 
 src/test/test-tables.c                |    2 
 23 files changed, 579 insertions(+), 35 deletions(-)

New commits:
commit e44da745d19b9e02e67e32ea82c3bad86175120c
Author: Daniel Mack <zonque at gmail.com>
Date:   Fri Aug 22 19:02:03 2014 +0200

    service: hook up custom endpoint logic
    
    If BusPolicy= was passed, the parser function will have created
    an ExecContext->bus_endpoint object, along with policy information.
    
    In that case, create a kdbus endpoint, and pass its path name to the
    namespace logic, to it will be mounted over the actual 'bus' node.
    
    At endpoint creation time, no policy is updloaded. That is done after
    fork(), through a separate call. This is necessary because we don't
    know the real uid of the process earlier than that.

diff --git a/src/core/execute.c b/src/core/execute.c
index 96cabe6..2b16b36 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -83,6 +83,7 @@
 #include "af-list.h"
 #include "mkdir.h"
 #include "apparmor-util.h"
+#include "bus-kernel.h"
 
 #ifdef HAVE_SECCOMP
 #include "seccomp-util.h"
@@ -1236,7 +1237,7 @@ static int exec_child(ExecCommand *command,
         _cleanup_strv_free_ char **our_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL;
         const char *username = NULL, *home = NULL, *shell = NULL;
         unsigned n_dont_close = 0;
-        int dont_close[n_fds + 3];
+        int dont_close[n_fds + 4];
         uid_t uid = (uid_t) -1;
         gid_t gid = (gid_t) -1;
         int i, err;
@@ -1279,6 +1280,8 @@ static int exec_child(ExecCommand *command,
                 memcpy(dont_close + n_dont_close, fds, sizeof(int) * n_fds);
                 n_dont_close += n_fds;
         }
+        if (params->bus_endpoint_fd >= 0)
+                dont_close[n_dont_close++] = params->bus_endpoint_fd;
         if (runtime) {
                 if (runtime->netns_storage_socket[0] >= 0)
                         dont_close[n_dont_close++] = runtime->netns_storage_socket[0];
@@ -1428,6 +1431,18 @@ static int exec_child(ExecCommand *command,
                 }
         }
 
+#ifdef ENABLE_KDBUS
+        if (params->bus_endpoint_fd >= 0 && context->bus_endpoint) {
+                uid_t ep_uid = (uid == (uid_t) -1) ? 0 : uid;
+
+                err = bus_kernel_set_endpoint_policy(params->bus_endpoint_fd, ep_uid, context->bus_endpoint);
+                if (err < 0) {
+                        *error = EXIT_BUS_ENDPOINT;
+                        return err;
+                }
+        }
+#endif
+
 #ifdef HAVE_PAM
         if (params->cgroup_path && context->user && context->pam_name) {
                 err = cg_set_task_access(SYSTEMD_CGROUP_CONTROLLER, params->cgroup_path, 0644, uid, gid);
@@ -1498,6 +1513,7 @@ static int exec_child(ExecCommand *command,
             !strv_isempty(context->inaccessible_dirs) ||
             context->mount_flags != 0 ||
             (context->private_tmp && runtime && (runtime->tmp_dir || runtime->var_tmp_dir)) ||
+            params->bus_endpoint_path ||
             context->private_devices ||
             context->protect_system != PROTECT_SYSTEM_NO ||
             context->protect_home != PROTECT_HOME_NO) {
@@ -1523,7 +1539,7 @@ static int exec_child(ExecCommand *command,
                                 context->inaccessible_dirs,
                                 tmp,
                                 var,
-                                NULL,
+                                params->bus_endpoint_path,
                                 context->private_devices,
                                 context->protect_home,
                                 context->protect_system,
@@ -1564,7 +1580,9 @@ static int exec_child(ExecCommand *command,
         /* We repeat the fd closing here, to make sure that
          * nothing is leaked from the PAM modules. Note that
          * we are more aggressive this time since socket_fd
-         * and the netns fds we don#t need anymore. */
+         * and the netns fds we don't need anymore. The custom
+         * endpoint fd was needed to upload the policy and can
+         * now be closed as well. */
         err = close_all_fds(fds, n_fds);
         if (err >= 0)
                 err = shift_fds(fds, n_fds);
diff --git a/src/core/execute.h b/src/core/execute.h
index e3cebfd..9c1f249 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -210,6 +210,8 @@ struct ExecParameters {
         const char *unit_id;
         usec_t watchdog_usec;
         int *idle_pipe;
+        char *bus_endpoint_path;
+        int bus_endpoint_fd;
 };
 
 int exec_spawn(ExecCommand *command,
diff --git a/src/core/service.c b/src/core/service.c
index f3775f2..3f6595c 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -45,6 +45,7 @@
 #include "fileio.h"
 #include "bus-error.h"
 #include "bus-util.h"
+#include "bus-kernel.h"
 
 static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
         [SERVICE_DEAD] = UNIT_INACTIVE,
@@ -102,6 +103,7 @@ static void service_init(Unit *u) {
         s->restart_usec = u->manager->default_restart_usec;
         s->type = _SERVICE_TYPE_INVALID;
         s->socket_fd = -1;
+        s->bus_endpoint_fd = -1;
         s->guess_main_pid = true;
 
         RATELIMIT_INIT(s->start_limit, u->manager->default_start_limit_interval, u->manager->default_start_limit_burst);
@@ -273,6 +275,7 @@ static void service_done(Unit *u) {
                 s->bus_name = NULL;
         }
 
+        s->bus_endpoint_fd = safe_close(s->bus_endpoint_fd);
         service_close_socket_fd(s);
         service_connection_unref(s);
 
@@ -889,6 +892,7 @@ static int service_spawn(
         int *fds = NULL;
         _cleanup_free_ int *fdsbuf = NULL;
         unsigned n_fds = 0, n_env = 0;
+        _cleanup_free_ char *bus_endpoint_path = NULL;
         _cleanup_strv_free_ char
                 **argv = NULL, **final_env = NULL, **our_env = NULL;
         const char *path;
@@ -896,6 +900,7 @@ static int service_spawn(
                 .apply_permissions = apply_permissions,
                 .apply_chroot      = apply_chroot,
                 .apply_tty_stdin   = apply_tty_stdin,
+                .bus_endpoint_fd   = -1,
         };
 
         assert(s);
@@ -972,6 +977,20 @@ static int service_spawn(
         } else
                 path = UNIT(s)->cgroup_path;
 
+#ifdef ENABLE_KDBUS
+        if (s->exec_context.bus_endpoint) {
+                r = bus_kernel_create_endpoint(UNIT(s)->manager->running_as == SYSTEMD_SYSTEM ? "system" : "user",
+                                               UNIT(s)->id, &bus_endpoint_path);
+                if (r < 0)
+                        goto fail;
+
+                /* Pass the fd to the exec_params so that the child process can upload the policy.
+                 * Keep a reference to the fd in the service, so the endpoint is kept alive as long
+                 * as the service is running. */
+                exec_params.bus_endpoint_fd = s->bus_endpoint_fd = r;
+        }
+#endif
+
         exec_params.argv = argv;
         exec_params.fds = fds;
         exec_params.n_fds = n_fds;
@@ -982,6 +1001,7 @@ static int service_spawn(
         exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager);
         exec_params.unit_id = UNIT(s)->id;
         exec_params.watchdog_usec = s->watchdog_usec;
+        exec_params.bus_endpoint_path = bus_endpoint_path;
         if (s->type == SERVICE_IDLE)
                 exec_params.idle_pipe = UNIT(s)->manager->idle_pipe;
 
@@ -1770,6 +1790,15 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
                 unit_serialize_item_format(u, f, "socket-fd", "%i", copy);
         }
 
+        if (s->bus_endpoint_fd >= 0) {
+                int copy;
+
+                if ((copy = fdset_put_dup(fds, s->bus_endpoint_fd)) < 0)
+                        return copy;
+
+                unit_serialize_item_format(u, f, "endpoint-fd", "%i", copy);
+        }
+
         if (s->main_exec_status.pid > 0) {
                 unit_serialize_item_format(u, f, "main-exec-status-pid", PID_FMT,
                                            s->main_exec_status.pid);
@@ -1879,10 +1908,18 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
                 if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
                         log_debug_unit(u->id, "Failed to parse socket-fd value %s", value);
                 else {
-
                         asynchronous_close(s->socket_fd);
                         s->socket_fd = fdset_remove(fds, fd);
                 }
+        } else if (streq(key, "endpoint-fd")) {
+                int fd;
+
+                if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+                        log_debug_unit(u->id, "Failed to parse endpoint-fd value %s", value);
+                else {
+                        safe_close(s->bus_endpoint_fd);
+                        s->bus_endpoint_fd = fdset_remove(fds, fd);
+                }
         } else if (streq(key, "main-exec-status-pid")) {
                 pid_t pid;
 
diff --git a/src/core/service.h b/src/core/service.h
index 5bcfd14..ad0b3b3 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -162,6 +162,8 @@ struct Service {
         pid_t main_pid, control_pid;
         int socket_fd;
 
+        int bus_endpoint_fd;
+
         bool permissions_start_only;
         bool root_directory_start_only;
         bool remain_after_exit;

commit 060e088e94852cbe166592429c330e3997c21c4c
Author: Daniel Mack <daniel at zonque.org>
Date:   Fri Sep 5 17:24:27 2014 +0200

    exit-status: add new exit code for custom endpoint errors

diff --git a/src/shared/exit-status.c b/src/shared/exit-status.c
index f3434f7..b036ded 100644
--- a/src/shared/exit-status.c
+++ b/src/shared/exit-status.c
@@ -148,6 +148,9 @@ const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) {
 
                 case EXIT_MAKE_STARTER:
                         return "MAKE_STARTER";
+
+                case EXIT_BUS_ENDPOINT:
+                        return "EXIT_BUS_ENDPOINT";
                 }
         }
 
diff --git a/src/shared/exit-status.h b/src/shared/exit-status.h
index 9d27c01..f719580 100644
--- a/src/shared/exit-status.h
+++ b/src/shared/exit-status.h
@@ -77,6 +77,7 @@ typedef enum ExitStatus {
         EXIT_RUNTIME_DIRECTORY,
         EXIT_MAKE_STARTER,
         EXIT_CHOWN,
+        EXIT_BUS_ENDPOINT,
 } ExitStatus;
 
 typedef enum ExitStatusLevel {

commit a610cc4f18c24a007e5a2cac21b2ecbd81e5f3c3
Author: Daniel Mack <zonque at gmail.com>
Date:   Fri Aug 22 18:55:21 2014 +0200

    namespace: add support for custom kdbus endpoint
    
    If a path to a previously created custom kdbus endpoint is passed in,
    bind-mount a new devtmpfs that contains a 'bus' node, which in turn in
    bind-mounted with the custom endpoint. This tmpfs then mounted over the
    kdbus subtree that refers to the current bus.
    
    This way, we can fake the bus node in order to lock down services with
    a kdbus custom endpoint policy.

diff --git a/src/core/execute.c b/src/core/execute.c
index a88e1b1..96cabe6 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -1523,6 +1523,7 @@ static int exec_child(ExecCommand *command,
                                 context->inaccessible_dirs,
                                 tmp,
                                 var,
+                                NULL,
                                 context->private_devices,
                                 context->protect_home,
                                 context->protect_system,
diff --git a/src/core/namespace.c b/src/core/namespace.c
index fe95377..eaaebdd 100644
--- a/src/core/namespace.c
+++ b/src/core/namespace.c
@@ -51,6 +51,7 @@ typedef enum MountMode {
         PRIVATE_TMP,
         PRIVATE_VAR_TMP,
         PRIVATE_DEV,
+        PRIVATE_BUS_ENDPOINT,
         READWRITE
 } MountMode;
 
@@ -272,6 +273,84 @@ fail:
         return r;
 }
 
+static int mount_kdbus(BindMount *m) {
+
+        char temporary_mount[] = "/tmp/kdbus-dev-XXXXXX";
+        _cleanup_free_ char *basepath = NULL;
+        _cleanup_umask_ mode_t u;
+        char *busnode, *root;
+        struct stat st;
+        int r;
+
+        assert(m);
+
+        u = umask(0000);
+
+        if (!mkdtemp(temporary_mount)) {
+                log_error("Failed create temp dir: %m");
+                return -errno;
+        }
+
+        root = strappenda(temporary_mount, "/kdbus");
+        mkdir(root, 0755);
+        if (mount("tmpfs", root, "tmpfs", MS_NOSUID|MS_STRICTATIME, "mode=777") < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        /* create a new /dev/null dev node copy so we have some fodder to
+         * bind-mount the custom endpoint over. */
+        if (stat("/dev/null", &st) < 0) {
+                log_error("Failed to stat /dev/null: %m");
+                r = -errno;
+                goto fail;
+        }
+
+        busnode = strappenda(root, "/bus");
+        if (mknod(busnode, (st.st_mode & ~07777) | 0600, st.st_rdev) < 0) {
+                log_error("mknod() for %s failed: %m", busnode);
+                r = -errno;
+                goto fail;
+        }
+
+        r = mount(m->path, busnode, "bind", MS_BIND, NULL);
+        if (r < 0) {
+                log_error("bind mount of %s failed: %m", m->path);
+                r = -errno;
+                goto fail;
+        }
+
+        basepath = dirname_malloc(m->path);
+        if (!basepath) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        if (mount(root, basepath, NULL, MS_MOVE, NULL) < 0) {
+                log_error("bind mount of %s failed: %m", basepath);
+                r = -errno;
+                goto fail;
+        }
+
+        rmdir(temporary_mount);
+        return 0;
+
+fail:
+        if (busnode) {
+                umount(busnode);
+                unlink(busnode);
+        }
+
+        if (root) {
+                umount(root);
+                rmdir(root);
+        }
+
+        rmdir(temporary_mount);
+
+        return r;
+}
+
 static int apply_mount(
                 BindMount *m,
                 const char *tmp_dir,
@@ -311,6 +390,9 @@ static int apply_mount(
         case PRIVATE_DEV:
                 return mount_dev(m);
 
+        case PRIVATE_BUS_ENDPOINT:
+                return mount_kdbus(m);
+
         default:
                 assert_not_reached("Unknown mode");
         }
@@ -350,6 +432,7 @@ int setup_namespace(
                 char** inaccessible_dirs,
                 char* tmp_dir,
                 char* var_tmp_dir,
+                char* bus_endpoint_path,
                 bool private_dev,
                 ProtectHome protect_home,
                 ProtectSystem protect_system,
@@ -365,7 +448,7 @@ int setup_namespace(
         if (unshare(CLONE_NEWNS) < 0)
                 return -errno;
 
-        n = !!tmp_dir + !!var_tmp_dir +
+        n = !!tmp_dir + !!var_tmp_dir + !!bus_endpoint_path +
                 strv_length(read_write_dirs) +
                 strv_length(read_only_dirs) +
                 strv_length(inaccessible_dirs) +
@@ -406,6 +489,12 @@ int setup_namespace(
                         m++;
                 }
 
+                if (bus_endpoint_path) {
+                        m->path = bus_endpoint_path;
+                        m->mode = PRIVATE_BUS_ENDPOINT;
+                        m++;
+                }
+
                 if (protect_home != PROTECT_HOME_NO) {
                         r = append_mounts(&m, STRV_MAKE("-/home", "-/run/user", "-/root"), protect_home == PROTECT_HOME_READ_ONLY ? READONLY : INACCESSIBLE);
                         if (r < 0)
diff --git a/src/core/namespace.h b/src/core/namespace.h
index 9343fe3..9cd420e 100644
--- a/src/core/namespace.h
+++ b/src/core/namespace.h
@@ -46,6 +46,7 @@ int setup_namespace(char **read_write_dirs,
                     char **inaccessible_dirs,
                     char *tmp_dir,
                     char *var_tmp_dir,
+                    char *endpoint_path,
                     bool private_dev,
                     ProtectHome protect_home,
                     ProtectSystem protect_system,
diff --git a/src/test/test-ns.c b/src/test/test-ns.c
index acad725..7714e49 100644
--- a/src/test/test-ns.c
+++ b/src/test/test-ns.c
@@ -59,6 +59,7 @@ int main(int argc, char *argv[]) {
                             (char **) inaccessible,
                             tmp_dir,
                             var_tmp_dir,
+                            NULL,
                             true,
                             PROTECT_HOME_NO,
                             PROTECT_SYSTEM_NO,

commit 501996231293506a85bf4d610938a655ddc8cb92
Author: Daniel Mack <zonque at gmail.com>
Date:   Mon Aug 18 22:42:28 2014 +0200

    bus: parse BusPolicy directive in service files
    
    Add a new directive called BusPolicy to define custom endpoint policies. If
    one such directive is given, an endpoint object in the service's ExecContext is
    created and the given policy is added to it.

diff --git a/man/systemd.service.xml b/man/systemd.service.xml
index c84a525..a82dfb2 100644
--- a/man/systemd.service.xml
+++ b/man/systemd.service.xml
@@ -308,6 +308,46 @@
                         </varlistentry>
 
                         <varlistentry>
+                                <term><varname>BusPolicy=</varname></term>
+
+                                <listitem><para>If specfied, a custom kdbus
+                                endpoint will be created and installed as the
+                                default bus node for the service. Such a custom
+                                endpoint can hold an own set of policy rules
+                                that are enforced on top of the bus-wide ones.
+                                The custom endpoint is named after the service
+                                it was created for, and its node will be
+                                bind-mounted over the default bus node
+                                location, so the service can only access the
+                                bus through its own endpoint. Note that custom
+                                bus endpoints default to a 'deny all' policy.
+                                Hence, if at least one
+                                <varname>BusPolicy=</varname> directive is
+                                given, you have to make sure to add explicit
+                                rules for everything the service should be able
+                                to do.</para>
+                                <para>The value of this directive is comprised
+                                of two parts; the bus name, and a verb to
+                                specify to granted access, which is one of
+                                <option>see</option>,
+                                <option>talk</option> or
+                                <option>own</option>.
+                                <option>talk</option> implies
+                                <option>see</option>, and <option>own</option>
+                                implies both <option>talk</option> and
+                                <option>see</option>.
+                                If multiple access levels are specified for the
+                                same bus name, the most powerful one takes
+                                effect.
+                                </para>
+                                <para>Examples:</para>
+                                <programlisting>BusPolicy=org.freedesktop.systemd1 talk</programlisting>
+                                <programlisting>BusPolicy=org.foo.bar see</programlisting>
+                                <para>This option is only available on kdbus enabled systems.</para>
+                                </listitem>
+                        </varlistentry>
+
+                        <varlistentry>
                                 <term><varname>ExecStart=</varname></term>
                                 <listitem><para>Commands with their
                                 arguments that are executed when this
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 24aa80d..e764d68 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -205,6 +205,9 @@ Service.NonBlocking,             config_parse_bool,                  0,
 Service.BusName,                 config_parse_unit_string_printf,    0,                             offsetof(Service, bus_name)
 Service.NotifyAccess,            config_parse_notify_access,         0,                             offsetof(Service, notify_access)
 Service.Sockets,                 config_parse_service_sockets,       0,                             0
+m4_ifdef(`ENABLE_KDBUS',
+`Service.BusPolicy,              config_parse_bus_endpoint_policy,   0,                             offsetof(Service, exec_context)',
+`Service.BusPolicy,              config_parse_warn_compat,           0,                             0')
 EXEC_CONTEXT_CONFIG_ITEMS(Service)m4_dnl
 CGROUP_CONTEXT_CONFIG_ITEMS(Service)m4_dnl
 KILL_CONTEXT_CONFIG_ITEMS(Service)m4_dnl
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index b4da6a5..2f3acd7 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -1752,6 +1752,62 @@ int config_parse_bus_policy(
         return 0;
 }
 
+int config_parse_bus_endpoint_policy(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        _cleanup_free_ char *name = NULL;
+        BusPolicyAccess access;
+        ExecContext *c = data;
+        char *access_str;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        name = strdup(rvalue);
+        if (!name)
+                return log_oom();
+
+        access_str = strpbrk(name, WHITESPACE);
+        if (!access_str) {
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Invalid endpoint policy value '%s'", rvalue);
+                return 0;
+        }
+
+        *access_str = '\0';
+        access_str++;
+        access_str += strspn(access_str, WHITESPACE);
+
+        access = bus_policy_access_from_string(access_str);
+        if (access <= _BUS_POLICY_ACCESS_INVALID ||
+            access >= _BUS_POLICY_ACCESS_MAX) {
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Invalid endpoint policy access type '%s'", access_str);
+                return 0;
+        }
+
+        if (!c->bus_endpoint) {
+                r = bus_endpoint_new(&c->bus_endpoint);
+
+                if (r < 0)
+                        return r;
+        }
+
+        return bus_endpoint_add_policy(c->bus_endpoint, name, access);
+}
+
 int config_parse_unit_env_file(const char *unit,
                                const char *filename,
                                unsigned line,
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index 9a1d7c5..65100c9 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -67,6 +67,7 @@ int config_parse_service_sockets(const char *unit, const char *filename, unsigne
 int config_parse_busname_service(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_bus_policy(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_bus_policy_world(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_bus_endpoint_policy(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_unit_env_file(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_ip_tos(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_unit_condition_path(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);

commit e7d718afdb28b1049d382604e5e7bf1d213a8291
Author: Daniel Mack <zonque at gmail.com>
Date:   Mon Aug 18 19:58:42 2014 +0200

    bus: add code to create custom endpoints and set their policy
    
    Custom endpoints are alternative connection points to a bus, allowing
    specific policy to be uploaded.
    
    Add two functions to bus-kernel. One to create such endpoints, and another
    one for setting a policy for them.

diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c
index ca0eddb..505f335 100644
--- a/src/libsystemd/sd-bus/bus-kernel.c
+++ b/src/libsystemd/sd-bus/bus-kernel.c
@@ -25,6 +25,7 @@
 
 #include <fcntl.h>
 #include <malloc.h>
+#include <libgen.h>
 #include <sys/mman.h>
 #include <sys/prctl.h>
 
@@ -1408,6 +1409,95 @@ int bus_kernel_open_bus_fd(const char *bus, char **path) {
         return fd;
 }
 
+int bus_kernel_create_endpoint(const char *bus_name, const char *ep_name, char **ep_path) {
+        _cleanup_free_ char *path;
+        struct kdbus_cmd_make *make;
+        struct kdbus_item *n;
+        size_t size;
+        int fd;
+
+        fd = bus_kernel_open_bus_fd(bus_name, &path);
+        if (fd < 0)
+                return fd;
+
+        size = ALIGN8(offsetof(struct kdbus_cmd_make, items));
+        size += ALIGN8(offsetof(struct kdbus_item, str) + strlen(ep_name) + 1);
+
+        make = alloca0(size);
+        make->size = size;
+        make->flags = KDBUS_MAKE_ACCESS_WORLD;
+
+        n = make->items;
+
+        n->type = KDBUS_ITEM_MAKE_NAME;
+        n->size = offsetof(struct kdbus_item, str) + strlen(ep_name) + 1;
+        strcpy(n->str, ep_name);
+
+        if (ioctl(fd, KDBUS_CMD_EP_MAKE, make) < 0) {
+                safe_close(fd);
+                return -errno;
+        }
+
+        /* The higher 32bit of the flags field are considered
+         * 'incompatible flags'. Refuse them all for now. */
+        if (make->flags > 0xFFFFFFFFULL) {
+                safe_close(fd);
+                return -ENOTSUP;
+        }
+
+        if (ep_path) {
+                asprintf(ep_path, "%s/%s", dirname(path), ep_name);
+                if (!*ep_path)
+                        return -ENOMEM;
+        }
+
+        return fd;
+}
+
+int bus_kernel_set_endpoint_policy(int fd, uid_t uid, BusEndpoint *ep) {
+
+        struct kdbus_cmd_update *update;
+        struct kdbus_item *n;
+        BusEndpointPolicy *po;
+        Iterator i;
+        size_t size;
+        int r;
+
+        size = ALIGN8(offsetof(struct kdbus_cmd_update, items));
+
+        HASHMAP_FOREACH(po, ep->policy_hash, i) {
+                size += ALIGN8(offsetof(struct kdbus_item, str) + strlen(po->name) + 1);
+                size += ALIGN8(offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access));
+        }
+
+        update = alloca0(size);
+        update->size = size;
+
+        n = update->items;
+
+        HASHMAP_FOREACH(po, ep->policy_hash, i) {
+                n->type = KDBUS_ITEM_NAME;
+                n->size = offsetof(struct kdbus_item, str) + strlen(po->name) + 1;
+                strcpy(n->str, po->name);
+                n = KDBUS_ITEM_NEXT(n);
+
+                n->type = KDBUS_ITEM_POLICY_ACCESS;
+                n->size = offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access);
+
+                n->policy_access.type = KDBUS_POLICY_ACCESS_USER;
+                n->policy_access.access = bus_kernel_translate_access(po->access);
+                n->policy_access.id = uid;
+
+                n = KDBUS_ITEM_NEXT(n);
+        }
+
+        r = ioctl(fd, KDBUS_CMD_EP_UPDATE, update);
+        if (r < 0)
+                return -errno;
+
+        return 0;
+}
+
 int bus_kernel_make_starter(
                 int fd,
                 const char *name,
diff --git a/src/libsystemd/sd-bus/bus-kernel.h b/src/libsystemd/sd-bus/bus-kernel.h
index 182f953..f1d832a 100644
--- a/src/libsystemd/sd-bus/bus-kernel.h
+++ b/src/libsystemd/sd-bus/bus-kernel.h
@@ -24,6 +24,7 @@
 #include <stdbool.h>
 
 #include "busname.h"
+#include "bus-endpoint.h"
 #include "sd-bus.h"
 
 #define KDBUS_ITEM_NEXT(item) \
@@ -69,8 +70,11 @@ int bus_kernel_open_bus_fd(const char *bus, char **path);
 int bus_kernel_make_starter(int fd, const char *name, bool activating, bool accept_fd, BusNamePolicy *policy, BusPolicyAccess world_policy);
 
 int bus_kernel_create_bus(const char *name, bool world, char **s);
+int bus_kernel_create_endpoint(const char *bus_name, const char *ep_name, char **path);
 int bus_kernel_create_domain(const char *name, char **s);
 
+int bus_kernel_set_endpoint_policy(int fd, uid_t uid, BusEndpoint *ep);
+
 int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *mapped, size_t *allocated);
 void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t mapped, size_t allocated);
 

commit bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8
Author: Daniel Mack <zonque at gmail.com>
Date:   Mon Aug 18 19:55:32 2014 +0200

    bus: add kdbus endpoint types
    
    Add types to describe endpoints and associated policy entries,
    and add a BusEndpoint instace to ExecContext.

diff --git a/Makefile.am b/Makefile.am
index 68a7896..35c877f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1028,6 +1028,8 @@ libsystemd_core_la_SOURCES = \
 	src/core/busname.h \
 	src/core/bus-common.c \
 	src/core/bus-common.h \
+	src/core/bus-endpoint.c \
+	src/core/bus-endpoint.h \
 	src/core/target.c \
 	src/core/target.h \
 	src/core/snapshot.c \
diff --git a/src/core/bus-endpoint.c b/src/core/bus-endpoint.c
new file mode 100644
index 0000000..8d11974
--- /dev/null
+++ b/src/core/bus-endpoint.c
@@ -0,0 +1,90 @@
+/***
+  This file is part of systemd.
+
+  Copyright 2014 Daniel Mack
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdlib.h>
+
+#include "bus-endpoint.h"
+
+int bus_endpoint_new(BusEndpoint **ep)
+{
+        assert(ep);
+
+        *ep = new0(BusEndpoint, 1);
+        if (!*ep)
+                return -ENOMEM;
+
+        return 0;
+}
+
+int bus_endpoint_add_policy(BusEndpoint *ep, const char *name, BusPolicyAccess access)
+{
+        _cleanup_free_ BusEndpointPolicy *po;
+        _cleanup_free_ char *key;
+        int r;
+
+        assert(ep);
+        assert(name);
+        assert(access > _BUS_POLICY_ACCESS_INVALID && access < _BUS_POLICY_ACCESS_MAX);
+
+        /* check if we already have this name in the policy list. If we do, see if the new access level
+         * is higher than the exising one, and upgrade the entry in that case. Otherwise, do nothing.
+         */
+
+        if (ep->policy_hash) {
+                po = hashmap_get(ep->policy_hash, name);
+                if (po) {
+                        if (po->access < access)
+                                po->access = access;
+
+                        return 0;
+                }
+        } else {
+                ep->policy_hash = hashmap_new(string_hash_func, string_compare_func);
+                if (!ep->policy_hash)
+                        return -ENOMEM;
+        }
+
+        po = new0(BusEndpointPolicy, 1);
+        if (!po)
+                return -ENOMEM;
+
+        key = strdup(name);
+        if (!key)
+                return -ENOMEM;
+
+        po->name = key;
+        po->access = access;
+
+        r = hashmap_put(ep->policy_hash, key, po);
+        if (r < 0)
+                return r;
+
+        po = NULL;
+        key = NULL;
+        return 0;
+}
+
+void bus_endpoint_free(BusEndpoint *endpoint)
+{
+        if (!endpoint)
+                return;
+
+        hashmap_free_free_free(endpoint->policy_hash);
+        free(endpoint);
+}
diff --git a/src/core/bus-endpoint.h b/src/core/bus-endpoint.h
new file mode 100644
index 0000000..2c5415f
--- /dev/null
+++ b/src/core/bus-endpoint.h
@@ -0,0 +1,42 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2014 Daniel Mack
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+typedef struct BusEndpoint BusEndpoint;
+typedef struct BusEndpointPolicy BusEndpointPolicy;
+
+#include "bus-common.h"
+#include "hashmap.h"
+
+struct BusEndpointPolicy {
+        char *name;
+        BusPolicyAccess access;
+};
+
+struct BusEndpoint {
+        Hashmap *policy_hash;
+};
+
+int bus_endpoint_new(BusEndpoint **ep);
+void bus_endpoint_free(BusEndpoint *endpoint);
+
+int bus_endpoint_add_policy(BusEndpoint *ep, const char *name, BusPolicyAccess access);
diff --git a/src/core/execute.c b/src/core/execute.c
index 0a59147..a88e1b1 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -1908,6 +1908,9 @@ void exec_context_done(ExecContext *c) {
 
         strv_free(c->runtime_directory);
         c->runtime_directory = NULL;
+
+        bus_endpoint_free(c->bus_endpoint);
+        c->bus_endpoint = NULL;
 }
 
 int exec_context_destroy_runtime_directory(ExecContext *c, const char *runtime_prefix) {
diff --git a/src/core/execute.h b/src/core/execute.h
index f31f0c9..e3cebfd 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -41,6 +41,7 @@ typedef struct ExecParameters ExecParameters;
 #include "fdset.h"
 #include "missing.h"
 #include "namespace.h"
+#include "bus-endpoint.h"
 
 typedef enum ExecInput {
         EXEC_INPUT_NULL,
@@ -188,6 +189,9 @@ struct ExecContext {
         bool ioprio_set:1;
         bool cpu_sched_set:1;
         bool no_new_privileges_set:1;
+
+        /* custom dbus enpoint */
+        BusEndpoint *bus_endpoint;
 };
 
 #include "cgroup.h"

commit 5369c77d2ee864ac0464d4adc0774ee70ba9c4bc
Author: Daniel Mack <zonque at gmail.com>
Date:   Mon Aug 18 22:07:47 2014 +0200

    bus: factor out bus policy items
    
    In order to re-use the policy definitions, factor them out into their own
    files.

diff --git a/Makefile.am b/Makefile.am
index 9c946d7..68a7896 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1026,6 +1026,8 @@ libsystemd_core_la_SOURCES = \
 	src/core/socket.h \
 	src/core/busname.c \
 	src/core/busname.h \
+	src/core/bus-common.c \
+	src/core/bus-common.h \
 	src/core/target.c \
 	src/core/target.h \
 	src/core/snapshot.c \
diff --git a/src/core/bus-common.c b/src/core/bus-common.c
new file mode 100644
index 0000000..4a61cb9
--- /dev/null
+++ b/src/core/bus-common.c
@@ -0,0 +1,35 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2014 Daniel Mack
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "special.h"
+#include "bus-kernel.h"
+#include "bus-internal.h"
+#include "bus-util.h"
+#include "service.h"
+#include "bus-common.h"
+
+static const char* const bus_policy_access_table[_BUS_POLICY_ACCESS_MAX] = {
+        [BUS_POLICY_ACCESS_SEE] = "see",
+        [BUS_POLICY_ACCESS_TALK] = "talk",
+        [BUS_POLICY_ACCESS_OWN] = "own",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bus_policy_access, BusPolicyAccess);
diff --git a/src/core/bus-common.h b/src/core/bus-common.h
new file mode 100644
index 0000000..209f870
--- /dev/null
+++ b/src/core/bus-common.h
@@ -0,0 +1,35 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+#include "macro.h"
+
+/***
+  This file is part of systemd.
+
+  Copyright 2014 Daniel Mack
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+typedef enum BusPolicyAccess {
+        BUS_POLICY_ACCESS_SEE,
+        BUS_POLICY_ACCESS_TALK,
+        BUS_POLICY_ACCESS_OWN,
+        _BUS_POLICY_ACCESS_MAX,
+        _BUS_POLICY_ACCESS_INVALID = -1
+} BusPolicyAccess;
+
+const char* bus_policy_access_to_string(BusPolicyAccess i) _const_;
+BusPolicyAccess bus_policy_access_from_string(const char *s) _pure_;
diff --git a/src/core/busname.c b/src/core/busname.c
index 39ea6a0..22d2a6d 100644
--- a/src/core/busname.c
+++ b/src/core/busname.c
@@ -911,14 +911,6 @@ static const char* const busname_result_table[_BUSNAME_RESULT_MAX] = {
 
 DEFINE_STRING_TABLE_LOOKUP(busname_result, BusNameResult);
 
-static const char* const busname_policy_access_table[_BUSNAME_POLICY_ACCESS_MAX] = {
-        [BUSNAME_POLICY_ACCESS_SEE] = "see",
-        [BUSNAME_POLICY_ACCESS_TALK] = "talk",
-        [BUSNAME_POLICY_ACCESS_OWN] = "own",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(busname_policy_access, BusNamePolicyAccess);
-
 const UnitVTable busname_vtable = {
         .object_size = sizeof(BusName),
 
diff --git a/src/core/busname.h b/src/core/busname.h
index 65d57f7..c9b653d 100644
--- a/src/core/busname.h
+++ b/src/core/busname.h
@@ -25,6 +25,7 @@ typedef struct BusName BusName;
 typedef struct BusNamePolicy BusNamePolicy;
 
 #include "unit.h"
+#include "bus-common.h"
 
 typedef enum BusNameState {
         BUSNAME_DEAD,
@@ -58,17 +59,9 @@ typedef enum BusNamePolicyType {
         _BUSNAME_POLICY_TYPE_INVALID = -1
 } BusNamePolicyType;
 
-typedef enum BusNamePolicyAccess {
-        BUSNAME_POLICY_ACCESS_SEE,
-        BUSNAME_POLICY_ACCESS_TALK,
-        BUSNAME_POLICY_ACCESS_OWN,
-        _BUSNAME_POLICY_ACCESS_MAX,
-        _BUSNAME_POLICY_ACCESS_INVALID = -1
-} BusNamePolicyAccess;
-
 struct BusNamePolicy {
         BusNamePolicyType type;
-        BusNamePolicyAccess access;
+        BusPolicyAccess access;
 
         char *name;
 
@@ -97,7 +90,7 @@ struct BusName {
         pid_t control_pid;
 
         LIST_HEAD(BusNamePolicy, policy);
-        BusNamePolicyAccess policy_world;
+        BusPolicyAccess policy_world;
 };
 
 extern const UnitVTable busname_vtable;
@@ -107,6 +100,3 @@ BusNameState busname_state_from_string(const char *s) _pure_;
 
 const char* busname_result_to_string(BusNameResult i) _const_;
 BusNameResult busname_result_from_string(const char *s) _pure_;
-
-const char* busname_policy_access_to_string(BusNamePolicyAccess i) _const_;
-BusNamePolicyAccess busname_policy_access_from_string(const char *s) _pure_;
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index fda27be..b4da6a5 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -1686,7 +1686,7 @@ int config_parse_busname_service(
         return 0;
 }
 
-DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, busname_policy_access, BusNamePolicyAccess, "Failed to parse bus name policy access");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access");
 
 int config_parse_bus_policy(
                 const char *unit,
@@ -1736,7 +1736,7 @@ int config_parse_bus_policy(
         access_str++;
         access_str += strspn(access_str, WHITESPACE);
 
-        p->access = busname_policy_access_from_string(access_str);
+        p->access = bus_policy_access_from_string(access_str);
         if (p->access < 0) {
                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
                            "Invalid busname policy access type '%s'", access_str);
diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c
index 03c4165..ca0eddb 100644
--- a/src/libsystemd/sd-bus/bus-kernel.c
+++ b/src/libsystemd/sd-bus/bus-kernel.c
@@ -1322,19 +1322,19 @@ int bus_kernel_create_bus(const char *name, bool world, char **s) {
         return fd;
 }
 
-static int bus_kernel_translate_access(BusNamePolicyAccess access) {
+static int bus_kernel_translate_access(BusPolicyAccess access) {
         assert(access >= 0);
-        assert(access < _BUSNAME_POLICY_ACCESS_MAX);
+        assert(access < _BUS_POLICY_ACCESS_MAX);
 
         switch (access) {
 
-        case BUSNAME_POLICY_ACCESS_SEE:
+        case BUS_POLICY_ACCESS_SEE:
                 return KDBUS_POLICY_SEE;
 
-        case BUSNAME_POLICY_ACCESS_TALK:
+        case BUS_POLICY_ACCESS_TALK:
                 return KDBUS_POLICY_TALK;
 
-        case BUSNAME_POLICY_ACCESS_OWN:
+        case BUS_POLICY_ACCESS_OWN:
                 return KDBUS_POLICY_OWN;
 
         default:
@@ -1414,7 +1414,7 @@ int bus_kernel_make_starter(
                 bool activating,
                 bool accept_fd,
                 BusNamePolicy *policy,
-                BusNamePolicyAccess world_policy) {
+                BusPolicyAccess world_policy) {
 
         struct kdbus_cmd_hello *hello;
         struct kdbus_item *n;
diff --git a/src/libsystemd/sd-bus/bus-kernel.h b/src/libsystemd/sd-bus/bus-kernel.h
index 448dd3a..182f953 100644
--- a/src/libsystemd/sd-bus/bus-kernel.h
+++ b/src/libsystemd/sd-bus/bus-kernel.h
@@ -66,7 +66,7 @@ int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m, bool hint_sync_call
 int bus_kernel_read_message(sd_bus *bus, bool hint_priority, int64_t priority);
 
 int bus_kernel_open_bus_fd(const char *bus, char **path);
-int bus_kernel_make_starter(int fd, const char *name, bool activating, bool accept_fd, BusNamePolicy *policy, BusNamePolicyAccess world_policy);
+int bus_kernel_make_starter(int fd, const char *name, bool activating, bool accept_fd, BusNamePolicy *policy, BusPolicyAccess world_policy);
 
 int bus_kernel_create_bus(const char *name, bool world, char **s);
 int bus_kernel_create_domain(const char *name, char **s);
diff --git a/src/test/test-tables.c b/src/test/test-tables.c
index 58fe443..907958e 100644
--- a/src/test/test-tables.c
+++ b/src/test/test-tables.c
@@ -55,7 +55,7 @@ int main(int argc, char **argv) {
         test_table(architecture, ARCHITECTURE);
         test_table(automount_result, AUTOMOUNT_RESULT);
         test_table(automount_state, AUTOMOUNT_STATE);
-        test_table(busname_policy_access, BUSNAME_POLICY_ACCESS);
+        test_table(bus_policy_access, BUS_POLICY_ACCESS);
         test_table(busname_result, BUSNAME_RESULT);
         test_table(busname_state, BUSNAME_STATE);
         test_table(cgroup_device_policy, CGROUP_DEVICE_POLICY);



More information about the systemd-commits mailing list