connection, metadata: convert auxgrp information as late as possible
authorDaniel Mack <zonque@gmail.com>
Fri, 15 Aug 2014 19:45:10 +0000 (21:45 +0200)
committerDaniel Mack <zonque@gmail.com>
Fri, 15 Aug 2014 20:11:04 +0000 (22:11 +0200)
Same as with the cred block - do the from_kgid() conversion shortly before
installing the message in the receiver's task.

connection.c
metadata.c

index 5a8f4c00ba1f74aae90dcd2d3aba0f8e28a2cf60..b6244bc3e0283323a992e38dd4b1ffdc7739bc63 100644 (file)
@@ -64,10 +64,17 @@ struct kdbus_conn_reply;
  * @creds_item_offset: The offset of the creds item inside the slice, if
  *                     the user requested this metainfo in its attach flags.
  *                     0 if unused.
+ * @auxgrp_item_offset:        The offset of the auxgrp item inside the slice, if
+ *                     the user requested this metainfo in its attach flags.
+ *                     0 if unused.
  * @uid:               The UID to patch into the final message
  * @gid:               The GID to patch into the final message
  * @pid:               The PID to patch into the final message
  * @tid:               The TID to patch into the final message
+ * @auxgrps:           An array storing the sender's aux groups, in kgid_t.
+ *                     This information is translated into the user's
+ *                     namespace when the message is installed.
+ * @auxgroup_count:    The number of items in @auxgrps.
  */
 struct kdbus_conn_queue {
        struct list_head entry;
@@ -87,12 +94,16 @@ struct kdbus_conn_queue {
        struct kdbus_conn_reply *reply;
        int user;
        off_t creds_item_offset;
+       off_t auxgrp_item_offset;
 
        /* to honor namespaces, we have to store the following here */
        kuid_t uid;
        kgid_t gid;
        struct pid *pid;
        struct pid *tid;
+
+       kgid_t *auxgrps;
+       unsigned int auxgrps_count;
 };
 
 /**
@@ -459,6 +470,8 @@ static void kdbus_conn_queue_cleanup(struct kdbus_conn_queue *queue)
                put_pid(queue->pid);
        if (queue->tid)
                put_pid(queue->tid);
+       if (queue->auxgrps)
+               kfree(queue->auxgrps);
 
        kdbus_conn_memfds_unref(queue);
        kdbus_conn_fds_unref(queue);
@@ -622,6 +635,33 @@ static int kdbus_conn_queue_alloc(struct kdbus_conn *conn,
                        queue->creds_item_offset += meta;
                }
 
+               ret = kdbus_meta_offset_of(kmsg->meta, KDBUS_ITEM_AUXGROUPS,
+                                          &queue->auxgrp_item_offset);
+               if (ret == 0) {
+                       struct group_info *info;
+                       int i;
+
+                       info = get_current_groups();
+                       queue->auxgrps_count = info->ngroups;
+
+                       if (info->ngroups > 0) {
+                               queue->auxgrps =
+                                       kcalloc(info->ngroups, sizeof(kgid_t),
+                                               GFP_KERNEL);
+                               if (!queue->auxgrps) {
+                                       ret = -ENOMEM;
+                                       put_group_info(info);
+                                       goto exit_pool_free;
+                               }
+
+                               for (i = 0; i < info->ngroups; i++)
+                                       queue->auxgrps[i] = GROUP_AT(info, i);
+                       }
+
+                       put_group_info(info);
+                       queue->auxgrp_item_offset += meta;
+               }
+
                ret = kdbus_pool_slice_copy(queue->slice, meta,
                                            kmsg->meta->data,
                                            kmsg->meta->size);
@@ -948,7 +988,30 @@ static int kdbus_conn_msg_install(struct kdbus_conn *conn,
 
                ret = kdbus_pool_slice_copy_user(queue->slice, off,
                                                 &creds, size);
-               if (ret != size)
+               if (ret < 0)
+                       goto exit_rewind;
+       }
+
+       if (queue->auxgrp_item_offset) {
+               size_t size = sizeof(__u64) * queue->auxgrps_count;
+               off_t off = queue->auxgrp_item_offset +
+                           offsetof(struct kdbus_item, data64);
+               __u64 *gid;
+
+               gid = kmalloc(size, GFP_KERNEL);
+               if (!gid) {
+                       ret = -ENOMEM;
+                       goto exit_rewind;
+               }
+
+               for (i = 0; i < queue->auxgrps_count; i++) {
+                       gid[i] = from_kgid(current_user_ns(),
+                                          queue->auxgrps[i]);
+               }
+
+               ret = kdbus_pool_slice_copy_user(queue->slice, off, gid, size);
+               kfree(gid);
+               if (ret < 0)
                        goto exit_rewind;
        }
 
index b2b27e614916561c4cea739149fa424e391532ba..fa078a265c414a4fd992113f865fcec31450db1e 100644 (file)
@@ -214,30 +214,14 @@ static int kdbus_meta_append_cred(struct kdbus_meta *meta)
 static int kdbus_meta_append_auxgroups(struct kdbus_meta *meta)
 {
        struct group_info *info;
-       struct kdbus_item *item;
-       u64 *gid, size;
-       int i, ret = 0;
+       unsigned int ngroups;
 
        info = get_current_groups();
-
-       size = KDBUS_ITEM_SIZE(info->ngroups * sizeof(*gid));
-       item = kdbus_meta_append_item(meta, size);
-       if (IS_ERR(item)) {
-               ret = PTR_ERR(item);
-               goto exit_put_groups;
-       }
-
-       item->size = size;
-       item->type = KDBUS_ITEM_AUXGROUPS;
-       gid = (u64 *) item->data;
-
-       for (i = 0; i < info->ngroups; i++)
-               gid[i] = from_kgid(current_user_ns(), GROUP_AT(info, i));
-
-exit_put_groups:
+       ngroups = info->ngroups;
        put_group_info(info);
 
-       return ret;
+       return kdbus_meta_append_data(meta, KDBUS_ITEM_AUXGROUPS,
+                                     NULL, ngroups * sizeof(__u64));
 }
 
 static int kdbus_meta_append_src_names(struct kdbus_meta *meta,