drivers/xen/privcmd.c | 4 ++++ 1 file changed, 4 insertions(+)
The "m.num * sizeof(*m.arr)" multiplication can have an integer overflow
on 32 bit systems. Probably no one really uses this software on 32 bit
systems, but it's still worth fixing the bug if only to make the static
checker happy.
Fixes: ceb90fa0a800 ("xen/privcmd: add PRIVCMD_MMAPBATCH_V2 ioctl")
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
---
drivers/xen/privcmd.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c
index ad17166b0ef6..1e59b76c618e 100644
--- a/drivers/xen/privcmd.c
+++ b/drivers/xen/privcmd.c
@@ -456,6 +456,8 @@ static long privcmd_ioctl_mmap_batch(
if (copy_from_user(&m, udata, sizeof(struct privcmd_mmapbatch)))
return -EFAULT;
/* Returns per-frame error in m.arr. */
+ if (m.num > SIZE_MAX / sizeof(*m.arr))
+ return -EINVAL;
m.err = NULL;
if (!access_ok(m.arr, m.num * sizeof(*m.arr)))
return -EFAULT;
@@ -464,6 +466,8 @@ static long privcmd_ioctl_mmap_batch(
if (copy_from_user(&m, udata, sizeof(struct privcmd_mmapbatch_v2)))
return -EFAULT;
/* Returns per-frame error code in m.err. */
+ if (m.num > SIZE_MAX / sizeof(*m.arr))
+ return -EINVAL;
if (!access_ok(m.err, m.num * (sizeof(*m.err))))
return -EFAULT;
break;
--
2.35.1
Hi Dan,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on xen-tip/linux-next]
[also build test WARNING on linus/master v5.19-rc7 next-20220719]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Dan-Carpenter/xen-privcmd-prevent-integer-overflow-on-32-bit-systems/20220715-162307
base: https://git.kernel.org/pub/scm/linux/kernel/git/xen/tip.git linux-next
config: x86_64-randconfig-a005 (https://download.01.org/0day-ci/archive/20220720/202207200236.GeswjpCk-lkp@intel.com/config)
compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project fa0c7639e91fa1cd0cf2ff0445a1634a90fe850a)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/intel-lab-lkp/linux/commit/ea22ebd83753c7181043e69251b78f0be73675ad
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Dan-Carpenter/xen-privcmd-prevent-integer-overflow-on-32-bit-systems/20220715-162307
git checkout ea22ebd83753c7181043e69251b78f0be73675ad
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=x86_64 SHELL=/bin/bash drivers/acpi/ drivers/ata/ drivers/rtc/ drivers/thermal/intel/ drivers/xen/
If you fix the issue, kindly add following tag where applicable
Reported-by: kernel test robot <lkp@intel.com>
All warnings (new ones prefixed by >>):
>> drivers/xen/privcmd.c:459:13: warning: result of comparison of constant 2305843009213693951 with expression of type 'unsigned int' is always false [-Wtautological-constant-out-of-range-compare]
if (m.num > SIZE_MAX / sizeof(*m.arr))
~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/xen/privcmd.c:469:13: warning: result of comparison of constant 2305843009213693951 with expression of type 'unsigned int' is always false [-Wtautological-constant-out-of-range-compare]
if (m.num > SIZE_MAX / sizeof(*m.arr))
~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~
2 warnings generated.
vim +459 drivers/xen/privcmd.c
441
442 static long privcmd_ioctl_mmap_batch(
443 struct file *file, void __user *udata, int version)
444 {
445 struct privcmd_data *data = file->private_data;
446 int ret;
447 struct privcmd_mmapbatch_v2 m;
448 struct mm_struct *mm = current->mm;
449 struct vm_area_struct *vma;
450 unsigned long nr_pages;
451 LIST_HEAD(pagelist);
452 struct mmap_batch_state state;
453
454 switch (version) {
455 case 1:
456 if (copy_from_user(&m, udata, sizeof(struct privcmd_mmapbatch)))
457 return -EFAULT;
458 /* Returns per-frame error in m.arr. */
> 459 if (m.num > SIZE_MAX / sizeof(*m.arr))
460 return -EINVAL;
461 m.err = NULL;
462 if (!access_ok(m.arr, m.num * sizeof(*m.arr)))
463 return -EFAULT;
464 break;
465 case 2:
466 if (copy_from_user(&m, udata, sizeof(struct privcmd_mmapbatch_v2)))
467 return -EFAULT;
468 /* Returns per-frame error code in m.err. */
469 if (m.num > SIZE_MAX / sizeof(*m.arr))
470 return -EINVAL;
471 if (!access_ok(m.err, m.num * (sizeof(*m.err))))
472 return -EFAULT;
473 break;
474 default:
475 return -EINVAL;
476 }
477
478 /* If restriction is in place, check the domid matches */
479 if (data->domid != DOMID_INVALID && data->domid != m.dom)
480 return -EPERM;
481
482 nr_pages = DIV_ROUND_UP(m.num, XEN_PFN_PER_PAGE);
483 if ((m.num <= 0) || (nr_pages > (LONG_MAX >> PAGE_SHIFT)))
484 return -EINVAL;
485
486 ret = gather_array(&pagelist, m.num, sizeof(xen_pfn_t), m.arr);
487
488 if (ret)
489 goto out;
490 if (list_empty(&pagelist)) {
491 ret = -EINVAL;
492 goto out;
493 }
494
495 if (version == 2) {
496 /* Zero error array now to only copy back actual errors. */
497 if (clear_user(m.err, sizeof(int) * m.num)) {
498 ret = -EFAULT;
499 goto out;
500 }
501 }
502
503 mmap_write_lock(mm);
504
505 vma = find_vma(mm, m.addr);
506 if (!vma ||
507 vma->vm_ops != &privcmd_vm_ops) {
508 ret = -EINVAL;
509 goto out_unlock;
510 }
511
512 /*
513 * Caller must either:
514 *
515 * Map the whole VMA range, which will also allocate all the
516 * pages required for the auto_translated_physmap case.
517 *
518 * Or
519 *
520 * Map unmapped holes left from a previous map attempt (e.g.,
521 * because those foreign frames were previously paged out).
522 */
523 if (vma->vm_private_data == NULL) {
524 if (m.addr != vma->vm_start ||
525 m.addr + (nr_pages << PAGE_SHIFT) != vma->vm_end) {
526 ret = -EINVAL;
527 goto out_unlock;
528 }
529 if (xen_feature(XENFEAT_auto_translated_physmap)) {
530 ret = alloc_empty_pages(vma, nr_pages);
531 if (ret < 0)
532 goto out_unlock;
533 } else
534 vma->vm_private_data = PRIV_VMA_LOCKED;
535 } else {
536 if (m.addr < vma->vm_start ||
537 m.addr + (nr_pages << PAGE_SHIFT) > vma->vm_end) {
538 ret = -EINVAL;
539 goto out_unlock;
540 }
541 if (privcmd_vma_range_is_mapped(vma, m.addr, nr_pages)) {
542 ret = -EINVAL;
543 goto out_unlock;
544 }
545 }
546
547 state.domain = m.dom;
548 state.vma = vma;
549 state.va = m.addr;
550 state.index = 0;
551 state.global_error = 0;
552 state.version = version;
553
554 BUILD_BUG_ON(((PAGE_SIZE / sizeof(xen_pfn_t)) % XEN_PFN_PER_PAGE) != 0);
555 /* mmap_batch_fn guarantees ret == 0 */
556 BUG_ON(traverse_pages_block(m.num, sizeof(xen_pfn_t),
557 &pagelist, mmap_batch_fn, &state));
558
559 mmap_write_unlock(mm);
560
561 if (state.global_error) {
562 /* Write back errors in second pass. */
563 state.user_gfn = (xen_pfn_t *)m.arr;
564 state.user_err = m.err;
565 ret = traverse_pages_block(m.num, sizeof(xen_pfn_t),
566 &pagelist, mmap_return_errors, &state);
567 } else
568 ret = 0;
569
570 /* If we have not had any EFAULT-like global errors then set the global
571 * error to -ENOENT if necessary. */
572 if ((ret == 0) && (state.global_error == -ENOENT))
573 ret = -ENOENT;
574
575 out:
576 free_page_list(&pagelist);
577 return ret;
578
579 out_unlock:
580 mmap_write_unlock(mm);
581 goto out;
582 }
583
--
0-DAY CI Kernel Test Service
https://01.org/lkp
On 15.07.22 11:20, Dan Carpenter wrote:
Hello Dan
> The "m.num * sizeof(*m.arr)" multiplication can have an integer overflow
> on 32 bit systems. Probably no one really uses this software on 32 bit
> systems, but it's still worth fixing the bug if only to make the static
> checker happy.
>
> Fixes: ceb90fa0a800 ("xen/privcmd: add PRIVCMD_MMAPBATCH_V2 ioctl")
> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
> ---
> drivers/xen/privcmd.c | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c
> index ad17166b0ef6..1e59b76c618e 100644
> --- a/drivers/xen/privcmd.c
> +++ b/drivers/xen/privcmd.c
> @@ -456,6 +456,8 @@ static long privcmd_ioctl_mmap_batch(
> if (copy_from_user(&m, udata, sizeof(struct privcmd_mmapbatch)))
> return -EFAULT;
> /* Returns per-frame error in m.arr. */
> + if (m.num > SIZE_MAX / sizeof(*m.arr))
> + return -EINVAL;
> m.err = NULL;
> if (!access_ok(m.arr, m.num * sizeof(*m.arr)))
> return -EFAULT;
> @@ -464,6 +466,8 @@ static long privcmd_ioctl_mmap_batch(
> if (copy_from_user(&m, udata, sizeof(struct privcmd_mmapbatch_v2)))
> return -EFAULT;
> /* Returns per-frame error code in m.err. */
> + if (m.num > SIZE_MAX / sizeof(*m.arr))
Looks like here we need to check against sizeof(*m.err) which is used in
the multiplication below.
> + return -EINVAL;
> if (!access_ok(m.err, m.num * (sizeof(*m.err))))
> return -EFAULT;
> break;
--
Regards,
Oleksandr Tyshchenko
On Fri, Jul 15, 2022 at 08:56:30AM +0000, Oleksandr Tyshchenko wrote:
>
> On 15.07.22 11:20, Dan Carpenter wrote:
>
>
> Hello Dan
>
> > The "m.num * sizeof(*m.arr)" multiplication can have an integer overflow
> > on 32 bit systems. Probably no one really uses this software on 32 bit
> > systems, but it's still worth fixing the bug if only to make the static
> > checker happy.
> >
> > Fixes: ceb90fa0a800 ("xen/privcmd: add PRIVCMD_MMAPBATCH_V2 ioctl")
> > Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
> > ---
> > drivers/xen/privcmd.c | 4 ++++
> > 1 file changed, 4 insertions(+)
> >
> > diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c
> > index ad17166b0ef6..1e59b76c618e 100644
> > --- a/drivers/xen/privcmd.c
> > +++ b/drivers/xen/privcmd.c
> > @@ -456,6 +456,8 @@ static long privcmd_ioctl_mmap_batch(
> > if (copy_from_user(&m, udata, sizeof(struct privcmd_mmapbatch)))
> > return -EFAULT;
> > /* Returns per-frame error in m.arr. */
> > + if (m.num > SIZE_MAX / sizeof(*m.arr))
> > + return -EINVAL;
> > m.err = NULL;
> > if (!access_ok(m.arr, m.num * sizeof(*m.arr)))
> > return -EFAULT;
> > @@ -464,6 +466,8 @@ static long privcmd_ioctl_mmap_batch(
> > if (copy_from_user(&m, udata, sizeof(struct privcmd_mmapbatch_v2)))
> > return -EFAULT;
> > /* Returns per-frame error code in m.err. */
> > + if (m.num > SIZE_MAX / sizeof(*m.arr))
>
> Looks like here we need to check against sizeof(*m.err) which is used in
> the multiplication below.
Oh, yeah. Sorry! Need to redo that.
regards,
dan carpenter
© 2016 - 2025 Red Hat, Inc.