connection: address possible auxgrp count mismatch
authorDaniel Mack <zonque@gmail.com>
Sat, 16 Aug 2014 08:54:08 +0000 (10:54 +0200)
committerDaniel Mack <zonque@gmail.com>
Sat, 16 Aug 2014 08:56:09 +0000 (10:56 +0200)
The number of auxgrps could theoretically change between the preparation of
the the meta data item and the scan in kdbus_conn_queue_alloc().

Solve this by clamping the number of group elements we look at.

connection.c

index 1533404699a8bd96c1062bc3e2c97d12a5837a5a..419c97eb9e35dcdfac2e5d07cff9ae1f82d3d815 100644 (file)
@@ -640,22 +640,33 @@ static int kdbus_conn_queue_alloc(struct kdbus_conn *conn,
                item = kdbus_meta_find_item(kmsg->meta, KDBUS_ITEM_AUXGROUPS);
                if (item) {
                        struct group_info *info;
+                       size_t item_elements;
                        int i;
 
                        info = get_current_groups();
-                       queue->auxgrps_count = info->ngroups;
+
+                       /*
+                        * In case the number of auxgroups changed since the
+                        * metadata element was composed, clamp the array
+                        * length.
+                        */
+                       item_elements = KDBUS_ITEM_PAYLOAD_SIZE(item) /
+                                       sizeof(__u64);
+                       queue->auxgrps_count = min_t(unsigned int,
+                                                    item_elements,
+                                                    info->ngroups);
 
                        if (info->ngroups > 0) {
                                queue->auxgrps =
-                                       kcalloc(info->ngroups, sizeof(kgid_t),
-                                               GFP_KERNEL);
+                                       kcalloc(queue->auxgrps_count,
+                                               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++)
+                               for (i = 0; i < queue->auxgrps_count; i++)
                                        queue->auxgrps[i] = GROUP_AT(info, i);
                        }