[PATCH] staging: comedi: kcomedilib: fix a __user space access issue

H Hartley Sweeten hartleys at visionengravers.com
Thu Sep 20 00:26:53 UTC 2012


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 at visionengravers.com>
Cc: Ian Abbott <abbotti at mev.co.uk>
Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
---
 drivers/staging/comedi/kcomedilib/kcomedilib_main.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
index f96416d..3f20ea5 100644
--- a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
+++ b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
@@ -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];
 
-- 
1.7.11




More information about the devel mailing list