Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f84197f4 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman Committed by PavanKumar S.R
Browse files

UPSTREAM: 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: default avatarSzymon Heidrich <szymon.heidrich@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
(cherry picked from commit 153a2d7e3350cc89d406ba2d35be8793a64c2038)
Bug: 210292367
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@google.com>
Change-Id: I9bbd6154177d7a1fb6c2e3a3dffa96634d85bb7f
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@google.com>
Git-commit: f92d5da0
Git-repo: https://android.googlesource.com/kernel/common


Signed-off-by: default avatarPavanKumar S.R <quic_pavasr@quicinc.com>
parent 90de98df
Loading
Loading
Loading
Loading
+12 −0
Original line number Original line Diff line number Diff line
@@ -1749,6 +1749,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.
+13 −0
Original line number Original line Diff line number Diff line
@@ -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:
+15 −1
Original line number Original line Diff line number Diff line
@@ -109,6 +109,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;
@@ -143,7 +145,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)
@@ -1332,6 +1334,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) {