Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

H Hartley Sweeten and committed by
Greg Kroah-Hartman
1f5cc359 94174847

+7 -7
+7 -7
drivers/staging/comedi/kcomedilib/kcomedilib_main.c
··· 80 80 } 81 81 EXPORT_SYMBOL(comedi_close); 82 82 83 - static int comedi_do_insn(struct comedi_device *dev, struct comedi_insn *insn) 83 + static int comedi_do_insn(struct comedi_device *dev, 84 + struct comedi_insn *insn, 85 + unsigned int *data) 84 86 { 85 87 struct comedi_subdevice *s; 86 88 int ret = 0; ··· 117 115 118 116 switch (insn->insn) { 119 117 case INSN_BITS: 120 - ret = s->insn_bits(dev, s, insn, insn->data); 118 + ret = s->insn_bits(dev, s, insn, data); 121 119 break; 122 120 case INSN_CONFIG: 123 121 /* XXX should check instruction length */ 124 - ret = s->insn_config(dev, s, insn, insn->data); 122 + ret = s->insn_config(dev, s, insn, data); 125 123 break; 126 124 default: 127 125 ret = -EINVAL; ··· 142 140 memset(&insn, 0, sizeof(insn)); 143 141 insn.insn = INSN_CONFIG; 144 142 insn.n = 1; 145 - insn.data = &io; 146 143 insn.subdev = subdev; 147 144 insn.chanspec = CR_PACK(chan, 0, 0); 148 145 149 - return comedi_do_insn(dev, &insn); 146 + return comedi_do_insn(dev, &insn, &io); 150 147 } 151 148 EXPORT_SYMBOL(comedi_dio_config); 152 149 ··· 159 158 memset(&insn, 0, sizeof(insn)); 160 159 insn.insn = INSN_BITS; 161 160 insn.n = 2; 162 - insn.data = data; 163 161 insn.subdev = subdev; 164 162 165 163 data[0] = mask; 166 164 data[1] = *bits; 167 165 168 - ret = comedi_do_insn(dev, &insn); 166 + ret = comedi_do_insn(dev, &insn, data); 169 167 170 168 *bits = data[1]; 171 169