policy checking scheme: modified to get connection information from kdbus 87/138787/3 accepted/tizen/4.0/unified/20170816.010723 accepted/tizen/unified/20170727.190341 submit/tizen/20170719.103604 submit/tizen/20170725.023005 submit/tizen_4.0/20170811.094300
authorsanghyeok.oh <sanghyeok.oh@samsung.com>
Thu, 13 Jul 2017 15:34:37 +0000 (00:34 +0900)
committersanghyeok.oh <sanghyeok.oh@samsung.com>
Tue, 18 Jul 2017 02:54:38 +0000 (11:54 +0900)
To check dbus policy it is needed to get every information, especially multiple names and label.

For example,
if Service A have multiple name such as name_A1, name_A2, and name_A3,
and if Service A specify the rule as below,

<deny send_destination="name_A2"/>
<allow send_destination="name_A1"/>

then according to dbus policy,
last specified rule '<allow send_destination="name_A1"/>' is applied,

*** In dbus policy world dbus treat multiple names of Service A as same name,
this also affect every other names of Service A, meaning,
<allow send_destination="name_A1"/> or <allow send_destination="name_A2"/> or <allow send_destination="name_A3"/>

After all, Service B can send message to name_A1, name_A2, and name_A3.
send message to unique name of Service A also allowed by this rule.

*** unique name also treat as same as well-known name of Service A.

Change-Id: I2253296267d8c844c53813455c829bf625f4360c
Signed-off-by: sanghyeok.oh <sanghyeok.oh@samsung.com>
src/internal/internal.cpp [changed mode: 0644->0755]
src/internal/internal.h [changed mode: 0644->0755]
src/libdbuspolicy1.c

old mode 100644 (file)
new mode 100755 (executable)
index fb2676f..aa0e947
@@ -123,6 +123,26 @@ int __internal_can_recv(bool bus_type,
        return static_cast<int>(policy_checker().check(bus_type, user, group, label, matcher, ldp_xml_parser::ItemType::RECEIVE));
 }
 
