misc: bcm-vk: validate write size before allocation

bcm_vk_write() uses the user-supplied write count to size a
flexible-array work entry and then copies count bytes into that array.
The allocation expression is evaluated before any overflow check, so a
very large count can wrap the allocation smaller than the subsequent
copy.

Reject empty writes, check the allocation arithmetic before kzalloc(),
and initialize the __counted_by field before copying into to_v_msg[].

Signed-off-by: Yousef Alhouseen <alhouseenyousef@gmail.com>
Link: https://patch.msgid.link/20260629160605.29412-1-alhouseenyousef@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Yousef Alhouseen 2026-06-29 18:06:05 +02:00 committed by Greg Kroah-Hartman
parent 808e530654
commit f66c40cd90

View File

@ -9,6 +9,7 @@
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/overflow.h>
#include <linux/poll.h>
#include <linux/sizes.h>
#include <linux/spinlock.h>
@ -1090,6 +1091,7 @@ ssize_t bcm_vk_write(struct file *p_file,
u32 q_num;
u32 msg_size;
u32 msgq_size;
size_t entry_size;
if (!bcm_vk_drv_access_ok(vk))
return -EPERM;
@ -1097,20 +1099,26 @@ ssize_t bcm_vk_write(struct file *p_file,
dev_dbg(dev, "Msg count %zu\n", count);
/* first, do sanity check where count should be multiple of basic blk */
if (count & (VK_MSGQ_BLK_SIZE - 1)) {
dev_err(dev, "Failure with size %zu not multiple of %zu\n",
if (!count || count & (VK_MSGQ_BLK_SIZE - 1)) {
dev_err(dev, "Failure with size %zu not a positive multiple of %zu\n",
count, VK_MSGQ_BLK_SIZE);
rc = -EINVAL;
goto write_err;
}
if (check_add_overflow(sizeof(*entry), count, &entry_size) ||
check_add_overflow(entry_size, vk->ib_sgl_size, &entry_size)) {
rc = -EOVERFLOW;
goto write_err;
}
/* allocate the work entry + buffer for size count and inband sgl */
entry = kzalloc(sizeof(*entry) + count + vk->ib_sgl_size,
GFP_KERNEL);
entry = kzalloc(entry_size, GFP_KERNEL);
if (!entry) {
rc = -ENOMEM;
goto write_err;
}
entry->to_v_blks = count >> VK_MSGQ_BLK_SZ_SHIFT;
/* now copy msg from user space, and then formulate the work entry */
if (copy_from_user(&entry->to_v_msg[0], buf, count)) {
@ -1118,7 +1126,6 @@ ssize_t bcm_vk_write(struct file *p_file,
goto write_free_ent;
}
entry->to_v_blks = count >> VK_MSGQ_BLK_SZ_SHIFT;
entry->ctx = ctx;
/* do a check on the blk size which could not exceed queue space */
@ -1355,4 +1362,3 @@ void bcm_vk_msg_remove(struct bcm_vk *vk)
bcm_vk_drain_all_pend(&vk->pdev->dev, &vk->to_v_msg_chan, NULL);
bcm_vk_drain_all_pend(&vk->pdev->dev, &vk->to_h_msg_chan, NULL);
}