diff mbox

[05/12] usb: usbtmc: Add ioctl for generic requests on control pipe

Message ID 20180517170336.8426-6-guido@kiener-muenchen.de (mailing list archive)
State New, archived
Headers show

Commit Message

Guido Kiener May 17, 2018, 5:03 p.m. UTC
Add USBTMC_IOCTL_CTRL_REQUEST to send arbitrary requests on the
control pipe.  Used by specific applications of IVI Foundation,
Inc. to implement VISA API functions: viUsbControlIn/Out.

Signed-off-by: Guido Kiener <guido.kiener@rohde-schwarz.com>
Reviewed-by: Steve Bayless <steve_bayless@keysight.com>
---
 drivers/usb/class/usbtmc.c   | 61 ++++++++++++++++++++++++++++++++++++
 include/uapi/linux/usb/tmc.h | 15 +++++++++
 2 files changed, 76 insertions(+)

Comments

Greg KH May 18, 2018, 12:42 p.m. UTC | #1
On Thu, May 17, 2018 at 07:03:29PM +0200, Guido Kiener wrote:
> Add USBTMC_IOCTL_CTRL_REQUEST to send arbitrary requests on the
> control pipe.  Used by specific applications of IVI Foundation,
> Inc. to implement VISA API functions: viUsbControlIn/Out.
> 
> Signed-off-by: Guido Kiener <guido.kiener@rohde-schwarz.com>
> Reviewed-by: Steve Bayless <steve_bayless@keysight.com>
> ---
>  drivers/usb/class/usbtmc.c   | 61 ++++++++++++++++++++++++++++++++++++
>  include/uapi/linux/usb/tmc.h | 15 +++++++++
>  2 files changed, 76 insertions(+)
> 
> diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
> index 152e2daa9644..00c2e51a23a7 100644
> --- a/drivers/usb/class/usbtmc.c
> +++ b/drivers/usb/class/usbtmc.c
> @@ -5,6 +5,7 @@
>   * Copyright (C) 2007 Stefan Kopp, Gechingen, Germany
>   * Copyright (C) 2008 Novell, Inc.
>   * Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de>
> + * Copyright (C) 2018, IVI Foundation, Inc.
>   */
>  
>  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> @@ -1263,6 +1264,62 @@ static int usbtmc_ioctl_indicator_pulse(struct usbtmc_device_data *data)
>  	return rv;
>  }
>  
> +static int usbtmc_ioctl_request(struct usbtmc_device_data *data,
> +				void __user *arg)
> +{
> +	struct device *dev = &data->intf->dev;
> +	struct usbtmc_ctrlrequest request;
> +	u8 *buffer = NULL;
> +	int rv;
> +	unsigned long res;
> +
> +	res = copy_from_user(&request, arg, sizeof(struct usbtmc_ctrlrequest));
> +	if (res)
> +		return -EFAULT;
> +
> +	buffer = kmalloc(min_t(u16, 256, request.req.wLength), GFP_KERNEL);

No validation that wLength is a sane number?

Go to the whiteboard nearby and write a the top of it:
	ALL INPUT IS EVIL

> +	if (!buffer)
> +		return -ENOMEM;
> +
> +	if ((request.req.bRequestType & USB_DIR_IN) == 0
> +	    && request.req.wLength) {
> +		res = copy_from_user(buffer, request.data,
> +				     request.req.wLength);
> +		if (res) {
> +			rv = -EFAULT;
> +			goto exit;
> +		}
> +	}
> +
> +	rv = usb_control_msg(data->usb_dev,
> +			usb_rcvctrlpipe(data->usb_dev, 0),
> +			request.req.bRequest,
> +			request.req.bRequestType,
> +			request.req.wValue,
> +			request.req.wIndex,
> +			buffer, request.req.wLength, USB_CTRL_GET_TIMEOUT);

request.req.wLength might not be the actual size of buffer here due to
your above min_t() check.

> +
> +	if (rv < 0) {
> +		dev_err(dev, "%s failed %d\n", __func__, rv);
> +		goto exit;
> +	}
> +	if ((request.req.bRequestType & USB_DIR_IN)) {
> +		if (rv > request.req.wLength) {
> +			dev_warn(dev, "%s returned too much data: %d\n",
> +				 __func__, rv);
> +			rv = request.req.wLength;

Why are you returning a value that is greater than the size asked for?
That's going to make userspace confused.

Then there is the generic question of "why are you allowing arbitrary
USB control messages to be sent to devices" here.  That feels like a
very odd way for a device that is supposed to be following a standard to
be working.  You are circumventing the standard here by allowing any
message to be sent to the device.  While nice for that one type of
device, you are breaking interoperability in horrible ways (now apps
only work with one type of device.)

Why did you all agree to allow this to happen?

thanks,

greg k-h
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Guido Kiener May 18, 2018, 1:32 p.m. UTC | #2
Zitat von Greg KH <gregkh@linuxfoundation.org>:

> On Thu, May 17, 2018 at 07:03:29PM +0200, Guido Kiener wrote:
>> Add USBTMC_IOCTL_CTRL_REQUEST to send arbitrary requests on the
>> control pipe.  Used by specific applications of IVI Foundation,
>> Inc. to implement VISA API functions: viUsbControlIn/Out.
>>
>> Signed-off-by: Guido Kiener <guido.kiener@rohde-schwarz.com>
>> Reviewed-by: Steve Bayless <steve_bayless@keysight.com>
>> ---
>>  drivers/usb/class/usbtmc.c   | 61 ++++++++++++++++++++++++++++++++++++
>>  include/uapi/linux/usb/tmc.h | 15 +++++++++
>>  2 files changed, 76 insertions(+)
>>
>> diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
>> index 152e2daa9644..00c2e51a23a7 100644
>> --- a/drivers/usb/class/usbtmc.c
>> +++ b/drivers/usb/class/usbtmc.c
>> @@ -5,6 +5,7 @@
>>   * Copyright (C) 2007 Stefan Kopp, Gechingen, Germany
>>   * Copyright (C) 2008 Novell, Inc.
>>   * Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de>
>> + * Copyright (C) 2018, IVI Foundation, Inc.
>>   */
>>
>>  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>> @@ -1263,6 +1264,62 @@ static int  
>> usbtmc_ioctl_indicator_pulse(struct usbtmc_device_data *data)
>>  	return rv;
>>  }
>>
>> +static int usbtmc_ioctl_request(struct usbtmc_device_data *data,
>> +				void __user *arg)
>> +{
>> +	struct device *dev = &data->intf->dev;
>> +	struct usbtmc_ctrlrequest request;
>> +	u8 *buffer = NULL;
>> +	int rv;
>> +	unsigned long res;
>> +
>> +	res = copy_from_user(&request, arg, sizeof(struct usbtmc_ctrlrequest));
>> +	if (res)
>> +		return -EFAULT;
>> +
>> +	buffer = kmalloc(min_t(u16, 256, request.req.wLength), GFP_KERNEL);
>
> No validation that wLength is a sane number?

Ooops. It should be buffer = kmalloc(max_t(u16, 256,  
request.req.wLength), GFP_KERNEL);
Then all values of request.req.wLength (0..65535) are ok.

>
> Go to the whiteboard nearby and write a the top of it:
> 	ALL INPUT IS EVIL
>
>> +	if (!buffer)
>> +		return -ENOMEM;
>> +
>> +	if ((request.req.bRequestType & USB_DIR_IN) == 0
>> +	    && request.req.wLength) {
>> +		res = copy_from_user(buffer, request.data,
>> +				     request.req.wLength);
>> +		if (res) {
>> +			rv = -EFAULT;
>> +			goto exit;
>> +		}
>> +	}
>> +
>> +	rv = usb_control_msg(data->usb_dev,
>> +			usb_rcvctrlpipe(data->usb_dev, 0),
>> +			request.req.bRequest,
>> +			request.req.bRequestType,
>> +			request.req.wValue,
>> +			request.req.wIndex,
>> +			buffer, request.req.wLength, USB_CTRL_GET_TIMEOUT);
>
> request.req.wLength might not be the actual size of buffer here due to
> your above min_t() check.
>
>> +
>> +	if (rv < 0) {
>> +		dev_err(dev, "%s failed %d\n", __func__, rv);
>> +		goto exit;
>> +	}
>> +	if ((request.req.bRequestType & USB_DIR_IN)) {
>> +		if (rv > request.req.wLength) {
>> +			dev_warn(dev, "%s returned too much data: %d\n",
>> +				 __func__, rv);
>> +			rv = request.req.wLength;
>
> Why are you returning a value that is greater than the size asked for?
> That's going to make userspace confused.

I followed the rule INPUT IS EVIL, but I'm not sure whether this really
can happen that a device can return more than requested.
I will a have a closer look again.

>
> Then there is the generic question of "why are you allowing arbitrary
> USB control messages to be sent to devices" here.  That feels like a
> very odd way for a device that is supposed to be following a standard to
> be working.  You are circumventing the standard here by allowing any
> message to be sent to the device.  While nice for that one type of
> device, you are breaking interoperability in horrible ways (now apps
> only work with one type of device.)
>
> Why did you all agree to allow this to happen?

I did not define the USBTMC and VISA standard. However the API requires
to send this generic control request. Otherwise we have to use the  
libusb again.

http://zone.ni.com/reference/en-XX/help/370131S-01/ni-visa/viusbcontrolin/

>
> thanks,
>
> greg k-h



--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Greg KH May 18, 2018, 1:50 p.m. UTC | #3
On Fri, May 18, 2018 at 01:32:51PM +0000, guido@kiener-muenchen.de wrote:
> 
> Zitat von Greg KH <gregkh@linuxfoundation.org>:
> 
> > On Thu, May 17, 2018 at 07:03:29PM +0200, Guido Kiener wrote:
> > > Add USBTMC_IOCTL_CTRL_REQUEST to send arbitrary requests on the
> > > control pipe.  Used by specific applications of IVI Foundation,
> > > Inc. to implement VISA API functions: viUsbControlIn/Out.
> > > 
> > > Signed-off-by: Guido Kiener <guido.kiener@rohde-schwarz.com>
> > > Reviewed-by: Steve Bayless <steve_bayless@keysight.com>
> > > ---
> > >  drivers/usb/class/usbtmc.c   | 61 ++++++++++++++++++++++++++++++++++++
> > >  include/uapi/linux/usb/tmc.h | 15 +++++++++
> > >  2 files changed, 76 insertions(+)
> > > 
> > > diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
> > > index 152e2daa9644..00c2e51a23a7 100644
> > > --- a/drivers/usb/class/usbtmc.c
> > > +++ b/drivers/usb/class/usbtmc.c
> > > @@ -5,6 +5,7 @@
> > >   * Copyright (C) 2007 Stefan Kopp, Gechingen, Germany
> > >   * Copyright (C) 2008 Novell, Inc.
> > >   * Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de>
> > > + * Copyright (C) 2018, IVI Foundation, Inc.
> > >   */
> > > 
> > >  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> > > @@ -1263,6 +1264,62 @@ static int
> > > usbtmc_ioctl_indicator_pulse(struct usbtmc_device_data *data)
> > >  	return rv;
> > >  }
> > > 
> > > +static int usbtmc_ioctl_request(struct usbtmc_device_data *data,
> > > +				void __user *arg)
> > > +{
> > > +	struct device *dev = &data->intf->dev;
> > > +	struct usbtmc_ctrlrequest request;
> > > +	u8 *buffer = NULL;
> > > +	int rv;
> > > +	unsigned long res;
> > > +
> > > +	res = copy_from_user(&request, arg, sizeof(struct usbtmc_ctrlrequest));
> > > +	if (res)
> > > +		return -EFAULT;
> > > +
> > > +	buffer = kmalloc(min_t(u16, 256, request.req.wLength), GFP_KERNEL);
> > 
> > No validation that wLength is a sane number?
> 
> Ooops. It should be buffer = kmalloc(max_t(u16, 256, request.req.wLength),
> GFP_KERNEL);
> Then all values of request.req.wLength (0..65535) are ok.

Yes, that would make more sense.  But you should still reject
known-invalid values, and not just "silently fix them up".

> > Go to the whiteboard nearby and write a the top of it:
> > 	ALL INPUT IS EVIL
> > 
> > > +	if (!buffer)
> > > +		return -ENOMEM;
> > > +
> > > +	if ((request.req.bRequestType & USB_DIR_IN) == 0
> > > +	    && request.req.wLength) {
> > > +		res = copy_from_user(buffer, request.data,
> > > +				     request.req.wLength);
> > > +		if (res) {
> > > +			rv = -EFAULT;
> > > +			goto exit;
> > > +		}
> > > +	}
> > > +
> > > +	rv = usb_control_msg(data->usb_dev,
> > > +			usb_rcvctrlpipe(data->usb_dev, 0),
> > > +			request.req.bRequest,
> > > +			request.req.bRequestType,
> > > +			request.req.wValue,
> > > +			request.req.wIndex,
> > > +			buffer, request.req.wLength, USB_CTRL_GET_TIMEOUT);
> > 
> > request.req.wLength might not be the actual size of buffer here due to
> > your above min_t() check.

Still wrong given the check above.

> > Then there is the generic question of "why are you allowing arbitrary
> > USB control messages to be sent to devices" here.  That feels like a
> > very odd way for a device that is supposed to be following a standard to
> > be working.  You are circumventing the standard here by allowing any
> > message to be sent to the device.  While nice for that one type of
> > device, you are breaking interoperability in horrible ways (now apps
> > only work with one type of device.)
> > 
> > Why did you all agree to allow this to happen?
> 
> I did not define the USBTMC and VISA standard. However the API requires
> to send this generic control request. Otherwise we have to use the libusb
> again.
> 
> http://zone.ni.com/reference/en-XX/help/370131S-01/ni-visa/viusbcontrolin/

Ugh, that's horrid.  And a sign of "who knows what our devices will want
to support!" design by committee (note, I've worked on lots of spec
groups before, I know how they work...)

Ok, so that needs to be supported, fair enough, so let's get the
implementation correct :)

thanks,

greg k-h
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Guido Kiener May 21, 2018, 10:06 p.m. UTC | #4
Zitat von Greg KH <gregkh@linuxfoundation.org>:

> On Fri, May 18, 2018 at 01:32:51PM +0000, guido@kiener-muenchen.de wrote:
>>
>> Zitat von Greg KH <gregkh@linuxfoundation.org>:
>>
>> > On Thu, May 17, 2018 at 07:03:29PM +0200, Guido Kiener wrote:
>> > > Add USBTMC_IOCTL_CTRL_REQUEST to send arbitrary requests on the
>> > > control pipe.  Used by specific applications of IVI Foundation,
>> > > Inc. to implement VISA API functions: viUsbControlIn/Out.
>> > >
>> > > Signed-off-by: Guido Kiener <guido.kiener@rohde-schwarz.com>
>> > > Reviewed-by: Steve Bayless <steve_bayless@keysight.com>
>> > > ---
>> > >  drivers/usb/class/usbtmc.c   | 61 ++++++++++++++++++++++++++++++++++++
>> > >  include/uapi/linux/usb/tmc.h | 15 +++++++++
>> > >  2 files changed, 76 insertions(+)
>> > >
>> > > diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
>> > > index 152e2daa9644..00c2e51a23a7 100644
>> > > --- a/drivers/usb/class/usbtmc.c
>> > > +++ b/drivers/usb/class/usbtmc.c
>> > > @@ -5,6 +5,7 @@
>> > >   * Copyright (C) 2007 Stefan Kopp, Gechingen, Germany
>> > >   * Copyright (C) 2008 Novell, Inc.
>> > >   * Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de>
>> > > + * Copyright (C) 2018, IVI Foundation, Inc.
>> > >   */
>> > >
>> > >  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>> > > @@ -1263,6 +1264,62 @@ static int
>> > > usbtmc_ioctl_indicator_pulse(struct usbtmc_device_data *data)
>> > >  	return rv;
>> > >  }
>> > >
>> > > +static int usbtmc_ioctl_request(struct usbtmc_device_data *data,
>> > > +				void __user *arg)
>> > > +{
>> > > +	struct device *dev = &data->intf->dev;
>> > > +	struct usbtmc_ctrlrequest request;
>> > > +	u8 *buffer = NULL;
>> > > +	int rv;
>> > > +	unsigned long res;
>> > > +
>> > > +	res = copy_from_user(&request, arg, sizeof(struct  
>> usbtmc_ctrlrequest));
>> > > +	if (res)
>> > > +		return -EFAULT;
>> > > +
>> > > +	buffer = kmalloc(min_t(u16, 256, request.req.wLength), GFP_KERNEL);
>> >
>> > No validation that wLength is a sane number?
>>
>> Ooops. It should be buffer = kmalloc(max_t(u16, 256, request.req.wLength),
>> GFP_KERNEL);
>> Then all values of request.req.wLength (0..65535) are ok.
>
> Yes, that would make more sense.  But you should still reject
> known-invalid values, and not just "silently fix them up".

When I start here to refuse (current) unknown settings or flags, then I fear
that people always want us to change or allow new flags. A device
should always be able to deal with all possible values. We cannot prevent a
user from sending crazy messages to the device and I do not want to develop
something like a firewall here.

>
>> > Go to the whiteboard nearby and write a the top of it:
>> > 	ALL INPUT IS EVIL
>> >
>> > > +	if (!buffer)
>> > > +		return -ENOMEM;
>> > > +
>> > > +	if ((request.req.bRequestType & USB_DIR_IN) == 0
>> > > +	    && request.req.wLength) {
>> > > +		res = copy_from_user(buffer, request.data,
>> > > +				     request.req.wLength);
>> > > +		if (res) {
>> > > +			rv = -EFAULT;
>> > > +			goto exit;
>> > > +		}
>> > > +	}
>> > > +
>> > > +	rv = usb_control_msg(data->usb_dev,
>> > > +			usb_rcvctrlpipe(data->usb_dev, 0),
>> > > +			request.req.bRequest,
>> > > +			request.req.bRequestType,
>> > > +			request.req.wValue,
>> > > +			request.req.wIndex,
>> > > +			buffer, request.req.wLength, USB_CTRL_GET_TIMEOUT);
>> >
>> > request.req.wLength might not be the actual size of buffer here due to
>> > your above min_t() check.
>
> Still wrong given the check above.

I'm missing something. I do not see the error. The size of buffer is just
at least 256 bytes. It doesn't matter when request.req.wLength < 256.
I thought this helps the memory management, since we need not to deal with
different and odd memory sizes. Maybe we should just alloc always a size of
request.req.wLength.

>
>> > Then there is the generic question of "why are you allowing arbitrary
>> > USB control messages to be sent to devices" here.  That feels like a
>> > very odd way for a device that is supposed to be following a standard to
>> > be working.  You are circumventing the standard here by allowing any
>> > message to be sent to the device.  While nice for that one type of
>> > device, you are breaking interoperability in horrible ways (now apps
>> > only work with one type of device.)
>> >
>> > Why did you all agree to allow this to happen?
>>
>> I did not define the USBTMC and VISA standard. However the API requires
>> to send this generic control request. Otherwise we have to use the libusb
>> again.
>>
>> http://zone.ni.com/reference/en-XX/help/370131S-01/ni-visa/viusbcontrolin/
>
> Ugh, that's horrid.  And a sign of "who knows what our devices will want
> to support!" design by committee (note, I've worked on lots of spec
> groups before, I know how they work...)
>
> Ok, so that needs to be supported, fair enough, so let's get the
> implementation correct :)
>
> thanks,
>
> greg k-h



--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Greg KH May 22, 2018, 9:56 a.m. UTC | #5
On Mon, May 21, 2018 at 10:06:57PM +0000, guido@kiener-muenchen.de wrote:
> 
> Zitat von Greg KH <gregkh@linuxfoundation.org>:
> 
> > On Fri, May 18, 2018 at 01:32:51PM +0000, guido@kiener-muenchen.de wrote:
> > > 
> > > Zitat von Greg KH <gregkh@linuxfoundation.org>:
> > > 
> > > > On Thu, May 17, 2018 at 07:03:29PM +0200, Guido Kiener wrote:
> > > > > Add USBTMC_IOCTL_CTRL_REQUEST to send arbitrary requests on the
> > > > > control pipe.  Used by specific applications of IVI Foundation,
> > > > > Inc. to implement VISA API functions: viUsbControlIn/Out.
> > > > >
> > > > > Signed-off-by: Guido Kiener <guido.kiener@rohde-schwarz.com>
> > > > > Reviewed-by: Steve Bayless <steve_bayless@keysight.com>
> > > > > ---
> > > > >  drivers/usb/class/usbtmc.c   | 61 ++++++++++++++++++++++++++++++++++++
> > > > >  include/uapi/linux/usb/tmc.h | 15 +++++++++
> > > > >  2 files changed, 76 insertions(+)
> > > > >
> > > > > diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
> > > > > index 152e2daa9644..00c2e51a23a7 100644
> > > > > --- a/drivers/usb/class/usbtmc.c
> > > > > +++ b/drivers/usb/class/usbtmc.c
> > > > > @@ -5,6 +5,7 @@
> > > > >   * Copyright (C) 2007 Stefan Kopp, Gechingen, Germany
> > > > >   * Copyright (C) 2008 Novell, Inc.
> > > > >   * Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de>
> > > > > + * Copyright (C) 2018, IVI Foundation, Inc.
> > > > >   */
> > > > >
> > > > >  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> > > > > @@ -1263,6 +1264,62 @@ static int
> > > > > usbtmc_ioctl_indicator_pulse(struct usbtmc_device_data *data)
> > > > >  	return rv;
> > > > >  }
> > > > >
> > > > > +static int usbtmc_ioctl_request(struct usbtmc_device_data *data,
> > > > > +				void __user *arg)
> > > > > +{
> > > > > +	struct device *dev = &data->intf->dev;
> > > > > +	struct usbtmc_ctrlrequest request;
> > > > > +	u8 *buffer = NULL;
> > > > > +	int rv;
> > > > > +	unsigned long res;
> > > > > +
> > > > > +	res = copy_from_user(&request, arg, sizeof(struct
> > > usbtmc_ctrlrequest));
> > > > > +	if (res)
> > > > > +		return -EFAULT;
> > > > > +
> > > > > +	buffer = kmalloc(min_t(u16, 256, request.req.wLength), GFP_KERNEL);
> > > >
> > > > No validation that wLength is a sane number?
> > > 
> > > Ooops. It should be buffer = kmalloc(max_t(u16, 256, request.req.wLength),
> > > GFP_KERNEL);
> > > Then all values of request.req.wLength (0..65535) are ok.
> > 
> > Yes, that would make more sense.  But you should still reject
> > known-invalid values, and not just "silently fix them up".
> 
> When I start here to refuse (current) unknown settings or flags, then I fear
> that people always want us to change or allow new flags.

That doesn't make sense, you always need to reject unknown values, or
people will put crap in them and then get mad in the future when you
want to use those fields/values for something else.

> A device should always be able to deal with all possible values.

But the kernel has to be sane and properly validate userspace values.

> We
> cannot prevent a
> user from sending crazy messages to the device and I do not want to develop
> something like a firewall here.

Sure, I'm not saying to do that, you are not validating the other
fields, just the length.  The kernel will validate the other fields when
you submit the urb.

> > > > > +	rv = usb_control_msg(data->usb_dev,
> > > > > +			usb_rcvctrlpipe(data->usb_dev, 0),
> > > > > +			request.req.bRequest,
> > > > > +			request.req.bRequestType,
> > > > > +			request.req.wValue,
> > > > > +			request.req.wIndex,
> > > > > +			buffer, request.req.wLength, USB_CTRL_GET_TIMEOUT);
> > > >
> > > > request.req.wLength might not be the actual size of buffer here due to
> > > > your above min_t() check.
> > 
> > Still wrong given the check above.
> 
> I'm missing something. I do not see the error. The size of buffer is just
> at least 256 bytes. It doesn't matter when request.req.wLength < 256.

If wLength is set to 10000 but buffer really isn't that big, bad things
happen...

> I thought this helps the memory management, since we need not to deal with
> different and odd memory sizes. Maybe we should just alloc always a size of
> request.req.wLength.

Again, you have to validate that number, if you want to bound it to 256,
great, then bound it.  Don't half-way do it please.

thanks,

greg k-h
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 152e2daa9644..00c2e51a23a7 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -5,6 +5,7 @@ 
  * Copyright (C) 2007 Stefan Kopp, Gechingen, Germany
  * Copyright (C) 2008 Novell, Inc.
  * Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de>
+ * Copyright (C) 2018, IVI Foundation, Inc.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -1263,6 +1264,62 @@  static int usbtmc_ioctl_indicator_pulse(struct usbtmc_device_data *data)
 	return rv;
 }
 