+int __internal_can_recv_multi(bool bus_type,
+       const uid_t user,
+       const gid_t group,
+       const char* const label,
+       const char** const sender,
+       const char* const path,
+       const char* const interface,
+       const char* const member,
+       int type)
+{
+       int i = 0;
+       ldp_xml_parser::MatchItemSR matcher(interface, member, path, static_cast<ldp_xml_parser::MessageType>(type), ldp_xml_parser::MessageDirection::RECEIVE);
+       if (sender)
+               while (sender[i]) {
+                       matcher.addName(sender[i++]);
+               }
+       return static_cast<int>(policy_checker().check(bus_type, user, group, label, matcher, ldp_xml_parser::ItemType::RECEIVE));
+}
+
+
 int __internal_can_own(bool bus_type,
                                           const uid_t user,
                                           const gid_t group,
old mode 100644 (file)
new mode 100755 (executable)
index 787b380..94db50b
@@ -118,6 +118,28 @@ int __internal_can_recv(bool bus_type,
                                                const char* const member,
                                                int type);
 
+/** Check if user can receive messages.
+ * \param[in] bus_type Bus type (system/session)
+ * \param[in] user User id
+ * \param[in] group User group id
+ * \param[in] label User label
+ * \param[in] sender Sender of received message
+ * \param[in] path Path
+ * \param[in] interface Interface name
+ * \param[in] member Member name
+ * \param[in] type Message type
+ * \return 1 on allow, 0 on deny, negative error code otherwise
+ */
+int __internal_can_recv_multi(bool bus_type,
+                                               uid_t user,
+                                               gid_t group,
+                                               const char* const label,
+                                               const char** const sender,
+                                               const char* const path,
+                                               const char* const interface,
+                                               const char* const member,
+                                               int type);
+
 /** Checks if given user can own interface with given label
  * \param[in] bus_type Bus type (system/session)
  * \param[in] user User id
index 61b2a37..1c9723b 100755 (executable)
@@ -94,6 +94,8 @@ static int kdbus_hello(bool bus_type, uint64_t hello_flags, uint64_t attach_flag
        int size = ALIGN8(sizeof(struct kdbus_cmd_hello)) + ALIGN8(offsetof(struct kdbus_item, data) + sizeof(CONNECTION_LABEL));
 
        cmd = calloc(1, size);
+       if (!cmd)
+               goto err;
        cmd->size = size;
        cmd->flags = hello_flags;
        cmd->attach_flags_send = attach_flags_send;
@@ -263,12 +265,111 @@ DBUSPOLICY1_EXPORT void __dbuspolicy1_change_creds(void* configuration, uid_t ui
        g_udesc.uid = uid;
        g_udesc.gid = gid;
        if (label)
-               strcpy (g_udesc.label, label);
+               strncpy (g_udesc.label, label, strlen(label) + 1);
 }
 #endif
 
 static bool configuration_bus_type(struct kconn const *configuration) { return configuration != g_conn; }
 
+union kdbus_cmd_union {
+       struct kdbus_cmd_info cmd_info;
+       struct kdbus_cmd_free cmd_free;
+       uint8_t _buffer_[sizeof(struct kdbus_cmd_info) + offsetof(struct kdbus_item, data) + ALIGN8(MAX_DBUS_NAME_LEN+1)];
+};
+
+struct kdbus_cmd_param {
+       char const *label;
+       const char* k_names[KDBUS_CONN_MAX_NAMES+1];
+       uid_t uid_n;
+       gid_t gid_n;
+       bool free_offset;
+       bool empty_names;
+       union kdbus_cmd_union cmd;
+};
+
+int kdbus_get_conn_info(bool bus_type, const char *destination, int message_type, struct kdbus_cmd_param *info)
+{
+       char const *label = NULL;
+       const char** k_names = info->k_names;
+       int k_i = 0;
+       int r;
+       uid_t uid_n = UID_INVALID;
+       gid_t gid_n = GID_INVALID;
+       bool free_offset = false;
+       bool empty_names = true;
+       union kdbus_cmd_union *cmd = &info->cmd;
+
+       struct kdbus_info *conn_info;
+       struct kdbus_item *item;
+       uintptr_t items_end;
+
+       cmd->cmd_info.flags = 0;
+       cmd->cmd_info.attach_flags = (__u64)(KDBUS_ATTACH_CREDS | KDBUS_ATTACH_NAMES | (DBUSPOLICY_MESSAGE_TYPE_SIGNAL != message_type ? KDBUS_ATTACH_SECLABEL : 0));
+
+       if (kdbus_is_unique_id(destination)) {
+               cmd->cmd_info.size = sizeof(cmd->cmd_info);
+               cmd->cmd_info.id = kdbus_unique_id(destination);
+       } else {
+               unsigned int l = strlen(destination);
+               cmd->cmd_info.size = sizeof(struct kdbus_cmd_info) + offsetof(struct kdbus_item, data) + ALIGN8(l+1);
+               cmd->cmd_info.id = 0;
+               cmd->cmd_info.items->size = (__u64)offsetof(struct kdbus_item, data) + (__u64)l + (__u64)1;
+               cmd->cmd_info.items->type = KDBUS_ITEM_NAME;
+               *(uint64_t*)ALIGNDN8((uintptr_t)cmd->cmd_info.items->str + l) = 0; /* trailing zero + padding */
+               memcpy(cmd->cmd_info.items->str, destination, l);
+       }
+       r = ioctl(g_conn[bus_type].fd, KDBUS_CMD_CONN_INFO, &cmd->cmd_info);
+       if (r < 0) {
+               if (errno == ENXIO || errno == ESRCH)
+                       r = DBUSPOLICY_RESULT_DEST_NOT_AVAILABLE;
+               else
+                       r = DBUSPOLICY_RESULT_KDBUS_ERROR;
+               goto end;
+       }
+
+       cmd->cmd_free.size = sizeof(cmd->cmd_free);
+       /* flags already 0 */
+       _Static_assert(sizeof(cmd->cmd_info.flags) == sizeof(cmd->cmd_free.flags), "cmd_info/cmd_free: flag sizeof differs");
+       _Static_assert(offsetof(typeof(cmd->cmd_info), flags) == offsetof(typeof(cmd->cmd_free), flags), "cmd_info/cmd_free: flag offsetof differs");
+       cmd->cmd_free.offset = cmd->cmd_info.offset;
+
+       free_offset = true;
+
+       conn_info = (struct kdbus_info *) ((uint8_t *) g_conn[bus_type].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");
+       _Static_assert((unsigned)KDBUS_ITEM_SECLABEL == KDBUS_ITEM_SECLABEL, "KDBUS_ITEM_SECLABEL not preserved when cast to unsigned");
+       _Static_assert((unsigned)KDBUS_ITEM_OWNED_NAME == KDBUS_ITEM_OWNED_NAME, "KDBUS_ITEM_OWNED_NAME not preserved when cast to unsigned");
+
+       for (item = conn_info->items; (uintptr_t)item < items_end; item = (typeof(item))ALIGN8((uintptr_t)item + (unsigned)item->size))
+               switch ((unsigned)item->type)
+       {
+               case KDBUS_ITEM_CREDS:
+                       uid_n = item->creds.euid;
+                       gid_n = item->creds.egid;
+                       break;
+               case KDBUS_ITEM_SECLABEL:
+                       label = item->str;
+                       break;
+               case KDBUS_ITEM_OWNED_NAME:
+                       empty_names = false;
+                       k_names[k_i++] = item->name.name;
+                       break;
+       }
+       if (!empty_names)
+               k_names[k_i++] = NULL;
+
+end:
+       info->label = label;
+       info->uid_n = uid_n;
+       info->gid_n = gid_n;
+       info->free_offset = free_offset;
+       info->empty_names = empty_names;
+
+       return r;
+}
+
 DBUSPOLICY1_EXPORT int dbuspolicy1_check_out(void* configuration,
                                                                                         const char *destination,
                                                                                         const char *sender,
@@ -284,103 +385,78 @@ DBUSPOLICY1_EXPORT int dbuspolicy1_check_out(void* configuration,
        (void)reply_serial;
        (void)requested_reply;
 
-       char const *label = NULL;
-       const char* k_names[KDBUS_CONN_MAX_NAMES+1];
-       int k_i = 0;
        int r;
-       uid_t uid_n = UID_INVALID;
-       gid_t gid_n = GID_INVALID;
-       bool free_offset = false;
-       bool empty_names = true;
        bool bus_type = configuration_bus_type(configuration);
-       union {
-               struct kdbus_cmd_info cmd_info;
-               struct kdbus_cmd_free cmd_free;
-               uint8_t _buffer_[sizeof(struct kdbus_cmd_info) + offsetof(struct kdbus_item, data) + ALIGN8(MAX_DBUS_NAME_LEN+1)];
-       } cmd;
+       struct kdbus_cmd_param info = {
+               .free_offset = false,
+               .empty_names = true
+       };
+       union kdbus_cmd_union *cmd = &info.cmd;
+       char *dest_label = NULL;
+
+       /* Broadcast signal has NULL destination */
+       /* Due to this sender can not check rule correctly */
+       if (message_type == DBUSPOLICY_MESSAGE_TYPE_SIGNAL && !destination)
+               return 1;
 
        __internal_enter();
 
-    if (DBUSPOLICY_MESSAGE_TYPE_SIGNAL != message_type || (destination && *destination)) {
-               struct kdbus_info *conn_info;
-               struct kdbus_item *item;
-               uintptr_t items_end;
-
-               cmd.cmd_info.flags = 0;
-               cmd.cmd_info.attach_flags = KDBUS_ATTACH_CREDS | KDBUS_ATTACH_NAMES | (DBUSPOLICY_MESSAGE_TYPE_SIGNAL != message_type ? KDBUS_ATTACH_SECLABEL : 0);
-
-               if (kdbus_is_unique_id(destination)) {
-                       cmd.cmd_info.size = sizeof(cmd.cmd_info);
-                       cmd.cmd_info.id = kdbus_unique_id(destination);
-               } else {
-                       int l = strlen(destination);
-                       cmd.cmd_info.size = sizeof(struct kdbus_cmd_info) + offsetof(struct kdbus_item, data) + ALIGN8(l+1);
-                       cmd.cmd_info.id = 0;
-                       cmd.cmd_info.items->size =  offsetof(struct kdbus_item, data) + l+1;
-                       cmd.cmd_info.items->type = KDBUS_ITEM_NAME;
-                       *(uint64_t*)ALIGNDN8((uintptr_t)cmd.cmd_info.items->str + l) = 0; /* trailing zero + padding */
-                       memcpy(cmd.cmd_info.items->str, destination, l);
-               }
-               r = ioctl(g_conn[bus_type].fd, KDBUS_CMD_CONN_INFO, &cmd.cmd_info);
-               if (r < 0) {
-                       if (errno == ENXIO || errno == ESRCH)
-                               r = DBUSPOLICY_RESULT_DEST_NOT_AVAILABLE;
-                       else
-                               r = DBUSPOLICY_RESULT_KDBUS_ERROR;
+       /* check can send */
+       /* if broadcasting, then pass - null destination */
+       if (destination && *destination) {
+               r = kdbus_get_conn_info(bus_type, destination, message_type, &info);
+               if (r < 0)
                        goto end;
-               }
-
-               cmd.cmd_free.size = sizeof(cmd.cmd_free);
-               /* flags already 0 */
-               _Static_assert(sizeof(cmd.cmd_info.flags) == sizeof(cmd.cmd_free.flags), "cmd_info/cmd_free: flag sizeof differs");
-               _Static_assert(offsetof(typeof(cmd.cmd_info), flags) == offsetof(typeof(cmd.cmd_free), flags), "cmd_info/cmd_free: flag offsetof differs");
-               cmd.cmd_free.offset = cmd.cmd_info.offset;
-
-               free_offset = true;
-
-               conn_info = (struct kdbus_info *) ((uint8_t *) g_conn[bus_type].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");
-               _Static_assert((unsigned)KDBUS_ITEM_SECLABEL == KDBUS_ITEM_SECLABEL, "KDBUS_ITEM_SECLABEL not preserved when cast to unsigned");
-               _Static_assert((unsigned)KDBUS_ITEM_OWNED_NAME == KDBUS_ITEM_OWNED_NAME, "KDBUS_ITEM_OWNED_NAME not preserved when cast to unsigned");
-
-               for (item = conn_info->items; (uintptr_t)item < items_end; item = (typeof(item))ALIGN8((uintptr_t)item + (unsigned)item->size))
-                       switch ((unsigned)item->type)
-                       {
-                       case KDBUS_ITEM_CREDS:
-                               uid_n = item->creds.euid;
-                               gid_n = item->creds.egid;
-                               break;
-                       case KDBUS_ITEM_SECLABEL:
-                               label = item->str;
-                               break;
-                       case KDBUS_ITEM_OWNED_NAME:
-                               empty_names = false;
-                               k_names[k_i++] = item->name.name;
-                               break;
-                       }
        }
 
-       if (empty_names)
+       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);
-       else {
-               k_names[k_i++] = NULL;
-        r = __internal_can_send_multi_dest(bus_type, g_udesc.uid, g_udesc.gid, g_udesc.label, k_names, 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);
+
        if (r <= 0)
                goto end;
 
-       if (message_type != DBUSPOLICY_MESSAGE_TYPE_SIGNAL) {
-               sender = NULL;
-               r = __internal_can_recv(bus_type, uid_n, gid_n, label, sender, path, interface, member, message_type);
+       uid_t dest_uid_n = 0;
+       gid_t dest_gid_n = 0;
+
+       /* copy & free */
+       if (destination && *destination) {
+               dest_uid_n = info.uid_n;
+               dest_gid_n = info.gid_n;
+
+               if (info.label) {
+                       dest_label = (char*)malloc(sizeof(char) * strlen(info.label) + 1);
+                       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);
+
+               info.free_offset = false;
+               info.empty_names = true;
+       }
+
+       /* check can recv */
+       /* get sender information from kdbus */
+       r = kdbus_get_conn_info(bus_type, sender, message_type, &info);
+       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);
+       else
+               r = __internal_can_recv_multi(bus_type, dest_uid_n, dest_gid_n, dest_label, info.k_names, path, interface, member, message_type);
+
 end:
-       if (free_offset)
-               ioctl(g_conn[bus_type].fd, KDBUS_CMD_FREE, &cmd.cmd_free);
+       if (info.free_offset)
+               ioctl(g_conn[bus_type].fd, KDBUS_CMD_FREE, &cmd->cmd_free);
 
+       if (dest_label)
+               free(dest_label);
        __internal_exit();
+
        return r;
 }
 
@@ -404,19 +480,37 @@ DBUSPOLICY1_EXPORT int dbuspolicy1_check_in(void* configuration,
 
        int r;
        bool bus_type = configuration_bus_type(configuration);
+       struct kdbus_cmd_param info = {
+               .free_offset = false,
+               .empty_names = true
+       };
 
        __internal_enter();
 
-       r = __internal_can_send(bus_type, sender_uid, sender_gid, sender_label, destination, path, interface, member, message_type);
+       if (destination && *destination) {
+               r = kdbus_get_conn_info(bus_type, destination, message_type, &info);
+               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);
+       else
+               r = __internal_can_send_multi_dest(bus_type, sender_uid, sender_gid, sender_label, info.k_names, path, interface, member, message_type);
+
        if (r <= 0)
                goto end;
 
-       if (message_type != DBUSPOLICY_MESSAGE_TYPE_SIGNAL) {
-               r = __internal_can_recv(bus_type, g_udesc.uid, g_udesc.gid, g_udesc.label, sender, path, interface, member, message_type);
-               if (r <= 0)
-                       goto end;
-       }
+       /* libdbus, gdbus pass multiple sender as parameter : eg. "name_A name_B name_C". */
+       /* Because of '__internal_can_recv' can check rule against multiple names, */
+       /* it is not needed to use __internal_can_recv_multi here. */
+       r = __internal_can_recv(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);
+
        __internal_exit();
        return r;
 }