]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
xen/gntalloc: validate grant count before allocation
authorYousef Alhouseen <alhouseenyousef@gmail.com>
Fri, 26 Jun 2026 22:38:05 +0000 (00:38 +0200)
committerJuergen Gross <jgross@suse.com>
Wed, 1 Jul 2026 07:58:24 +0000 (09:58 +0200)
gntalloc_ioctl_alloc() allocates the grant-id array before checking
whether the requested count fits within the global grant limit. Counts
above that limit cannot succeed, so reject them before the
user-controlled allocation reaches kcalloc().

Use a subtraction-based check while holding gref_mutex so adding the
requested count cannot wrap. Also cast the count before advancing the
per-file index so the page-size multiplication is performed in 64-bit
arithmetic.

Signed-off-by: Yousef Alhouseen <alhouseenyousef@gmail.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
Signed-off-by: Juergen Gross <jgross@suse.com>
Message-ID: <20260626223805.43781-3-alhouseenyousef@gmail.com>

drivers/xen/gntalloc.c

index 9279f1521b6f5dba02cedb1c992b0bb0d9a70660..3218686be45b893fc118667a0f2aa51a6ab336c9 100644 (file)
@@ -272,6 +272,7 @@ static long gntalloc_ioctl_alloc(struct gntalloc_file_private_data *priv,
        int rc = 0;
        struct ioctl_gntalloc_alloc_gref op;
        uint32_t *gref_ids;
+       unsigned int limit_snapshot;
 
        pr_debug("%s: priv %p\n", __func__, priv);
 
@@ -280,6 +281,12 @@ static long gntalloc_ioctl_alloc(struct gntalloc_file_private_data *priv,
                goto out;
        }
 
+       limit_snapshot = READ_ONCE(limit);
+       if (op.count > limit_snapshot) {
+               rc = -ENOSPC;
+               goto out;
+       }
+
        gref_ids = kcalloc(op.count, sizeof(gref_ids[0]), GFP_KERNEL);
        if (!gref_ids) {
                rc = -ENOMEM;
@@ -292,14 +299,16 @@ static long gntalloc_ioctl_alloc(struct gntalloc_file_private_data *priv,
         * are about to enforce, removing them here is a good idea.
         */
        do_cleanup();
-       if (gref_size + op.count > limit) {
+       limit_snapshot = READ_ONCE(limit);
+       if (gref_size > limit_snapshot ||
+           op.count > limit_snapshot - gref_size) {
                mutex_unlock(&gref_mutex);
                rc = -ENOSPC;
                goto out_free;
        }
        gref_size += op.count;
        op.index = priv->index;
-       priv->index += op.count * PAGE_SIZE;
+       priv->index += (uint64_t)op.count * PAGE_SIZE;
        mutex_unlock(&gref_mutex);
 
        rc = add_grefs(&op, gref_ids, priv);