From 8889711323c43470e020f6b8a823c4162862f2f0 Mon Sep 17 00:00:00 2001 From: Sebastian Josue Alba Vives Date: Sun, 29 Mar 2026 06:29:57 -0600 Subject: [PATCH] staging: vc04_services: vc-sm-cma: fix integer overflow in vc_sm_cma_clean_invalid2() and add address validation in clean_invalid_contig_2d() --- .../staging/vc04_services/vc-sm-cma/vc_sm.c | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c index 34155d62a4507..29aa5a939989e 100644 --- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c +++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -1263,6 +1264,8 @@ static int clean_invalid_contig_2d(const void __user *addr, const unsigned int cache_op) { size_t i; + size_t last_block_offset; + size_t total_range; void (*op_fn)(const void *start, const void *end); if (!block_size) { @@ -1270,11 +1273,27 @@ static int clean_invalid_contig_2d(const void __user *addr, return -EINVAL; } + if (!block_count) + return 0; + op_fn = cache_op_to_func(cache_op); if (!op_fn) return -EINVAL; - for (i = 0; i < block_count; i ++, addr += stride) + /* + * Validate that the entire user-supplied address range falls + * within userspace. Without this check, an attacker could + * invoke cache maintenance operations on kernel addresses. + */ + if (check_mul_overflow((size_t)(block_count - 1), stride, + &last_block_offset)) + return -EOVERFLOW; + if (check_add_overflow(last_block_offset, block_size, &total_range)) + return -EOVERFLOW; + if (!access_ok(addr, total_range)) + return -EFAULT; + + for (i = 0; i < block_count; i++, addr += stride) op_fn(addr, addr + block_size); return 0; @@ -1292,9 +1311,13 @@ static int vc_sm_cma_clean_invalid2(unsigned int cmdnr, unsigned long arg) __func__, cmdnr); return -EFAULT; } - block = kmalloc(ioparam.op_count * sizeof(*block), GFP_KERNEL); + + if (!ioparam.op_count) + return 0; + + block = kmalloc_array(ioparam.op_count, sizeof(*block), GFP_KERNEL); if (!block) - return -EFAULT; + return -ENOMEM; if (copy_from_user(block, (void *)(arg + sizeof(ioparam)), ioparam.op_count * sizeof(*block)) != 0) {