Skip to content

Commit

Permalink
staging: comedi: kcomedilib: fix a __user space access issue
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
H Hartley Sweeten authored and Greg Kroah-Hartman committed Sep 21, 2012
1 parent 9417484 commit 1f5cc35
Showing 1 changed file with 7 additions and 7 deletions.
14 changes: 7 additions & 7 deletions drivers/staging/comedi/kcomedilib/kcomedilib_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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);

Expand All @@ -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];

Expand Down

0 comments on commit 1f5cc35

Please sign in to comment.