add support for sharing fd and pool with clients 14/201214/4
authorAdrian Szyndela <adrian.s@samsung.com>
Mon, 11 Mar 2019 09:54:03 +0000 (10:54 +0100)
committerAdrian Szyndela <adrian.s@samsung.com>
Fri, 15 Mar 2019 13:59:45 +0000 (14:59 +0100)
This adds two new API functions, which can be used for sharing
kdbus fd and kdbus pool with the library clients.

Until now, the library created its own connection each time
it was initialized, effectively allocating 1MB of memory
only for getting small responses to one of kdbus ioctls.

This kind of activity may be performed on any usable kdbus
connection. Thus, the idea of sharing existing connections
with libdbuspolicy.

As it is a change of interface (two new API functions), the version
of library and package has been bumped up.

Change-Id: I7bae7a60a386f1c3bc35c88528c9f2baa2c57e34

Makefile.am
configure.ac
packaging/libdbuspolicy.spec
src/dbuspolicy1/libdbuspolicy1.h
src/libdbuspolicy1.c
src/libdbuspolicy1.sym

index 8df326f..e103e4a 100644 (file)
@@ -43,9 +43,9 @@ SED_PROCESS = \
 %.pc: %.pc.in Makefile
        $(SED_PROCESS)
 
-LIBDBUSPOLICY1_CURRENT=1
+LIBDBUSPOLICY1_CURRENT=2
 LIBDBUSPOLICY1_REVISION=0
-LIBDBUSPOLICY1_AGE=0
+LIBDBUSPOLICY1_AGE=1
 
 pkginclude_HEADERS = src/dbuspolicy1/libdbuspolicy1.h
 lib_LTLIBRARIES = src/libdbuspolicy1.la