+static int usbtmc_ioctl_request(struct usbtmc_device_data *data,
+				void __user *arg)
+{
+	struct device *dev = &data->intf->dev;
+	struct usbtmc_ctrlrequest request;
+	u8 *buffer = NULL;
+	int rv;
+	unsigned long res;
+
+	res = copy_from_user(&request, arg, sizeof(struct usbtmc_ctrlrequest));
+	if (res)
+		return -EFAULT;
+
+	buffer = kmalloc(min_t(u16, 256, request.req.wLength), GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	if ((request.req.bRequestType & USB_DIR_IN) == 0
+	    && request.req.wLength) {
+		res = copy_from_user(buffer, request.data,
+				     request.req.wLength);
+		if (res) {
+			rv = -EFAULT;
+			goto exit;
+		}
+	}
+
+	rv = usb_control_msg(data->usb_dev,
+			usb_rcvctrlpipe(data->usb_dev, 0),
+			request.req.bRequest,
+			request.req.bRequestType,
+			request.req.wValue,
+			request.req.wIndex,
+			buffer, request.req.wLength, USB_CTRL_GET_TIMEOUT);
+
+	if (rv < 0) {
+		dev_err(dev, "%s failed %d\n", __func__, rv);
+		goto exit;
+	}
+	if ((request.req.bRequestType & USB_DIR_IN)) {
+		if (rv > request.req.wLength) {
+			dev_warn(dev, "%s returned too much data: %d\n",
+				 __func__, rv);
+			rv = request.req.wLength;
+		}
+
+		res = copy_to_user(request.data, buffer, rv);
+		if (res)
+			rv = -EFAULT;
+	}
+
+ exit:
+	kfree(buffer);
+	return rv;
+}
+
 /*
  * Get the usb timeout value
  */
@@ -1379,6 +1436,10 @@  static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 		retval = usbtmc_ioctl_abort_bulk_in(data);
 		break;
 
+	case USBTMC_IOCTL_CTRL_REQUEST:
+		retval = usbtmc_ioctl_request(data, (void __user *)arg);
+		break;
+
 	case USBTMC_IOCTL_GET_TIMEOUT:
 		retval = usbtmc_ioctl_get_timeout(file_data,
 						  (void __user *)arg);
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index 60369825691c..c1acec9ad834 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -4,6 +4,7 @@ 
  * Copyright (C) 2008 Novell, Inc.
  * Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de>
  * Copyright (C) 2015 Dave Penkler <dpenkler@gmail.com>
+ * Copyright (C) 2018, IVI Foundation, Inc.
  *
  * This file holds USB constants defined by the USB Device Class
  * and USB488 Subclass Definitions for Test and Measurement devices
@@ -40,6 +41,19 @@ 
 #define USBTMC488_REQUEST_GOTO_LOCAL			161
 #define USBTMC488_REQUEST_LOCAL_LOCKOUT			162
 
+struct usbtmc_request {
+	__u8 bRequestType;
+	__u8 bRequest;
+	__u16 wValue;
+	__u16 wIndex;
+	__u16 wLength;
+} __attribute__ ((packed));
+
+struct usbtmc_ctrlrequest {
+	struct usbtmc_request req;
+	void __user *data;
+} __attribute__ ((packed));
+
 struct usbtmc_termchar {
 	__u8 term_char;
 	__u8 term_char_enabled; // bool
@@ -53,6 +67,7 @@  struct usbtmc_termchar {
 #define USBTMC_IOCTL_ABORT_BULK_IN	_IO(USBTMC_IOC_NR, 4)
 #define USBTMC_IOCTL_CLEAR_OUT_HALT	_IO(USBTMC_IOC_NR, 6)
 #define USBTMC_IOCTL_CLEAR_IN_HALT	_IO(USBTMC_IOC_NR, 7)
+#define USBTMC_IOCTL_CTRL_REQUEST	_IOWR(USBTMC_IOC_NR, 8, struct usbtmc_ctrlrequest)
 #define USBTMC_IOCTL_GET_TIMEOUT	_IOR(USBTMC_IOC_NR, 9, unsigned int)
 #define USBTMC_IOCTL_SET_TIMEOUT	_IOW(USBTMC_IOC_NR, 10, unsigned int)
 #define USBTMC_IOCTL_EOM_ENABLE	        _IOW(USBTMC_IOC_NR, 11, __u8)