[ Upstream commit 08ae4b20f5e82101d77326ecab9089e110f224cc ]
The handling of the `COMEDI_INSNLIST` ioctl allocates a kernel buffer to hold the array of `struct comedi_insn`, getting the length from the `n_insns` member of the `struct comedi_insnlist` supplied by the user. The allocation will fail with a WARNING and a stack dump if it is too large.
Avoid that by failing with an `-EINVAL` error if the supplied `n_insns` value is unreasonable.
Define the limit on the `n_insns` value in the `MAX_INSNS` macro. Set this to the same value as `MAX_SAMPLES` (65536), which is the maximum allowed sum of the values of the member `n` in the array of `struct comedi_insn`, and sensible comedi instructions will have an `n` of at least 1.
Reported-by: syzbot+d6995b62e5ac7d79557a@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=d6995b62e5ac7d79557a Fixes: ed9eccbe8970 ("Staging: add comedi core") Tested-by: Ian Abbott abbotti@mev.co.uk Cc: stable@vger.kernel.org # 5.13+ Signed-off-by: Ian Abbott abbotti@mev.co.uk Link: https://lore.kernel.org/r/20250704120405.83028-1-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/staging/comedi/comedi_fops.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 8f896e6208a8..5aa6a84d1fa6 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -1584,6 +1584,16 @@ static int do_insnlist_ioctl(struct comedi_device *dev, return i; }
+#define MAX_INSNS MAX_SAMPLES +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_INSN ioctl * synchronous instruction @@ -2234,6 +2244,9 @@ static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd, rc = -EFAULT; break; } + rc = check_insnlist_len(dev, insnlist.n_insns); + if (rc) + break; insns = kcalloc(insnlist.n_insns, sizeof(*insns), GFP_KERNEL); if (!insns) { rc = -ENOMEM; @@ -3085,6 +3098,9 @@ static int compat_insnlist(struct file *file, unsigned long arg) if (copy_from_user(&insnlist32, compat_ptr(arg), sizeof(insnlist32))) return -EFAULT;
+ rc = check_insnlist_len(dev, insnlist32.n_insns); + if (rc) + return rc; insns = kcalloc(insnlist32.n_insns, sizeof(*insns), GFP_KERNEL); if (!insns) return -ENOMEM;
[ Upstream commit ab705c8c35e18652abc6239c07cf3441f03e2cda ]
Correct some left shifts of the signed integer constant 1 by some unsigned number less than 32. Change the constant to 1U to avoid shifting a 1 into the sign bit.
The corrected functions are comedi_dio_insn_config(), comedi_dio_update_state(), and __comedi_device_postconfig().
Fixes: e523c6c86232 ("staging: comedi: drivers: introduce comedi_dio_insn_config()") Fixes: 05e60b13a36b ("staging: comedi: drivers: introduce comedi_dio_update_state()") Fixes: 09567cb4373e ("staging: comedi: initialize subdevice s->io_bits in postconfig") Cc: stable@vger.kernel.org # 5.13+ Signed-off-by: Ian Abbott abbotti@mev.co.uk Link: https://lore.kernel.org/r/20250707121555.65424-1-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/staging/comedi/drivers.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c index 750a6ff3c03c..6bb7b8a1e75d 100644 --- a/drivers/staging/comedi/drivers.c +++ b/drivers/staging/comedi/drivers.c @@ -339,10 +339,10 @@ int comedi_dio_insn_config(struct comedi_device *dev, unsigned int *data, unsigned int mask) { - unsigned int chan_mask = 1 << CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec);
- if (!mask) - mask = chan_mask; + if (!mask && chan < 32) + mask = 1U << chan;
switch (data[0]) { case INSN_CONFIG_DIO_INPUT: @@ -382,7 +382,7 @@ EXPORT_SYMBOL_GPL(comedi_dio_insn_config); unsigned int comedi_dio_update_state(struct comedi_subdevice *s, unsigned int *data) { - unsigned int chanmask = (s->n_chan < 32) ? ((1 << s->n_chan) - 1) + unsigned int chanmask = (s->n_chan < 32) ? ((1U << s->n_chan) - 1) : 0xffffffff; unsigned int mask = data[0] & chanmask; unsigned int bits = data[1]; @@ -625,8 +625,8 @@ static int insn_rw_emulate_bits(struct comedi_device *dev, if (insn->insn == INSN_WRITE) { if (!(s->subdev_flags & SDF_WRITABLE)) return -EINVAL; - _data[0] = 1 << (chan - base_chan); /* mask */ - _data[1] = data[0] ? (1 << (chan - base_chan)) : 0; /* bits */ + _data[0] = 1U << (chan - base_chan); /* mask */ + _data[1] = data[0] ? (1U << (chan - base_chan)) : 0; /* bits */ }
ret = s->insn_bits(dev, s, &_insn, _data); @@ -709,7 +709,7 @@ static int __comedi_device_postconfig(struct comedi_device *dev)
if (s->type == COMEDI_SUBD_DO) { if (s->n_chan < 32) - s->io_bits = (1 << s->n_chan) - 1; + s->io_bits = (1U << s->n_chan) - 1; else s->io_bits = 0xffffffff; }
[ Sasha's backport helper bot ]
Hi,
✅ All tests passed successfully. No issues detected. No action required from the submitter.
The upstream commit SHA1 provided is correct: ab705c8c35e18652abc6239c07cf3441f03e2cda
Status in newer kernel trees: 6.15.y | Not found 6.12.y | Not found 6.6.y | Not found 6.1.y | Not found 5.15.y | Not found
Note: The patch differs from the upstream commit: --- 1: ab705c8c35e1 ! 1: e5ccdaa83664 comedi: Fix some signed shift left operations @@ Metadata ## Commit message ## comedi: Fix some signed shift left operations
+ [ Upstream commit ab705c8c35e18652abc6239c07cf3441f03e2cda ] + Correct some left shifts of the signed integer constant 1 by some unsigned number less than 32. Change the constant to 1U to avoid shifting a 1 into the sign bit. @@ Commit message Link: https://lore.kernel.org/r/20250707121555.65424-1-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
- ## drivers/comedi/drivers.c ## -@@ drivers/comedi/drivers.c: int comedi_dio_insn_config(struct comedi_device *dev, + ## drivers/staging/comedi/drivers.c ## +@@ drivers/staging/comedi/drivers.c: int comedi_dio_insn_config(struct comedi_device *dev, unsigned int *data, unsigned int mask) { @@ drivers/comedi/drivers.c: int comedi_dio_insn_config(struct comedi_device *dev,
switch (data[0]) { case INSN_CONFIG_DIO_INPUT: -@@ drivers/comedi/drivers.c: EXPORT_SYMBOL_GPL(comedi_dio_insn_config); +@@ drivers/staging/comedi/drivers.c: EXPORT_SYMBOL_GPL(comedi_dio_insn_config); unsigned int comedi_dio_update_state(struct comedi_subdevice *s, unsigned int *data) { @@ drivers/comedi/drivers.c: EXPORT_SYMBOL_GPL(comedi_dio_insn_config); : 0xffffffff; unsigned int mask = data[0] & chanmask; unsigned int bits = data[1]; -@@ drivers/comedi/drivers.c: static int insn_rw_emulate_bits(struct comedi_device *dev, +@@ drivers/staging/comedi/drivers.c: static int insn_rw_emulate_bits(struct comedi_device *dev, if (insn->insn == INSN_WRITE) { if (!(s->subdev_flags & SDF_WRITABLE)) return -EINVAL; @@ drivers/comedi/drivers.c: static int insn_rw_emulate_bits(struct comedi_device * }
ret = s->insn_bits(dev, s, &_insn, _data); -@@ drivers/comedi/drivers.c: static int __comedi_device_postconfig(struct comedi_device *dev) +@@ drivers/staging/comedi/drivers.c: static int __comedi_device_postconfig(struct comedi_device *dev)
if (s->type == COMEDI_SUBD_DO) { if (s->n_chan < 32)
---
Results of testing on various branches:
| Branch | Patch Apply | Build Test | |---------------------------|-------------|------------| | origin/linux-5.10.y | Success | Success |
[ Upstream commit ed93c6f68a3be06e4e0c331c6e751f462dee3932 ]
When checking for a supported IRQ number, the following test is used:
/* only irqs 2, 3, 4, 5, 6, 7, 10, 11, 12, 14, and 15 are valid */ if ((1 << it->options[1]) & 0xdcfc) {
However, `it->options[i]` is an unchecked `int` value from userspace, so the shift amount could be negative or out of bounds. Fix the test by requiring `it->options[1]` to be within bounds before proceeding with the original test.
Reported-by: syzbot+c52293513298e0fd9a94@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=c52293513298e0fd9a94 Fixes: 729988507680 ("staging: comedi: das16m1: tidy up the irq support in das16m1_attach()") Tested-by: syzbot+c52293513298e0fd9a94@syzkaller.appspotmail.com Suggested-by: "Enju, Kohei" enjuk@amazon.co.jp Cc: stable@vger.kernel.org # 5.13+ Signed-off-by: Ian Abbott abbotti@mev.co.uk Link: https://lore.kernel.org/r/20250707130908.70758-1-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/staging/comedi/drivers/das16m1.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index 75f3dbbe97ac..0d54387a1c26 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -523,7 +523,8 @@ static int das16m1_attach(struct comedi_device *dev, devpriv->extra_iobase = dev->iobase + DAS16M1_8255_IOBASE;
/* only irqs 2, 3, 4, 5, 6, 7, 10, 11, 12, 14, and 15 are valid */ - if ((1 << it->options[1]) & 0xdcfc) { + if (it->options[1] >= 2 && it->options[1] <= 15 && + (1 << it->options[1]) & 0xdcfc) { ret = request_irq(it->options[1], das16m1_interrupt, 0, dev->board_name, dev); if (ret == 0)
[ Sasha's backport helper bot ]
Hi,
✅ All tests passed successfully. No issues detected. No action required from the submitter.
The upstream commit SHA1 provided is correct: ed93c6f68a3be06e4e0c331c6e751f462dee3932
Status in newer kernel trees: 6.15.y | Not found 6.12.y | Not found 6.6.y | Not found 6.1.y | Not found 5.15.y | Not found
Note: The patch differs from the upstream commit: --- 1: ed93c6f68a3b ! 1: 866ef819f63e comedi: das16m1: Fix bit shift out of bounds @@ Metadata ## Commit message ## comedi: das16m1: Fix bit shift out of bounds
+ [ Upstream commit ed93c6f68a3be06e4e0c331c6e751f462dee3932 ] + When checking for a supported IRQ number, the following test is used:
/* only irqs 2, 3, 4, 5, 6, 7, 10, 11, 12, 14, and 15 are valid */ @@ Commit message Link: https://lore.kernel.org/r/20250707130908.70758-1-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
- ## drivers/comedi/drivers/das16m1.c ## -@@ drivers/comedi/drivers/das16m1.c: static int das16m1_attach(struct comedi_device *dev, + ## drivers/staging/comedi/drivers/das16m1.c ## +@@ drivers/staging/comedi/drivers/das16m1.c: static int das16m1_attach(struct comedi_device *dev, devpriv->extra_iobase = dev->iobase + DAS16M1_8255_IOBASE;
/* only irqs 2, 3, 4, 5, 6, 7, 10, 11, 12, 14, and 15 are valid */
---
Results of testing on various branches:
| Branch | Patch Apply | Build Test | |---------------------------|-------------|------------| | origin/linux-5.10.y | Success | Success |
[ Upstream commit b14b076ce593f72585412fc7fd3747e03a5e3632 ]
When checking for a supported IRQ number, the following test is used:
if ((1 << it->options[1]) & board->irq_bits) {
However, `it->options[i]` is an unchecked `int` value from userspace, so the shift amount could be negative or out of bounds. Fix the test by requiring `it->options[1]` to be within bounds before proceeding with the original test. Valid `it->options[1]` values that select the IRQ will be in the range [1,15]. The value 0 explicitly disables the use of interrupts.
Reported-by: syzbot+32de323b0addb9e114ff@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=32de323b0addb9e114ff Fixes: fcdb427bc7cf ("Staging: comedi: add pcl821 driver") Cc: stable@vger.kernel.org # 5.13+ Signed-off-by: Ian Abbott abbotti@mev.co.uk Link: https://lore.kernel.org/r/20250707133429.73202-1-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/staging/comedi/drivers/pcl812.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c index b87ab3840eee..fc06f284ba74 100644 --- a/drivers/staging/comedi/drivers/pcl812.c +++ b/drivers/staging/comedi/drivers/pcl812.c @@ -1151,7 +1151,8 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (!dev->pacer) return -ENOMEM;
- if ((1 << it->options[1]) & board->irq_bits) { + if (it->options[1] > 0 && it->options[1] < 16 && + (1 << it->options[1]) & board->irq_bits) { ret = request_irq(it->options[1], pcl812_interrupt, 0, dev->board_name, dev); if (ret == 0)
[ Sasha's backport helper bot ]
Hi,
✅ All tests passed successfully. No issues detected. No action required from the submitter.
The upstream commit SHA1 provided is correct: b14b076ce593f72585412fc7fd3747e03a5e3632
Status in newer kernel trees: 6.15.y | Not found 6.12.y | Not found 6.6.y | Not found 6.1.y | Not found 5.15.y | Not found
Note: The patch differs from the upstream commit: --- 1: b14b076ce593 ! 1: b9004585cda3 comedi: pcl812: Fix bit shift out of bounds @@ Metadata ## Commit message ## comedi: pcl812: Fix bit shift out of bounds
+ [ Upstream commit b14b076ce593f72585412fc7fd3747e03a5e3632 ] + When checking for a supported IRQ number, the following test is used:
if ((1 << it->options[1]) & board->irq_bits) { @@ Commit message Link: https://lore.kernel.org/r/20250707133429.73202-1-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
- ## drivers/comedi/drivers/pcl812.c ## -@@ drivers/comedi/drivers/pcl812.c: static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it) - if (IS_ERR(dev->pacer)) - return PTR_ERR(dev->pacer); + ## drivers/staging/comedi/drivers/pcl812.c ## +@@ drivers/staging/comedi/drivers/pcl812.c: static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it) + if (!dev->pacer) + return -ENOMEM;
- if ((1 << it->options[1]) & board->irq_bits) { + if (it->options[1] > 0 && it->options[1] < 16 &&
---
Results of testing on various branches:
| Branch | Patch Apply | Build Test | |---------------------------|-------------|------------| | origin/linux-5.10.y | Success | Success |
When checking for a supported IRQ number, the following test is used:
if ((1 << it->options[1]) & 0xdcfc) {
However, `it->options[i]` is an unchecked `int` value from userspace, so the shift amount could be negative or out of bounds. Fix the test by requiring `it->options[1]` to be within bounds before proceeding with the original test. Valid `it->options[1]` values that select the IRQ will be in the range [1,15]. The value 0 explicitly disables the use of interrupts.
Fixes: ad7a370c8be4 ("staging: comedi: aio_iiro_16: add command support for change of state detection") Cc: stable@vger.kernel.org # 5.13+ Signed-off-by: Ian Abbott abbotti@mev.co.uk Link: https://lore.kernel.org/r/20250707134622.75403-1-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/staging/comedi/drivers/aio_iiro_16.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/staging/comedi/drivers/aio_iiro_16.c b/drivers/staging/comedi/drivers/aio_iiro_16.c index fe3876235075..60c9c683906b 100644 --- a/drivers/staging/comedi/drivers/aio_iiro_16.c +++ b/drivers/staging/comedi/drivers/aio_iiro_16.c @@ -178,7 +178,8 @@ static int aio_iiro_16_attach(struct comedi_device *dev, * Digital input change of state interrupts are optionally supported * using IRQ 2-7, 10-12, 14, or 15. */ - if ((1 << it->options[1]) & 0xdcfc) { + if (it->options[1] > 0 && it->options[1] < 16 && + (1 << it->options[1]) & 0xdcfc) { ret = request_irq(it->options[1], aio_iiro_16_cos, 0, dev->board_name, dev); if (ret == 0)
[ Sasha's backport helper bot ]
Hi,
✅ All tests passed successfully. No issues detected. No action required from the submitter.
Found matching upstream commit: 66acb1586737a22dd7b78abc63213b1bcaa100e4
Status in newer kernel trees: 6.15.y | Not found 6.12.y | Not found 6.6.y | Not found 6.1.y | Not found 5.15.y | Not found
Note: The patch differs from the upstream commit: --- 1: 66acb1586737 ! 1: 050bb07db030 comedi: aio_iiro_16: Fix bit shift out of bounds @@ Commit message Link: https://lore.kernel.org/r/20250707134622.75403-1-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
- ## drivers/comedi/drivers/aio_iiro_16.c ## -@@ drivers/comedi/drivers/aio_iiro_16.c: static int aio_iiro_16_attach(struct comedi_device *dev, + ## drivers/staging/comedi/drivers/aio_iiro_16.c ## +@@ drivers/staging/comedi/drivers/aio_iiro_16.c: static int aio_iiro_16_attach(struct comedi_device *dev, * Digital input change of state interrupts are optionally supported * using IRQ 2-7, 10-12, 14, or 15. */
---
Results of testing on various branches:
| Branch | Patch Apply | Build Test | |---------------------------|-------------|------------| | origin/linux-5.10.y | Success | Success |
[ Upstream commit 70f2b28b5243df557f51c054c20058ae207baaac ]
When checking for a supported IRQ number, the following test is used:
/* IRQs 2,3,5,6,7, 10,11,15 are valid for "enhanced" mode */ if ((1 << it->options[1]) & 0x8cec) {
However, `it->options[i]` is an unchecked `int` value from userspace, so the shift amount could be negative or out of bounds. Fix the test by requiring `it->options[1]` to be within bounds before proceeding with the original test. Valid `it->options[1]` values that select the IRQ will be in the range [1,15]. The value 0 explicitly disables the use of interrupts.
Fixes: 79e5e6addbb1 ("staging: comedi: das6402: rewrite broken driver") Cc: stable@vger.kernel.org # 5.13+ Signed-off-by: Ian Abbott abbotti@mev.co.uk Link: https://lore.kernel.org/r/20250707135737.77448-1-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/staging/comedi/drivers/das6402.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c index 96f4107b8054..927d4b832ecc 100644 --- a/drivers/staging/comedi/drivers/das6402.c +++ b/drivers/staging/comedi/drivers/das6402.c @@ -569,7 +569,8 @@ static int das6402_attach(struct comedi_device *dev, das6402_reset(dev);
/* IRQs 2,3,5,6,7, 10,11,15 are valid for "enhanced" mode */ - if ((1 << it->options[1]) & 0x8cec) { + if (it->options[1] > 0 && it->options[1] < 16 && + (1 << it->options[1]) & 0x8cec) { ret = request_irq(it->options[1], das6402_interrupt, 0, dev->board_name, dev); if (ret == 0) {
[ Sasha's backport helper bot ]
Hi,
✅ All tests passed successfully. No issues detected. No action required from the submitter.
The upstream commit SHA1 provided is correct: 70f2b28b5243df557f51c054c20058ae207baaac
Status in newer kernel trees: 6.15.y | Not found 6.12.y | Not found 6.6.y | Not found 6.1.y | Not found 5.15.y | Not found
Note: The patch differs from the upstream commit: --- 1: 70f2b28b5243 ! 1: dee1eb300666 comedi: das6402: Fix bit shift out of bounds @@ Metadata ## Commit message ## comedi: das6402: Fix bit shift out of bounds
+ [ Upstream commit 70f2b28b5243df557f51c054c20058ae207baaac ] + When checking for a supported IRQ number, the following test is used:
/* IRQs 2,3,5,6,7, 10,11,15 are valid for "enhanced" mode */ @@ Commit message Link: https://lore.kernel.org/r/20250707135737.77448-1-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
- ## drivers/comedi/drivers/das6402.c ## -@@ drivers/comedi/drivers/das6402.c: static int das6402_attach(struct comedi_device *dev, + ## drivers/staging/comedi/drivers/das6402.c ## +@@ drivers/staging/comedi/drivers/das6402.c: static int das6402_attach(struct comedi_device *dev, das6402_reset(dev);
/* IRQs 2,3,5,6,7, 10,11,15 are valid for "enhanced" mode */
---
Results of testing on various branches:
| Branch | Patch Apply | Build Test | |---------------------------|-------------|------------| | origin/linux-5.10.y | Success | Success |
[ Upstream commit e9cb26291d009243a4478a7ffb37b3a9175bfce9 ]
For Comedi `INSN_READ` and `INSN_WRITE` instructions on "digital" subdevices (subdevice types `COMEDI_SUBD_DI`, `COMEDI_SUBD_DO`, and `COMEDI_SUBD_DIO`), it is common for the subdevice driver not to have `insn_read` and `insn_write` handler functions, but to have an `insn_bits` handler function for handling Comedi `INSN_BITS` instructions. In that case, the subdevice's `insn_read` and/or `insn_write` function handler pointers are set to point to the `insn_rw_emulate_bits()` function by `__comedi_device_postconfig()`.
For `INSN_WRITE`, `insn_rw_emulate_bits()` currently assumes that the supplied `data[0]` value is a valid copy from user memory. It will at least exist because `do_insnlist_ioctl()` and `do_insn_ioctl()` in "comedi_fops.c" ensure at lease `MIN_SAMPLES` (16) elements are allocated. However, if `insn->n` is 0 (which is allowable for `INSN_READ` and `INSN_WRITE` instructions, then `data[0]` may contain uninitialized data, and certainly contains invalid data, possibly from a different instruction in the array of instructions handled by `do_insnlist_ioctl()`. This will result in an incorrect value being written to the digital output channel (or to the digital input/output channel if configured as an output), and may be reflected in the internal saved state of the channel.
Fix it by returning 0 early if `insn->n` is 0, before reaching the code that accesses `data[0]`. Previously, the function always returned 1 on success, but it is supposed to be the number of data samples actually read or written up to `insn->n`, which is 0 in this case.
Reported-by: syzbot+cb96ec476fb4914445c9@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=cb96ec476fb4914445c9 Fixes: ed9eccbe8970 ("Staging: add comedi core") Cc: stable@vger.kernel.org # 5.13+ Signed-off-by: Ian Abbott abbotti@mev.co.uk Link: https://lore.kernel.org/r/20250707153355.82474-1-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/staging/comedi/drivers.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c index 6bb7b8a1e75d..ced660663f0d 100644 --- a/drivers/staging/comedi/drivers.c +++ b/drivers/staging/comedi/drivers.c @@ -615,6 +615,9 @@ static int insn_rw_emulate_bits(struct comedi_device *dev, unsigned int _data[2]; int ret;
+ if (insn->n == 0) + return 0; + memset(_data, 0, sizeof(_data)); memset(&_insn, 0, sizeof(_insn)); _insn.insn = INSN_BITS;
[ Sasha's backport helper bot ]
Hi,
✅ All tests passed successfully. No issues detected. No action required from the submitter.
The upstream commit SHA1 provided is correct: e9cb26291d009243a4478a7ffb37b3a9175bfce9
Status in newer kernel trees: 6.15.y | Not found 6.12.y | Not found 6.6.y | Not found 6.1.y | Not found 5.15.y | Not found
Note: The patch differs from the upstream commit: --- 1: e9cb26291d00 ! 1: 8bad4aa45706 comedi: Fix use of uninitialized data in insn_rw_emulate_bits() @@ Metadata ## Commit message ## comedi: Fix use of uninitialized data in insn_rw_emulate_bits()
+ [ Upstream commit e9cb26291d009243a4478a7ffb37b3a9175bfce9 ] + For Comedi `INSN_READ` and `INSN_WRITE` instructions on "digital" subdevices (subdevice types `COMEDI_SUBD_DI`, `COMEDI_SUBD_DO`, and `COMEDI_SUBD_DIO`), it is common for the subdevice driver not to have @@ Commit message Link: https://lore.kernel.org/r/20250707153355.82474-1-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
- ## drivers/comedi/drivers.c ## -@@ drivers/comedi/drivers.c: static int insn_rw_emulate_bits(struct comedi_device *dev, + ## drivers/staging/comedi/drivers.c ## +@@ drivers/staging/comedi/drivers.c: static int insn_rw_emulate_bits(struct comedi_device *dev, unsigned int _data[2]; int ret;
---
Results of testing on various branches:
| Branch | Patch Apply | Build Test | |---------------------------|-------------|------------| | origin/linux-5.10.y | Success | Success |
[ Upstream commit 46d8c744136ce2454aa4c35c138cc06817f92b8e ]
Some Comedi subdevice instruction handlers are known to access instruction data elements beyond the first `insn->n` elements in some cases. The `do_insn_ioctl()` and `do_insnlist_ioctl()` functions allocate at least `MIN_SAMPLES` (16) data elements to deal with this, but they do not initialize all of that. For Comedi instruction codes that write to the subdevice, the first `insn->n` data elements are copied from user-space, but the remaining elements are left uninitialized. That could be a problem if the subdevice instruction handler reads the uninitialized data. Ensure that the first `MIN_SAMPLES` elements are initialized before calling these instruction handlers, filling the uncopied elements with 0. For `do_insnlist_ioctl()`, the same data buffer elements are used for handling a list of instructions, so ensure the first `MIN_SAMPLES` elements are initialized for each instruction that writes to the subdevice.
Fixes: ed9eccbe8970 ("Staging: add comedi core") Cc: stable@vger.kernel.org # 5.13+ Signed-off-by: Ian Abbott abbotti@mev.co.uk Link: https://lore.kernel.org/r/20250707161439.88385-1-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/staging/comedi/comedi_fops.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 5aa6a84d1fa6..96d68cc8f449 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -1551,21 +1551,27 @@ static int do_insnlist_ioctl(struct comedi_device *dev, }
for (i = 0; i < n_insns; ++i) { + unsigned int n = insns[i].n; + if (insns[i].insn & INSN_MASK_WRITE) { if (copy_from_user(data, insns[i].data, - insns[i].n * sizeof(unsigned int))) { + n * sizeof(unsigned int))) { dev_dbg(dev->class_dev, "copy_from_user failed\n"); ret = -EFAULT; goto error; } + if (n < MIN_SAMPLES) { + memset(&data[n], 0, (MIN_SAMPLES - n) * + sizeof(unsigned int)); + } } ret = parse_insn(dev, insns + i, data, file); if (ret < 0) goto error; if (insns[i].insn & INSN_MASK_READ) { if (copy_to_user(insns[i].data, data, - insns[i].n * sizeof(unsigned int))) { + n * sizeof(unsigned int))) { dev_dbg(dev->class_dev, "copy_to_user failed\n"); ret = -EFAULT; @@ -1638,6 +1644,10 @@ static int do_insn_ioctl(struct comedi_device *dev, ret = -EFAULT; goto error; } + if (insn->n < MIN_SAMPLES) { + memset(&data[insn->n], 0, + (MIN_SAMPLES - insn->n) * sizeof(unsigned int)); + } } ret = parse_insn(dev, insn, data, file); if (ret < 0)
[ Sasha's backport helper bot ]
Hi,
✅ All tests passed successfully. No issues detected. No action required from the submitter.
The upstream commit SHA1 provided is correct: 46d8c744136ce2454aa4c35c138cc06817f92b8e
Status in newer kernel trees: 6.15.y | Not found 6.12.y | Not found 6.6.y | Not found 6.1.y | Not found 5.15.y | Not found
Note: The patch differs from the upstream commit: --- 1: 46d8c744136c ! 1: b96c24925413 comedi: Fix initialization of data for instructions that write to subdevice @@ Metadata ## Commit message ## comedi: Fix initialization of data for instructions that write to subdevice
+ [ Upstream commit 46d8c744136ce2454aa4c35c138cc06817f92b8e ] + Some Comedi subdevice instruction handlers are known to access instruction data elements beyond the first `insn->n` elements in some cases. The `do_insn_ioctl()` and `do_insnlist_ioctl()` functions @@ Commit message Link: https://lore.kernel.org/r/20250707161439.88385-1-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
- ## drivers/comedi/comedi_fops.c ## -@@ drivers/comedi/comedi_fops.c: static int do_insnlist_ioctl(struct comedi_device *dev, + ## drivers/staging/comedi/comedi_fops.c ## +@@ drivers/staging/comedi/comedi_fops.c: static int do_insnlist_ioctl(struct comedi_device *dev, }
for (i = 0; i < n_insns; ++i) { @@ drivers/comedi/comedi_fops.c: static int do_insnlist_ioctl(struct comedi_device dev_dbg(dev->class_dev, "copy_to_user failed\n"); ret = -EFAULT; -@@ drivers/comedi/comedi_fops.c: static int do_insn_ioctl(struct comedi_device *dev, +@@ drivers/staging/comedi/comedi_fops.c: static int do_insn_ioctl(struct comedi_device *dev, ret = -EFAULT; goto error; }
---
Results of testing on various branches:
| Branch | Patch Apply | Build Test | |---------------------------|-------------|------------| | origin/linux-5.10.y | Success | Success |
[ Upstream commit 1b98304c09a0192598d0767f1eb8c83d7e793091 ]
In `waveform_common_attach()`, the two timers `&devpriv->ai_timer` and `&devpriv->ao_timer` are initialized after the allocation of the device private data by `comedi_alloc_devpriv()` and the subdevices by `comedi_alloc_subdevices()`. The function may return with an error between those function calls. In that case, `waveform_detach()` will be called by the Comedi core to clean up. The check that `waveform_detach()` uses to decide whether to delete the timers is incorrect. It only checks that the device private data was allocated, but that does not guarantee that the timers were initialized. It also needs to check that the subdevices were allocated. Fix it.
Fixes: 73e0e4dfed4c ("staging: comedi: comedi_test: fix timer lock-up") Cc: stable@vger.kernel.org # 6.15+ Signed-off-by: Ian Abbott abbotti@mev.co.uk Link: https://lore.kernel.org/r/20250708130627.21743-1-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org [ changed timer_delete_sync() to del_timer_sync() ] Signed-off-by: Ian Abbott abbotti@mev.co.uk --- drivers/staging/comedi/drivers/comedi_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c index bea9a3adf08c..f5199474c0e9 100644 --- a/drivers/staging/comedi/drivers/comedi_test.c +++ b/drivers/staging/comedi/drivers/comedi_test.c @@ -790,7 +790,7 @@ static void waveform_detach(struct comedi_device *dev) { struct waveform_private *devpriv = dev->private;
- if (devpriv) { + if (devpriv && dev->n_subdevices) { del_timer_sync(&devpriv->ai_timer); del_timer_sync(&devpriv->ao_timer); }
[ Sasha's backport helper bot ]
Hi,
✅ All tests passed successfully. No issues detected. No action required from the submitter.
The upstream commit SHA1 provided is correct: 1b98304c09a0192598d0767f1eb8c83d7e793091
Status in newer kernel trees: 6.15.y | Not found 6.12.y | Not found 6.6.y | Not found 6.1.y | Not found 5.15.y | Not found
Note: The patch differs from the upstream commit: --- 1: 1b98304c09a0 < -: ------------ comedi: comedi_test: Fix possible deletion of uninitialized timers -: ------------ > 1: 670acfccefbe comedi: comedi_test: Fix possible deletion of uninitialized timers
---
Results of testing on various branches:
| Branch | Patch Apply | Build Test | |---------------------------|-------------|------------| | origin/linux-5.10.y | Success | Success |
[ Sasha's backport helper bot ]
Hi,
✅ All tests passed successfully. No issues detected. No action required from the submitter.
The upstream commit SHA1 provided is correct: 08ae4b20f5e82101d77326ecab9089e110f224cc
Status in newer kernel trees: 6.15.y | Not found 6.12.y | Not found 6.6.y | Not found 6.1.y | Not found 5.15.y | Not found
Note: The patch differs from the upstream commit: --- 1: 08ae4b20f5e8 ! 1: 973ce1afed22 comedi: Fail COMEDI_INSNLIST ioctl if n_insns is too large @@ Metadata ## Commit message ## comedi: Fail COMEDI_INSNLIST ioctl if n_insns is too large
+ [ Upstream commit 08ae4b20f5e82101d77326ecab9089e110f224cc ] + The handling of the `COMEDI_INSNLIST` ioctl allocates a kernel buffer to hold the array of `struct comedi_insn`, getting the length from the `n_insns` member of the `struct comedi_insnlist` supplied by the user. @@ Commit message Link: https://lore.kernel.org/r/20250704120405.83028-1-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
- ## drivers/comedi/comedi_fops.c ## -@@ drivers/comedi/comedi_fops.c: static int do_insnlist_ioctl(struct comedi_device *dev, + ## drivers/staging/comedi/comedi_fops.c ## +@@ drivers/staging/comedi/comedi_fops.c: static int do_insnlist_ioctl(struct comedi_device *dev, return i; }
@@ drivers/comedi/comedi_fops.c: static int do_insnlist_ioctl(struct comedi_device /* * COMEDI_INSN ioctl * synchronous instruction -@@ drivers/comedi/comedi_fops.c: static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd, +@@ drivers/staging/comedi/comedi_fops.c: static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd, rc = -EFAULT; break; } @@ drivers/comedi/comedi_fops.c: static long comedi_unlocked_ioctl(struct file *fil insns = kcalloc(insnlist.n_insns, sizeof(*insns), GFP_KERNEL); if (!insns) { rc = -ENOMEM; -@@ drivers/comedi/comedi_fops.c: static int compat_insnlist(struct file *file, unsigned long arg) +@@ drivers/staging/comedi/comedi_fops.c: static int compat_insnlist(struct file *file, unsigned long arg) if (copy_from_user(&insnlist32, compat_ptr(arg), sizeof(insnlist32))) return -EFAULT;
---
Results of testing on various branches:
| Branch | Patch Apply | Build Test | |---------------------------|-------------|------------| | origin/linux-5.10.y | Success | Success |
linux-stable-mirror@lists.linaro.org