forked from Minki/linux
USB: gadget: detect too-big endpoint 0 requests
Sometimes USB hosts can ask for buffers that are too large from endpoint 0, which should not be allowed. If this happens for OUT requests, stall the endpoint, but for IN requests, trim the request size to the endpoint buffer size. Co-developed-by: Szymon Heidrich <szymon.heidrich@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
7faac1953e
commit
153a2d7e33
@ -1679,6 +1679,18 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
|||||||
struct usb_function *f = NULL;
|
struct usb_function *f = NULL;
|
||||||
u8 endp;
|
u8 endp;
|
||||||
|
|
||||||
|
if (w_length > USB_COMP_EP0_BUFSIZ) {
|
||||||
|
if (ctrl->bRequestType == USB_DIR_OUT) {
|
||||||
|
goto done;
|
||||||
|
} else {
|
||||||
|
/* Cast away the const, we are going to overwrite on purpose. */
|
||||||
|
__le16 *temp = (__le16 *)&ctrl->wLength;
|
||||||
|
|
||||||
|
*temp = cpu_to_le16(USB_COMP_EP0_BUFSIZ);
|
||||||
|
w_length = USB_COMP_EP0_BUFSIZ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* partial re-init of the response message; the function or the
|
/* partial re-init of the response message; the function or the
|
||||||
* gadget might need to intercept e.g. a control-OUT completion
|
* gadget might need to intercept e.g. a control-OUT completion
|
||||||
* when we delegate to it.
|
* when we delegate to it.
|
||||||
|
@ -345,6 +345,19 @@ static int dbgp_setup(struct usb_gadget *gadget,
|
|||||||
void *data = NULL;
|
void *data = NULL;
|
||||||
u16 len = 0;
|
u16 len = 0;
|
||||||
|
|
||||||
|
if (length > DBGP_REQ_LEN) {
|
||||||
|
if (ctrl->bRequestType == USB_DIR_OUT) {
|
||||||
|
return err;
|
||||||
|
} else {
|
||||||
|
/* Cast away the const, we are going to overwrite on purpose. */
|
||||||
|
__le16 *temp = (__le16 *)&ctrl->wLength;
|
||||||
|
|
||||||
|
*temp = cpu_to_le16(DBGP_REQ_LEN);
|
||||||
|
length = DBGP_REQ_LEN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (request == USB_REQ_GET_DESCRIPTOR) {
|
if (request == USB_REQ_GET_DESCRIPTOR) {
|
||||||
switch (value>>8) {
|
switch (value>>8) {
|
||||||
case USB_DT_DEVICE:
|
case USB_DT_DEVICE:
|
||||||
|
@ -110,6 +110,8 @@ enum ep0_state {
|
|||||||
/* enough for the whole queue: most events invalidate others */
|
/* enough for the whole queue: most events invalidate others */
|
||||||
#define N_EVENT 5
|
#define N_EVENT 5
|
||||||
|
|
||||||
|
#define RBUF_SIZE 256
|
||||||
|
|
||||||
struct dev_data {
|
struct dev_data {
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
refcount_t count;
|
refcount_t count;
|
||||||
@ -144,7 +146,7 @@ struct dev_data {
|
|||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
|
|
||||||
/* except this scratch i/o buffer for ep0 */
|
/* except this scratch i/o buffer for ep0 */
|
||||||
u8 rbuf [256];
|
u8 rbuf[RBUF_SIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void get_dev (struct dev_data *data)
|
static inline void get_dev (struct dev_data *data)
|
||||||
@ -1331,6 +1333,18 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
|||||||
u16 w_value = le16_to_cpu(ctrl->wValue);
|
u16 w_value = le16_to_cpu(ctrl->wValue);
|
||||||
u16 w_length = le16_to_cpu(ctrl->wLength);
|
u16 w_length = le16_to_cpu(ctrl->wLength);
|
||||||
|
|
||||||
|
if (w_length > RBUF_SIZE) {
|
||||||
|
if (ctrl->bRequestType == USB_DIR_OUT) {
|
||||||
|
return value;
|
||||||
|
} else {
|
||||||
|
/* Cast away the const, we are going to overwrite on purpose. */
|
||||||
|
__le16 *temp = (__le16 *)&ctrl->wLength;
|
||||||
|
|
||||||
|
*temp = cpu_to_le16(RBUF_SIZE);
|
||||||
|
w_length = RBUF_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
spin_lock (&dev->lock);
|
spin_lock (&dev->lock);
|
||||||
dev->setup_abort = 0;
|
dev->setup_abort = 0;
|
||||||
if (dev->state == STATE_DEV_UNCONNECTED) {
|
if (dev->state == STATE_DEV_UNCONNECTED) {
|
||||||
|
Loading…
Reference in New Issue
Block a user