Skip to content

Commit

Permalink
Input: usbtouchscreen - fix buffer overflow, make more egalax work
Browse files Browse the repository at this point in the history
Fix a buffer overflow in mutli-packet handling code.  The overflow can
only happen with eGalax devices and is even there very unlikely (only
non-report packet are affected any only when truncated after the first
byte).

Also changes the mutli-packet handling code not to drop unknown packets,
but rather just drop one byte.  This allows synchronizing on report packets
in the data stream.  It's required for some egalax devices to work at all.

Also remove the pointless 'flags' member of the device struct and set the
version number to 0.6, plus some minor cleanups.

[akpm@linux-foundation.org: coding-style fixes]

Signed-off-by: Daniel Ritz <daniel.ritz@gmx.ch>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
  • Loading branch information
Daniel Ritz authored and Dmitry Torokhov committed Jan 17, 2008
1 parent 6724f93 commit 62aa366
Showing 1 changed file with 33 additions and 22 deletions.
55 changes: 33 additions & 22 deletions drivers/input/touchscreen/usbtouchscreen.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* - DMC TSC-10/25
* - IRTOUCHSYSTEMS/UNITOP
* - IdealTEK URTC1000
* - General Touch
* - GoTop Super_Q2/GogoPen/PenPower tablets
*
* Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch>
Expand Down Expand Up @@ -50,7 +51,7 @@
#include <linux/usb/input.h>


#define DRIVER_VERSION "v0.5"
#define DRIVER_VERSION "v0.6"
#define DRIVER_AUTHOR "Daniel Ritz <daniel.ritz@gmx.ch>"
#define DRIVER_DESC "USB Touchscreen Driver"

Expand All @@ -65,17 +66,21 @@ struct usbtouch_device_info {
int min_yc, max_yc;
int min_press, max_press;
int rept_size;
int flags;

void (*process_pkt) (struct usbtouch_usb *usbtouch, unsigned char *pkt, int len);

/*
* used to get the packet len. possible return values:
* > 0: packet len
* = 0: skip one byte
* < 0: -return value more bytes needed
*/
int (*get_pkt_len) (unsigned char *pkt, int len);

int (*read_data) (struct usbtouch_usb *usbtouch, unsigned char *pkt);
int (*init) (struct usbtouch_usb *usbtouch);
};

#define USBTOUCH_FLG_BUFFER 0x01


/* a usbtouch device */
struct usbtouch_usb {
unsigned char *data;
Expand All @@ -94,15 +99,6 @@ struct usbtouch_usb {
};


#if defined(CONFIG_TOUCHSCREEN_USB_EGALAX) || defined(CONFIG_TOUCHSCREEN_USB_ETURBO) || defined(CONFIG_TOUCHSCREEN_USB_IDEALTEK)
#define MULTI_PACKET
#endif

#ifdef MULTI_PACKET
static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
unsigned char *pkt, int len);
#endif

/* device types */
enum {
DEVTPYE_DUMMY = -1,
Expand Down Expand Up @@ -186,6 +182,10 @@ static struct usb_device_id usbtouch_devices[] = {

#ifdef CONFIG_TOUCHSCREEN_USB_EGALAX

#ifndef MULTI_PACKET
#define MULTI_PACKET
#endif

#define EGALAX_PKT_TYPE_MASK 0xFE
#define EGALAX_PKT_TYPE_REPT 0x80
#define EGALAX_PKT_TYPE_DIAG 0x0A
Expand Down Expand Up @@ -323,6 +323,9 @@ static int itm_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
* eTurboTouch part
*/
#ifdef CONFIG_TOUCHSCREEN_USB_ETURBO
#ifndef MULTI_PACKET
#define MULTI_PACKET
#endif
static int eturbo_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
{
unsigned int shift;
Expand Down Expand Up @@ -461,6 +464,9 @@ static int irtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
* IdealTEK URTC1000 Part
*/
#ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK
#ifndef MULTI_PACKET
#define MULTI_PACKET
#endif
static int idealtek_get_pkt_len(unsigned char *buf, int len)
{
if (buf[0] & 0x80)
Expand Down Expand Up @@ -525,6 +531,11 @@ static int gotop_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
/*****************************************************************************
* the different device descriptors
*/
#ifdef MULTI_PACKET
static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
unsigned char *pkt, int len);
#endif

static struct usbtouch_device_info usbtouch_dev_info[] = {
#ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
[DEVTYPE_EGALAX] = {
Expand All @@ -533,7 +544,6 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
.min_yc = 0x0,
.max_yc = 0x07ff,
.rept_size = 16,
.flags = USBTOUCH_FLG_BUFFER,
.process_pkt = usbtouch_process_multi,
.get_pkt_len = egalax_get_pkt_len,
.read_data = egalax_read_data,
Expand Down Expand Up @@ -582,7 +592,6 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
.min_yc = 0x0,
.max_yc = 0x07ff,
.rept_size = 8,
.flags = USBTOUCH_FLG_BUFFER,
.process_pkt = usbtouch_process_multi,
.get_pkt_len = eturbo_get_pkt_len,
.read_data = eturbo_read_data,
Expand Down Expand Up @@ -630,7 +639,6 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
.min_yc = 0x0,
.max_yc = 0x0fff,
.rept_size = 8,
.flags = USBTOUCH_FLG_BUFFER,
.process_pkt = usbtouch_process_multi,
.get_pkt_len = idealtek_get_pkt_len,
.read_data = idealtek_read_data,
Expand Down Expand Up @@ -738,11 +746,14 @@ static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
pos = 0;
while (pos < buf_len) {
/* get packet len */
pkt_len = usbtouch->type->get_pkt_len(buffer + pos, len);
pkt_len = usbtouch->type->get_pkt_len(buffer + pos,
buf_len - pos);

/* unknown packet: drop everything */
if (unlikely(!pkt_len))
goto out_flush_buf;
/* unknown packet: skip one byte */
if (unlikely(!pkt_len)) {
pos++;
continue;
}

/* full packet: process */
if (likely((pkt_len > 0) && (pkt_len <= buf_len - pos))) {
Expand Down Expand Up @@ -857,7 +868,7 @@ static int usbtouch_probe(struct usb_interface *intf,
if (!usbtouch->data)
goto out_free;

if (type->flags & USBTOUCH_FLG_BUFFER) {
if (type->get_pkt_len) {
usbtouch->buffer = kmalloc(type->rept_size, GFP_KERNEL);
if (!usbtouch->buffer)
goto out_free_buffers;
Expand Down

0 comments on commit 62aa366

Please sign in to comment.