allow HELLO to impersonate somebody else
authorKay Sievers <kay@vrfy.org>
Tue, 24 Dec 2013 02:09:13 +0000 (03:09 +0100)
committerKay Sievers <kay@vrfy.org>
Tue, 24 Dec 2013 02:09:13 +0000 (03:09 +0100)
handle.c
kdbus.h
metadata.c
metadata.h

index f6559fcc57459e0679bae3734cf18229e1c131fd..654122d137f60104f1bcdfa11a051dd75036e685 100644 (file)
--- a/handle.c
+++ b/handle.c
@@ -301,6 +301,79 @@ static long kdbus_handle_ioctl_control(struct file *file, unsigned int cmd,
        return ret;
 }
 
+static int kdbus_handle_hello(struct kdbus_handle *handle,
+                             struct kdbus_cmd_hello *hello)
+{
+       const struct kdbus_item *item;
+       const struct kdbus_creds *creds = NULL;
+       const char *seclabel = NULL;
+
+       if (!kdbus_check_flags(hello->conn_flags))
+               return -ENOTSUPP;
+
+       if (hello->pool_size == 0 ||
+           !IS_ALIGNED(hello->pool_size, PAGE_SIZE))
+               return -EFAULT;
+
+       KDBUS_ITEM_FOREACH(item, hello, items) {
+               if (!KDBUS_ITEM_VALID(item, hello))
+                       return -EFAULT;
+
+               switch (item->type) {
+               case KDBUS_ITEM_CREDS:
+                       if (!capable(CAP_IPC_OWNER))
+                               return -EPERM;
+
+                       if (item->size !=
+                           KDBUS_ITEM_SIZE(sizeof(struct kdbus_creds)))
+                               return -EINVAL;
+
+                       creds = &item->creds;
+                       break;
+
+               case KDBUS_ITEM_SECLABEL:
+                       if (!capable(CAP_IPC_OWNER))
+                               return -EPERM;
+
+                       if (!kdbus_validate_nul(item->str,
+                                       item->size - KDBUS_ITEM_HEADER_SIZE))
+                               return -EINVAL;
+
+                       seclabel = item->data;
+                       break;
+               }
+       }
+
+       /* privileged processes can impersonate somebody else */
+       if (creds || seclabel) {
+               int ret;
+
+               /*
+                * Replace the connection's metadata gathered at open()
+                * time, with the information provided with the HELLO call.
+                */
+               kdbus_meta_free(&handle->meta);
+
+               ret = kdbus_meta_append_data(&handle->meta,
+                               KDBUS_ITEM_SECLABEL, item->data,
+                               item->size - KDBUS_ITEM_HEADER_SIZE);
+               if (ret < 0)
+                       return ret;
+
+               ret = kdbus_meta_append_data(&handle->meta,
+                               KDBUS_ITEM_CREDS, &item->creds,
+                               item->size - KDBUS_ITEM_HEADER_SIZE);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (!KDBUS_ITEM_END(item, hello))
+               return -EINVAL;
+
+       return kdbus_conn_new(handle->ep, hello, &handle->meta,
+                             &handle->conn);
+}
+
 /* kdbus endpoint make commands */
 static long kdbus_handle_ioctl_ep(struct file *file, unsigned int cmd,
                                  void __user *buf)
@@ -373,19 +446,7 @@ static long kdbus_handle_ioctl_ep(struct file *file, unsigned int cmd,
                }
                hello = v;
 
-               if (!kdbus_check_flags(hello->conn_flags)) {
-                       ret = -ENOTSUPP;
-                       break;
-               }
-
-               if (hello->pool_size == 0 ||
-                   !IS_ALIGNED(hello->pool_size, PAGE_SIZE)) {
-                       ret = -EFAULT;
-                       break;
-               }
-
-               ret = kdbus_conn_new(handle->ep, hello, &handle->meta,
-                                    &handle->conn);
+               ret = kdbus_handle_hello(handle, hello);
                if (ret < 0)
                        break;
 
diff --git a/kdbus.h b/kdbus.h
index 7a6225a461c32907e58723653ba5686358c22f81..6991b7fb8b84772d66fad2a97bc293eac6e73752 100644 (file)
--- a/kdbus.h
+++ b/kdbus.h
@@ -631,9 +631,9 @@ struct kdbus_conn_info {
  * struct kdbus_cmd_match - struct to add or remove matches
  * @size:              The total size of the struct
  * @owner_id:          Privileged users may (de)register matches on behalf
- *                     of other peers. In other cases, set to 0.
+ *                     of other peers
  * @cookie:            Userspace supplied cookie. When removing, the cookie
- *                     identifies the match to remove.
+ *                     identifies the match to remove
  * @items:             A list of items for additional information
  *
  * This structure is used with the KDBUS_CMD_ADD_MATCH and
index dd54a858a4c48f9a6f057d2337c5ffee6a4e9b6b..8804a3de1e6f26b69d7dd56d2e251c12fc3764ff 100644 (file)
@@ -81,7 +81,16 @@ kdbus_meta_append_item(struct kdbus_meta *meta, size_t extra_size)
        return item;
 }
 
-static int kdbus_meta_append_data(struct kdbus_meta *meta, u64 type,
+/**
+ * kdbus_meta_append_data() - append given raw data to metadata object
+ * @meta:              Metadata object
+ * @type:              KDBUS_ITEM_* type
+ * @data:              pointer to data to copy from
+ * @len:               number of bytes to copy
+ *
+ * Returns: 0 on success, negative errno on failure.
+ */
+int kdbus_meta_append_data(struct kdbus_meta *meta, u64 type,
                                  const void *buf, size_t len)
 {
        struct kdbus_item *item;
index 5c111b5d42fc8db4b16ca6664a325a7bec1c8e9e..4c236048bbd410d79e1d25f7333a64125cb03aae 100644 (file)
@@ -34,6 +34,8 @@ struct kdbus_meta {
 
 struct kdbus_conn;
 
+int kdbus_meta_append_data(struct kdbus_meta *meta, u64 type,
+                          const void *buf, size_t len);
 int kdbus_meta_append(struct kdbus_meta *meta,
                      struct kdbus_conn *conn,
                      u64 which);