Commit 1f5cc359 authored by H Hartley Sweeten's avatar H Hartley Sweeten Committed by Greg Kroah-Hartman

staging: comedi: kcomedilib: fix a __user space access issue

The 'data' field in struct comedi_insn is an unsigned int __user *.
The comedi core copies this data to kernel space before passing it
on to a drivers insn_bits/insn_config method.

kcomedilib provides an interface for external kernel modules to
use the comedi drivers. This interface creates a comedi_insn
that is then passed to the comedi drivers insn_bits/insn_config
method. Unfortunately, kcomedilib is using the comedi_insn 'data'
field directly which results in some sparse warnings:

  warning: incorrect type in argument 4 (different address spaces)
     expected unsigned int *<noident>
     got unsigned int [noderef] <asn:1>*data

  warning: incorrect type in assignment (different address spaces)
     expected unsigned int [noderef] <asn:1>*[addressable] [assigned] data
     got unsigned int *<noident>

Fix this by passing the kernel data directly, as a separate parameter,
instead of trying to put in into the comedi_insn 'data' field. This is
how the comedi core handles the data from user space.
Signed-off-by: default avatarH Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 94174847
...@@ -80,7 +80,9 @@ int comedi_close(struct comedi_device *d) ...@@ -80,7 +80,9 @@ int comedi_close(struct comedi_device *d)
} }
EXPORT_SYMBOL(comedi_close); EXPORT_SYMBOL(comedi_close);
static int comedi_do_insn(struct comedi_device *dev, struct comedi_insn *insn) static int comedi_do_insn(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{ {
struct comedi_subdevice *s; struct comedi_subdevice *s;
int ret = 0; int ret = 0;
...@@ -115,11 +117,11 @@ static int comedi_do_insn(struct comedi_device *dev, struct comedi_insn *insn) ...@@ -115,11 +117,11 @@ static int comedi_do_insn(struct comedi_device *dev, struct comedi_insn *insn)
switch (insn->insn) { switch (insn->insn) {
case INSN_BITS: case INSN_BITS:
ret = s->insn_bits(dev, s, insn, insn->data); ret = s->insn_bits(dev, s, insn, data);
break; break;
case INSN_CONFIG: case INSN_CONFIG:
/* XXX should check instruction length */ /* XXX should check instruction length */
ret = s->insn_config(dev, s, insn, insn->data); ret = s->insn_config(dev, s, insn, data);
break; break;
default: default:
ret = -EINVAL; ret = -EINVAL;
...@@ -140,11 +142,10 @@ int comedi_dio_config(struct comedi_device *dev, unsigned int subdev, ...@@ -140,11 +142,10 @@ int comedi_dio_config(struct comedi_device *dev, unsigned int subdev,
memset(&insn, 0, sizeof(insn)); memset(&insn, 0, sizeof(insn));
insn.insn = INSN_CONFIG; insn.insn = INSN_CONFIG;
insn.n = 1; insn.n = 1;
insn.data = &io;
insn.subdev = subdev; insn.subdev = subdev;
insn.chanspec = CR_PACK(chan, 0, 0); insn.chanspec = CR_PACK(chan, 0, 0);
return comedi_do_insn(dev, &insn); return comedi_do_insn(dev, &insn, &io);
} }
EXPORT_SYMBOL(comedi_dio_config); EXPORT_SYMBOL(comedi_dio_config);
...@@ -158,13 +159,12 @@ int comedi_dio_bitfield(struct comedi_device *dev, unsigned int subdev, ...@@ -158,13 +159,12 @@ int comedi_dio_bitfield(struct comedi_device *dev, unsigned int subdev,
memset(&insn, 0, sizeof(insn)); memset(&insn, 0, sizeof(insn));
insn.insn = INSN_BITS; insn.insn = INSN_BITS;
insn.n = 2; insn.n = 2;
insn.data = data;
insn.subdev = subdev; insn.subdev = subdev;
data[0] = mask; data[0] = mask;
data[1] = *bits; data[1] = *bits;
ret = comedi_do_insn(dev, &insn); ret = comedi_do_insn(dev, &insn, data);
*bits = data[1]; *bits = data[1];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment