diff --git a/drivers/staging/comedi/comedi_compat32.c b/drivers/staging/comedi/comedi_compat32.c index 36a3564ba1fb..2f444e2b92c2 100644 --- a/drivers/staging/comedi/comedi_compat32.c +++ b/drivers/staging/comedi/comedi_compat32.c @@ -360,6 +360,9 @@ static int compat_insnlist(struct file *file, unsigned long arg) if (err) return -EFAULT; + if (n_insns > 65536) /* See MAX_INSNS in comedi_fops.c */ + return -EINVAL; + /* Allocate user memory to copy insnlist and insns into. */ s = compat_alloc_user_space(offsetof(struct combined_insnlist, insn[n_insns])); diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 49eba2e672eb..219a36216e50 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -1519,6 +1519,16 @@ out: return ret; } +#define MAX_INSNS 65536 +static int check_insnlist_len(struct comedi_device *dev, unsigned int n_insns) +{ + if (n_insns > MAX_INSNS) { + dev_dbg(dev->class_dev, "insnlist length too large\n"); + return -EINVAL; + } + return 0; +} + /* * COMEDI_INSNLIST ioctl * synchronous instruction list @@ -1551,6 +1561,9 @@ static int do_insnlist_ioctl(struct comedi_device *dev, if (copy_from_user(&insnlist, arg, sizeof(insnlist))) return -EFAULT; + ret = check_insnlist_len(dev, insnlist.n_insns); + if (ret) + return ret; insns = kcalloc(insnlist.n_insns, sizeof(*insns), GFP_KERNEL); if (!insns) { ret = -ENOMEM;