index be90ee8..5ffc83a 100644 (file)
@@ -1,6 +1,6 @@
 AC_PREREQ(2.60)
 AC_INIT([dbuspolicy],
-        [1],
+        [1.1.0],
         [dev@lists.tizen.org],
         [dbuspolicy],
         [http://review.tizen.org])
index ba23170..debe443 100644 (file)
@@ -2,7 +2,7 @@ Name:           libdbuspolicy
 Summary:        Helper library for fine-grained userspace policy handling
 License:        Apache-2.0
 Group:          Base/IPC
-Version:        1.0.0
+Version:        1.1.0
 Release:        0
 Source:         %{name}-%{version}.tar.gz
 Source1001:     %{name}.manifest
index 9333ddd..21f79a2 100644 (file)
@@ -65,6 +65,10 @@ struct udesc;
  */
 void* dbuspolicy1_init(const char *bus_path);
 
+void* dbuspolicy1_init_shared(const char *bus_path, int fd);
+
+void dbuspolicy1_init_set_pool(void *configuration, void *pool);
+
 /**
  * Free libdbuspolicy configuration context
  * \ingroup API
index c67e2c5..d725136 100644 (file)
@@ -58,8 +58,8 @@ typedef unsigned long dbus_gid_t;
 
 struct kconn {
        int fd;
-       uint64_t id;
        char *pool;
+       BusType bus_type;
 } g_conn[2] = {
        {.pool = MAP_FAILED},
        {.pool = MAP_FAILED}
@@ -71,6 +71,10 @@ struct udesc {
        char label[256];
 } g_udesc;
 
+static bool init_once_done = false;
+static bool init_once_db[2] = {false, false};
+static bool init_once_conn[2] = {false, false};
+
 void __dbuspolicy1_change_creds(uid_t uid, gid_t gid, const char* label)
 {
        g_udesc.uid = uid;
@@ -84,12 +88,11 @@ static int kdbus_open_bus(const char *path)
        return open(path, O_RDWR|O_NOCTTY|O_LARGEFILE|O_CLOEXEC);
 }
 
-static int kdbus_hello(BusType bus_type, uint64_t hello_flags, uint64_t attach_flags_send, uint64_t attach_flags_recv)
+static int kdbus_hello(struct kconn *kconn, uint64_t hello_flags, uint64_t attach_flags_send, uint64_t attach_flags_recv)
 {
        struct kdbus_cmd_hello* cmd;
        struct kdbus_cmd_free cmd_free;
        struct kdbus_item* item;
-       int fd = g_conn[bus_type].fd;
        int size = ALIGN8(sizeof(struct kdbus_cmd_hello)) + ALIGN8(offsetof(struct kdbus_item, data) + sizeof(CONNECTION_LABEL));
 
        cmd = calloc(1, size);
@@ -105,16 +108,15 @@ static int kdbus_hello(BusType bus_type, uint64_t hello_flags, uint64_t attach_f
        item->size = offsetof(struct kdbus_item, data) + sizeof(CONNECTION_LABEL);
        item->type = KDBUS_ITEM_CONN_DESCRIPTION;
        memcpy(item->str, CONNECTION_LABEL, sizeof(CONNECTION_LABEL));
-       if (ioctl(fd, KDBUS_CMD_HELLO, cmd) < 0)
+       if (ioctl(kconn->fd, KDBUS_CMD_HELLO, cmd) < 0)
                goto err;
 
-       g_conn[bus_type].id = cmd->id;
-       if (MAP_FAILED == (g_conn[bus_type].pool = mmap(NULL, KDBUS_POOL_SIZE, PROT_READ, MAP_SHARED, fd, 0)))
+       if (MAP_FAILED == (kconn->pool = mmap(NULL, KDBUS_POOL_SIZE, PROT_READ, MAP_SHARED, kconn->fd, 0)))
                goto err;
 
        cmd_free.offset = cmd->offset;
        cmd_free.size = sizeof(struct kdbus_cmd_free);
-       ioctl(g_conn[bus_type].fd, KDBUS_CMD_FREE, &cmd_free);
+       ioctl(kconn->fd, KDBUS_CMD_FREE, &cmd_free);
        free(cmd);
        return 0;
 
@@ -142,15 +144,18 @@ static uint64_t kdbus_unique_id(char const *name)
        return res;
 }
 
-static bool dbuspolicy_init_once(void)
+static bool dbuspolicy_init_once_locked(void)
 {
+       if (init_once_done)
+               return false;
+
        char buf[1024];
        int attr_fd;
        int r;
 
        attr_fd = open("/proc/self/attr/current", O_RDONLY);
        if (attr_fd < 0)
-               return -1;
+               return true;
        r = read(attr_fd, buf, sizeof(buf));
        close(attr_fd);
 
@@ -164,27 +169,46 @@ static bool dbuspolicy_init_once(void)
 
        __internal_init_once();
 
+       init_once_done = true;
+
+       return false;
+}
+
+static bool bus_type_from_path(const char *bus_path, BusType *bus_type, char **pp)
+{
+       char *p = realpath(bus_path, NULL);
+       if (!p)
+               return false;
+
+       if (pp)
+               *pp = p;
+
+       if (0 == strcmp(p, KDBUS_SYSTEM_BUS_PATH)) {
+               *bus_type = SYSTEM_BUS;
+               return true;
+       }
+
+       if (0 == strncmp(p, KDBUS_PATH_PREFIX, strlen(KDBUS_PATH_PREFIX))) {
+               *bus_type = SESSION_BUS;
+               return true;
+       }
+
+       free(p);
        return false;
 }
 
 static int bus_path_resolve(const char *bus_path, char *resolved_path, unsigned resolved_path_size, BusType *bus_type, uid_t *bus_owner)
 {
-       char *p;
        const char user_suffix[] = "-user/bus";
        int suffix_pos;
        char* last_slash;
        int ret = -1;
+       char *p;
 
-       p = realpath(bus_path, NULL);
-       if (!p)
+       if (!bus_type_from_path(bus_path, bus_type, &p))
                return -1;
 
-       if (0 != strncmp(p, KDBUS_PATH_PREFIX, strlen(KDBUS_PATH_PREFIX)))
-               goto err;
-
-       if (0 == strcmp(p, KDBUS_SYSTEM_BUS_PATH)) {
-               *bus_type = SYSTEM_BUS;
-       } else {
+       if (*bus_type == SESSION_BUS && NULL != bus_owner) {
                suffix_pos = strlen(p) - strlen(user_suffix);
                if (suffix_pos < 0)
                        goto err;
@@ -205,90 +229,136 @@ static int bus_path_resolve(const char *bus_path, char *resolved_path, unsigned
                // so it's OK to assume that *bus_owner==0 always means error.
                if (errno || (*bus_owner == 0))
                        goto err;
-
-               *bus_type = SESSION_BUS;
        }
 
-       snprintf(resolved_path, resolved_path_size, "%s", p);
+       if (resolved_path)
+               snprintf(resolved_path, resolved_path_size, "%s", p);
+
        ret = 0;
 err:
        free(p);
        return ret;
 }
 
-static bool init_once_done = false;
-static bool init_once[2] = {false, false};
+static bool init_common_locked(BusType bus_type)
+{
+       dbuspolicy_init_once_locked();
 
-DBUSPOLICY1_EXPORT void* dbuspolicy1_init(const char *bus_path)
+       if (init_once_db[bus_type])
+               return true;
+
+       int ret = __internal_init_auto_serialized(bus_type, (bus_type == SYSTEM_BUS) ? system_bus_conf_file_primary() : session_bus_conf_file_primary());
+       if (ret < 0)
+               ret = __internal_init(bus_type, (bus_type == SYSTEM_BUS) ? SYSTEM_BUS_CONF_FILE_SECONDARY : SESSION_BUS_CONF_FILE_SECONDARY);
+
+       if (ret >= 0) {
+               __internal_init_sup_group(bus_type, g_udesc.uid, g_udesc.gid);
+               init_once_db[bus_type] = true;
+       }
+       return ret >= 0;
+}
+
+static struct kconn *init_global_conn_locked(BusType bus_type, const char *resolved_path)
 {
-       BusType bus_type = SESSION_BUS;
-       char resolved_path[PATH_MAX] = { 0 };
-       int rp, rs;
-       uid_t bus_owner = 0;
+       if (init_once_conn[bus_type])
+               return &g_conn[bus_type];
 
-       _Static_assert(SYSTEM_BUS == 0, "SYSTEM_BUS not 0");
-       _Static_assert(SESSION_BUS == 1, "SESSION_BUS not 1");
+       struct kconn *result = &g_conn[bus_type];
+       if ((result->fd = kdbus_open_bus(resolved_path)) < 0) {
+               LOGE("Error opening bus: %s", resolved_path);
+               return NULL;
+       }
 
-       if (bus_path_resolve(bus_path, resolved_path, sizeof(resolved_path), &bus_type, &bus_owner) < 0) {
-               LOGE("Error resolving bus path: %s", bus_path);
+       if (kdbus_hello(result, 0, _KDBUS_ATTACH_ALL, 0) < 0) {
+               LOGE("Error: bus hello failed");
+               close(result->fd);
                return NULL;
        }
+       result->bus_type = bus_type;
+       init_once_conn[bus_type] = true;
 
+       return result;
+}
+
+static struct kconn *get_global_conn(BusType bus_type, const char *resolved_path)
+{
        pthread_mutex_lock(&g_mutex);
-       if (!init_once_done) {
-               init_once_done = true;
-               dbuspolicy_init_once();
+       struct kconn *result = init_global_conn_locked(bus_type, resolved_path);
+       pthread_mutex_unlock(&g_mutex);
+       return result;
+}
+
+static struct kconn *init_shared_fd(BusType bus_type, int fd)
+{
+       struct kconn *result = malloc(sizeof(*result));
+       if (NULL == result) {
+               LOGE("Error: failed to allocate memory for policy configuration");
+               return NULL;
        }
-       if (!init_once[bus_type]) {
-               rp = __internal_init_auto_serialized(bus_type, (bus_type == SYSTEM_BUS) ? system_bus_conf_file_primary() : session_bus_conf_file_primary());
-               if (rp < 0)
-                       rs = __internal_init(bus_type, (bus_type == SYSTEM_BUS) ? SYSTEM_BUS_CONF_FILE_SECONDARY : SESSION_BUS_CONF_FILE_SECONDARY);
-               else
-                       rs = 1;
+       result->fd = fd;
+       result->bus_type = bus_type;
+       return result;
+}
 
-               if (rp < 0 && rs < 0) /* when both negative */
-                       goto err;
+static bool can_open(BusType bus_type, uid_t bus_owner)
+{
+       pthread_mutex_lock(&g_mutex);
+       bool ret = init_common_locked(bus_type);
+       pthread_mutex_unlock(&g_mutex);
 
-               __internal_init_sup_group(bus_type, g_udesc.uid, g_udesc.gid);
+       if (ret)
+               return __internal_can_open(bus_type, bus_owner, g_udesc.uid, g_udesc.gid, g_udesc.label) > 0;
 
-               if (__internal_can_open(bus_type, bus_owner, g_udesc.uid, g_udesc.gid, g_udesc.label) <= 0) {
-                       LOGE("Error: %lu isn't allowed", g_udesc.uid);
-                       goto err;
-               }
+       return false;
+}
 
-               if ((g_conn[bus_type].fd = kdbus_open_bus(resolved_path)) < 0) {
-                       LOGE("Error opening bus: %s", resolved_path);
-                       goto err;
-               }
+DBUSPOLICY1_EXPORT void* dbuspolicy1_init_shared(const char *bus_path, int fd)
+{
+       _Static_assert(SYSTEM_BUS == 0, "SYSTEM_BUS not 0");
+       _Static_assert(SESSION_BUS == 1, "SESSION_BUS not 1");
 
-               if (kdbus_hello(bus_type, 0, _KDBUS_ATTACH_ALL, 0) < 0) {
-                       LOGE("Error: bus hello failed");
-                       goto err_close;
-               }
+       BusType bus_type = SESSION_BUS;
+       uid_t bus_owner = 0;
+       char resolved_path[PATH_MAX] = { 0 };
 
-               init_once[bus_type] = true;
+       if (bus_path_resolve(bus_path, resolved_path, sizeof(resolved_path), &bus_type, &bus_owner) < 0) {
+               LOGE("Error resolving bus path: %s", bus_path);
+               return NULL;
+       }
+
+       struct kconn *result = NULL;
+       if (can_open(bus_type, bus_owner)) {
+               if (-1 == fd) {
+                       result = get_global_conn(bus_type, resolved_path);
+               } else {
+                       result = init_shared_fd(bus_type, fd);
+               }
        }
 
-       pthread_mutex_unlock(&g_mutex);
        __internal_init_flush_logs();
 
-       return &g_conn[bus_type];
+       return result;
+}
 
-err_close:
-       if (g_conn[bus_type].pool != MAP_FAILED)
-               munmap(g_conn[bus_type].pool, KDBUS_POOL_SIZE);
-       close(g_conn[bus_type].fd);
-err:
-       pthread_mutex_unlock(&g_mutex);
-       return NULL;
+DBUSPOLICY1_EXPORT void* dbuspolicy1_init(const char *bus_path)
+{
+       return dbuspolicy1_init_shared(bus_path, -1);
 }
 
-DBUSPOLICY1_EXPORT void dbuspolicy1_free(void* configuration)
+DBUSPOLICY1_EXPORT void dbuspolicy1_init_set_pool(void *configuration, void *pool)
 {
-       configuration = configuration;
+       struct kconn *conf = configuration;
+       conf->pool = pool;
 }
 
-static BusType configuration_bus_type(struct kconn const *configuration) { return configuration == g_conn ? SYSTEM_BUS : SESSION_BUS; }
+DBUSPOLICY1_EXPORT void dbuspolicy1_free(void* configuration)
+{
+       for (size_t i = 0; i < sizeof(g_conn)/sizeof(g_conn[0]); i++)
+               if (configuration == &g_conn[i])
+                       return;
+
+       free(configuration);
+}
 
 union kdbus_cmd_union {
        struct kdbus_cmd_info cmd_info;
@@ -306,7 +376,7 @@ struct kdbus_cmd_param {
        union kdbus_cmd_union cmd;
 };
 
-int kdbus_get_conn_info(BusType bus_type, const char *destination, struct kdbus_cmd_param *info, __u64 flags)
+int kdbus_get_conn_info(struct kconn *kconn, const char *destination, struct kdbus_cmd_param *info, __u64 flags)
 {
        char const *label = NULL;
        const char** k_names = info->k_names;
@@ -337,7 +407,7 @@ int kdbus_get_conn_info(BusType bus_type, const char *destination, struct kdbus_
                *(uint64_t*)ALIGNDN8((uintptr_t)cmd->cmd_info.items->str + l) = 0; /* trailing zero + padding */
                memcpy(cmd->cmd_info.items->str, destination, l + 1);
        }
-       r = ioctl(g_conn[bus_type].fd, KDBUS_CMD_CONN_INFO, &cmd->cmd_info);
+       r = ioctl(kconn->fd, KDBUS_CMD_CONN_INFO, &cmd->cmd_info);
        if (r < 0) {
                if (errno == ENXIO || errno == ESRCH)
                        r = DBUSPOLICY_RESULT_DEST_NOT_AVAILABLE;
@@ -354,7 +424,7 @@ int kdbus_get_conn_info(BusType bus_type, const char *destination, struct kdbus_
 
        free_offset = true;
 
-       conn_info = (struct kdbus_info *) ((uint8_t *) g_conn[bus_type].pool + cmd->cmd_info.offset);
+       conn_info = (struct kdbus_info *) ((uint8_t *) kconn->pool + cmd->cmd_info.offset);
        items_end = (uintptr_t)conn_info + (unsigned)conn_info->size;
 
        _Static_assert((unsigned)KDBUS_ITEM_CREDS == KDBUS_ITEM_CREDS, "KDBUS_ITEM_CREDS not preserved when cast to unsigned");
@@ -404,8 +474,9 @@ DBUSPOLICY1_EXPORT int dbuspolicy1_check_out(void* configuration,
        (void)reply_serial;
        (void)requested_reply;
 
+       struct kconn *kconn = configuration;
+
        int r;
-       BusType bus_type = configuration_bus_type(configuration);
        struct kdbus_cmd_param info = {
                .free_offset = false,
                .empty_names = true
@@ -423,15 +494,15 @@ DBUSPOLICY1_EXPORT int dbuspolicy1_check_out(void* configuration,
        /* check can send */
        /* if broadcasting, then pass - null destination */
        if (destination && *destination) {
-               r = kdbus_get_conn_info(bus_type, destination, &info, POLICY_CONN_INFO_ALL);
+               r = kdbus_get_conn_info(kconn, destination, &info, POLICY_CONN_INFO_ALL);
                if (r < 0)
                        goto end;
        }
 
        if (info.empty_names)
-               r = __internal_can_send(bus_type, g_udesc.uid, g_udesc.gid, g_udesc.label, destination, path, interface, member, message_type);
+               r = __internal_can_send(kconn->bus_type, g_udesc.uid, g_udesc.gid, g_udesc.label, destination, path, interface, member, message_type);
        else
-               r = __internal_can_send_multi_dest(bus_type, g_udesc.uid, g_udesc.gid, g_udesc.label, info.k_names, path, interface, member, message_type);
+               r = __internal_can_send_multi_dest(kconn->bus_type, g_udesc.uid, g_udesc.gid, g_udesc.label, info.k_names, path, interface, member, message_type);
 
        if (r <= 0)
                goto end;
@@ -449,7 +520,7 @@ DBUSPOLICY1_EXPORT int dbuspolicy1_check_out(void* configuration,
                        strncpy(dest_label, info.label, strlen(info.label) + 1);
                }
                if (info.free_offset)
-                       ioctl(g_conn[bus_type].fd, KDBUS_CMD_FREE, &cmd->cmd_free);
+                       ioctl(kconn->fd, KDBUS_CMD_FREE, &cmd->cmd_free);
 
                info.free_offset = false;
                info.empty_names = true;
@@ -457,20 +528,20 @@ DBUSPOLICY1_EXPORT int dbuspolicy1_check_out(void* configuration,
 
        /* check can recv */
        /* get sender information from kdbus */
-       r = kdbus_get_conn_info(bus_type, sender, &info, POLICY_CONN_INFO_NAME);
+       r = kdbus_get_conn_info(kconn, sender, &info, POLICY_CONN_INFO_NAME);
        if (r < 0) {
                fprintf(stderr, "failed to kdbus conn info:%d\n", r);
                goto end;
        }
 
        if (info.empty_names)
-               r = __internal_can_recv(bus_type, dest_uid_n, dest_gid_n, dest_label, sender, path, interface, member, message_type);
+               r = __internal_can_recv(kconn->bus_type, dest_uid_n, dest_gid_n, dest_label, sender, path, interface, member, message_type);
        else
-               r = __internal_can_recv_multi(bus_type, dest_uid_n, dest_gid_n, dest_label, info.k_names, path, interface, member, message_type);
+               r = __internal_can_recv_multi(kconn->bus_type, dest_uid_n, dest_gid_n, dest_label, info.k_names, path, interface, member, message_type);
 
 end:
        if (info.free_offset)
-               ioctl(g_conn[bus_type].fd, KDBUS_CMD_FREE, &cmd->cmd_free);
+               ioctl(kconn->fd, KDBUS_CMD_FREE, &cmd->cmd_free);
 
        if (dest_label)
                free(dest_label);
@@ -497,8 +568,9 @@ DBUSPOLICY1_EXPORT int dbuspolicy1_check_in(void* configuration,
        (void)reply_serial;
        (void)requested_reply;
 
+       struct kconn *kconn = configuration;
+
        int r;
-       BusType bus_type = configuration_bus_type(configuration);
        struct kdbus_cmd_param info = {
                .free_offset = false,
                .empty_names = true
@@ -507,15 +579,15 @@ DBUSPOLICY1_EXPORT int dbuspolicy1_check_in(void* configuration,
        __internal_enter();
 
        if (destination && *destination) {
-               r = kdbus_get_conn_info(bus_type, destination, &info, POLICY_CONN_INFO_NAME);
+               r = kdbus_get_conn_info(kconn, destination, &info, POLICY_CONN_INFO_NAME);
                if (r < 0)
                        goto end;
        }
 
        if (info.empty_names)
-               r = __internal_can_send(bus_type, sender_uid, sender_gid, sender_label, destination, path, interface, member, message_type);
+               r = __internal_can_send(kconn->bus_type, sender_uid, sender_gid, sender_label, destination, path, interface, member, message_type);
        else
-               r = __internal_can_send_multi_dest(bus_type, sender_uid, sender_gid, sender_label, info.k_names, path, interface, member, message_type);
+               r = __internal_can_send_multi_dest(kconn->bus_type, sender_uid, sender_gid, sender_label, info.k_names, path, interface, member, message_type);
 
        if (r <= 0)
                goto end;
@@ -525,12 +597,12 @@ DBUSPOLICY1_EXPORT int dbuspolicy1_check_in(void* configuration,
        /* it is not needed to use __internal_can_recv_multi here. */
        if (!sender)
                sender = ":";
-       r = __internal_can_recv(bus_type, g_udesc.uid, g_udesc.gid, g_udesc.label, sender, path, interface, member, message_type);
+       r = __internal_can_recv(kconn->bus_type, g_udesc.uid, g_udesc.gid, g_udesc.label, sender, path, interface, member, message_type);
        if (r <= 0)
                goto end;
 end:
        if (info.free_offset)
-               ioctl(g_conn[bus_type].fd, KDBUS_CMD_FREE, &info.cmd.cmd_free);
+               ioctl(kconn->fd, KDBUS_CMD_FREE, &info.cmd.cmd_free);
 
        __internal_exit();
        return r;
@@ -539,9 +611,9 @@ end:
 DBUSPOLICY1_EXPORT int dbuspolicy1_can_own(void* configuration, const char* const service)
 {
        int r;
-       BusType bus_type = configuration_bus_type(configuration);
+       struct kconn *kconn = configuration;
        __internal_enter();
-       r = __internal_can_own(bus_type, g_udesc.uid, g_udesc.gid, g_udesc.label, service);
+       r = __internal_can_own(kconn->bus_type, g_udesc.uid, g_udesc.gid, g_udesc.label, service);
        __internal_exit();
        return r;
 }
index 447f243..4cdb793 100644 (file)
@@ -8,3 +8,8 @@ global:
 local:
         *;
 };
+
+LIBDBUSPOLICY1_1.1 {
+        dbuspolicy1_init_shared;
+        dbuspolicy1_init_set_pool;
+} LIBDBUSPOLICY1_1;