Commit 2a9a1964 authored by Foster Snowhill's avatar Foster Snowhill Committed by Paolo Abeni
Browse files

usbnet: ipheth: refactor NCM datagram loop



Introduce an rx_error label to reduce repetitions in the header
signature checks.

Store wDatagramIndex and wDatagramLength after endianness conversion to
avoid repeated le16_to_cpu() calls.

Rewrite the loop to return on a null trailing DPE, which is required
by the CDC NCM spec. In case it is missing, fall through to rx_error.

This change does not fix any particular issue. Its purpose is to
simplify a subsequent commit that fixes a potential OoB read by limiting
the maximum amount of processed DPEs.

Cc: stable@vger.kernel.org # 6.5.x
Signed-off-by: default avatarFoster Snowhill <forst@pen.gy>
Reviewed-by: default avatarJakub Kicinski <kuba@kernel.org>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 86586dcb
Loading
Loading
Loading
Loading
+23 −19
Original line number Diff line number Diff line
@@ -213,9 +213,9 @@ static int ipheth_rcvbulk_callback_ncm(struct urb *urb)
	struct usb_cdc_ncm_ndp16 *ncm0;
	struct usb_cdc_ncm_dpe16 *dpe;
	struct ipheth_device *dev;
	u16 dg_idx, dg_len;
	int retval = -EINVAL;
	char *buf;
	int len;

	dev = urb->context;

@@ -227,39 +227,43 @@ static int ipheth_rcvbulk_callback_ncm(struct urb *urb)
	ncmh = urb->transfer_buffer;
	if (ncmh->dwSignature != cpu_to_le32(USB_CDC_NCM_NTH16_SIGN) ||
	    /* On iOS, NDP16 directly follows NTH16 */
	    ncmh->wNdpIndex != cpu_to_le16(sizeof(struct usb_cdc_ncm_nth16))) {
		dev->net->stats.rx_errors++;
		return retval;
	}
	    ncmh->wNdpIndex != cpu_to_le16(sizeof(struct usb_cdc_ncm_nth16)))
		goto rx_error;

	ncm0 = urb->transfer_buffer + sizeof(struct usb_cdc_ncm_nth16);
	if (ncm0->dwSignature != cpu_to_le32(USB_CDC_NCM_NDP16_NOCRC_SIGN)) {
		dev->net->stats.rx_errors++;
		return retval;
	}
	if (ncm0->dwSignature != cpu_to_le32(USB_CDC_NCM_NDP16_NOCRC_SIGN))
		goto rx_error;

	dpe = ncm0->dpe16;
	while (le16_to_cpu(dpe->wDatagramIndex) != 0 &&
	       le16_to_cpu(dpe->wDatagramLength) != 0) {
		if (le16_to_cpu(dpe->wDatagramIndex) < IPHETH_NCM_HEADER_SIZE ||
		    le16_to_cpu(dpe->wDatagramIndex) >= urb->actual_length ||
		    le16_to_cpu(dpe->wDatagramLength) > urb->actual_length -
		    le16_to_cpu(dpe->wDatagramIndex)) {
	while (true) {
		dg_idx = le16_to_cpu(dpe->wDatagramIndex);
		dg_len = le16_to_cpu(dpe->wDatagramLength);

		/* Null DPE must be present after last datagram pointer entry
		 * (3.3.1 USB CDC NCM spec v1.0)
		 */
		if (dg_idx == 0 && dg_len == 0)
			return 0;

		if (dg_idx < IPHETH_NCM_HEADER_SIZE ||
		    dg_idx >= urb->actual_length ||
		    dg_len > urb->actual_length - dg_idx) {
			dev->net->stats.rx_length_errors++;
			return retval;
		}

		buf = urb->transfer_buffer + le16_to_cpu(dpe->wDatagramIndex);
		len = le16_to_cpu(dpe->wDatagramLength);
		buf = urb->transfer_buffer + dg_idx;

		retval = ipheth_consume_skb(buf, len, dev);
		retval = ipheth_consume_skb(buf, dg_len, dev);
		if (retval != 0)
			return retval;

		dpe++;
	}

	return 0;
rx_error:
	dev->net->stats.rx_errors++;
	return retval;
}

static void ipheth_rcvbulk_callback(struct urb *urb)