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: H Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
H Hartley Sweeten 2012-09-19 17:26:53 -07:00 committed by Greg Kroah-Hartman
parent 94174847ea
commit 1f5cc35915

View file

@ -80,7 +80,9 @@ int comedi_close(struct comedi_device *d)
}
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;
int ret = 0;
@ -115,11 +117,11 @@ static int comedi_do_insn(struct comedi_device *dev, struct comedi_insn *insn)
switch (insn->insn) {
case INSN_BITS:
ret = s->insn_bits(dev, s, insn, insn->data);
ret = s->insn_bits(dev, s, insn, data);
break;
case INSN_CONFIG:
/* XXX should check instruction length */
ret = s->insn_config(dev, s, insn, insn->data);
ret = s->insn_config(dev, s, insn, data);
break;
default:
ret = -EINVAL;
@ -140,11 +142,10 @@ int comedi_dio_config(struct comedi_device *dev, unsigned int subdev,
memset(&insn, 0, sizeof(insn));
insn.insn = INSN_CONFIG;
insn.n = 1;
insn.data = &io;
insn.subdev = subdev;
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);
@ -158,13 +159,12 @@ int comedi_dio_bitfield(struct comedi_device *dev, unsigned int subdev,
memset(&insn, 0, sizeof(insn));
insn.insn = INSN_BITS;
insn.n = 2;
insn.data = data;
insn.subdev = subdev;
data[0] = mask;
data[1] = *bits;
ret = comedi_do_insn(dev, &insn);
ret = comedi_do_insn(dev, &insn, data);
*bits = data[1];