input: touchpanel: fix security issues in GT915 driver

There are multiple buffer overflow and input validation issues
in Goodix gt915 driver, fix these issues by adding data length
check and change file system node mode.

Change-Id: I5173fc1ca021fd45c939c7c8a4f460651330de5b
Signed-off-by: Bingzhe Cai <bingzhec@codeaurora.org>
Signed-off-by: Sudhakar Manapati <smanap@codeaurora.org>
This commit is contained in:
Bingzhe Cai 2013-09-24 01:42:12 +08:00 committed by Gerrit - the friendly Code Review server
parent 0ddb25d00e
commit 24a8120f34

View file

@ -22,6 +22,7 @@
*/
#include "gt9xx.h"
#include <linux/mutex.h>
#define DATA_LENGTH_UINT 512
#define CMD_HEAD_LENGTH (sizeof(st_cmd_head) - sizeof(u8 *))
@ -53,6 +54,8 @@ static struct i2c_client *gt_client;
static struct proc_dir_entry *goodix_proc_entry;
static struct mutex lock;
static s32 goodix_tool_write(struct file *filp, const char __user *buff,
unsigned long len, void *data);
static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
@ -181,7 +184,7 @@ static void unregister_i2c_func(void)
s32 init_wr_node(struct i2c_client *client)
{
s32 i;
u8 i;
gt_client = client;
memset(&cmd_head, 0, sizeof(cmd_head));
@ -195,8 +198,8 @@ s32 init_wr_node(struct i2c_client *client)
i--;
}
if (i) {
DATA_LENGTH = i * DATA_LENGTH_UINT + GTP_ADDR_LENGTH;
GTP_INFO("Applied memory size:%d.", DATA_LENGTH);
DATA_LENGTH = i * DATA_LENGTH_UINT;
dev_dbg(&client->dev, "Applied memory size:%d.", DATA_LENGTH);
} else {
GTP_ERROR("Apply for memory failed.");
return FAIL;
@ -207,8 +210,9 @@ s32 init_wr_node(struct i2c_client *client)
register_i2c_func();
mutex_init(&lock);
tool_set_proc_name(procname);
goodix_proc_entry = create_proc_entry(procname, 0666, NULL);
goodix_proc_entry = create_proc_entry(procname, 0660, NULL);
if (goodix_proc_entry == NULL) {
GTP_ERROR("Couldn't create proc entry!");
return FAIL;
@ -330,9 +334,13 @@ static s32 goodix_tool_write(struct file *filp, const char __user *buff,
GTP_DEBUG_FUNC();
GTP_DEBUG_ARRAY((u8 *)buff, len);
mutex_lock(&lock);
ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH);
if (ret)
if (ret) {
GTP_ERROR("copy_from_user failed.");
ret = -EACCES;
goto exit;
}
GTP_DEBUG("wr :0x%02x.", cmd_head.wr);
GTP_DEBUG("flag:0x%02x.", cmd_head.flag);
@ -350,6 +358,19 @@ static s32 goodix_tool_write(struct file *filp, const char __user *buff,
GTP_DEBUG("len:%d.", (s32)len);
GTP_DEBUG("buf[20]:0x%02x.", buff[CMD_HEAD_LENGTH]);
if (cmd_head.data_len > (DATA_LENGTH - GTP_ADDR_LENGTH)) {
pr_err("data len %d > data buff %d, rejected!\n",
cmd_head.data_len, (DATA_LENGTH - GTP_ADDR_LENGTH));
ret = -EINVAL;
goto exit;
}
if (cmd_head.addr_len > GTP_ADDR_LENGTH) {
pr_err(" addr len %d > data buff %d, rejected!\n",
cmd_head.addr_len, GTP_ADDR_LENGTH);
ret = -EINVAL;
goto exit;
}
if (cmd_head.wr == 1) {
/* copy_from_user(&cmd_head.data[cmd_head.addr_len],
* &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
@ -370,7 +391,8 @@ static s32 goodix_tool_write(struct file *filp, const char __user *buff,
if (cmd_head.flag == 1) {
if (comfirm() == FAIL) {
GTP_ERROR("[WRITE]Comfirm fail!");
return FAIL;
ret = -EINVAL;
goto exit;
}
} else if (cmd_head.flag == 2) {
/* Need interrupt! */
@ -379,7 +401,8 @@ static s32 goodix_tool_write(struct file *filp, const char __user *buff,
&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],
cmd_head.data_len + cmd_head.addr_len) <= 0) {
GTP_ERROR("[WRITE]Write data failed!");
return FAIL;
ret = -EIO;
goto exit;
}
GTP_DEBUG_ARRAY(
@ -388,7 +411,8 @@ static s32 goodix_tool_write(struct file *filp, const char __user *buff,
if (cmd_head.delay)
msleep(cmd_head.delay);
return cmd_head.data_len + CMD_HEAD_LENGTH;
ret = cmd_head.data_len + CMD_HEAD_LENGTH;
goto exit;
} else if (cmd_head.wr == 3) { /* Write ic type */
ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH],
@ -396,30 +420,40 @@ static s32 goodix_tool_write(struct file *filp, const char __user *buff,
if (ret)
GTP_ERROR("copy_from_user failed.");
if (cmd_head.data_len > sizeof(IC_TYPE)) {
pr_err("<<-GTP->> data len %d > data buff %d, rejected!\n",
cmd_head.data_len, sizeof(IC_TYPE));
ret = -EINVAL;
goto exit;
}
memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);
register_i2c_func();
return cmd_head.data_len + CMD_HEAD_LENGTH;
} else if (cmd_head.wr == 3) {
ret = cmd_head.data_len + CMD_HEAD_LENGTH;
goto exit;
} else if (cmd_head.wr == 5) {
/* memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len); */
return cmd_head.data_len + CMD_HEAD_LENGTH;
ret = cmd_head.data_len + CMD_HEAD_LENGTH;
goto exit;
} else if (cmd_head.wr == 7) { /* disable irq! */
gtp_irq_disable(i2c_get_clientdata(gt_client));
#if GTP_ESD_PROTECT
gtp_esd_switch(gt_client, SWITCH_OFF);
#endif
return CMD_HEAD_LENGTH;
ret = CMD_HEAD_LENGTH;
goto exit;
} else if (cmd_head.wr == 9) { /* enable irq! */
gtp_irq_enable(i2c_get_clientdata(gt_client));
#if GTP_ESD_PROTECT
gtp_esd_switch(gt_client, SWITCH_ON);
#endif
return CMD_HEAD_LENGTH;
ret = CMD_HEAD_LENGTH;
goto exit;
} else if (cmd_head.wr == 17) {
struct goodix_ts_data *ts = i2c_get_clientdata(gt_client);
@ -434,27 +468,40 @@ static s32 goodix_tool_write(struct file *filp, const char __user *buff,
ts->gtp_rawdiff_mode = false;
GTP_DEBUG("gtp leave rawdiff.");
}
return CMD_HEAD_LENGTH;
ret = CMD_HEAD_LENGTH;
goto exit;
}
#ifdef UPDATE_FUNCTIONS
else if (cmd_head.wr == 11) { /* Enter update mode! */
if (gup_enter_update_mode(gt_client) == FAIL)
return FAIL;
ret = -EBUSY;
goto exit;
} else if (cmd_head.wr == 13) { /* Leave update mode! */
gup_leave_update_mode();
} else if (cmd_head.wr == 15) { /* Update firmware! */
show_len = 0;
total_len = 0;
if (cmd_head.data_len + 1 > DATA_LENGTH) {
pr_err("<<-GTP->> data len %d > data buff %d, rejected!\n",
cmd_head.data_len + 1, DATA_LENGTH);
ret = -EINVAL;
goto exit;
}
memset(cmd_head.data, 0, cmd_head.data_len + 1);
memcpy(cmd_head.data, &buff[CMD_HEAD_LENGTH],
cmd_head.data_len);
if (gup_update_proc((void *)cmd_head.data) == FAIL)
return FAIL;
if (gup_update_proc((void *)cmd_head.data) == FAIL) {
ret = -EBUSY;
goto exit;
}
}
#endif
ret = CMD_HEAD_LENGTH;
return CMD_HEAD_LENGTH;
exit:
mutex_unlock(&lock);
return ret;
}
/*******************************************************
@ -469,10 +516,14 @@ static s32 goodix_tool_write(struct file *filp, const char __user *buff,
static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
int *eof, void *data)
{
s32 ret;
GTP_DEBUG_FUNC();
mutex_lock(&lock);
if (cmd_head.wr % 2) {
return FAIL;
pr_err("<< [READ]command head wrong\n");
ret = -EINVAL;
goto exit;
} else if (!cmd_head.wr) {
u16 len = 0;
s16 data_len = 0;
@ -481,7 +532,8 @@ static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
if (cmd_head.flag == 1) {
if (comfirm() == FAIL) {
GTP_ERROR("[READ]Comfirm fail!");
return FAIL;
ret = -EINVAL;
goto exit;
}
} else if (cmd_head.flag == 2) {
/* Need interrupt! */
@ -504,11 +556,12 @@ static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
else
len = data_len;
data_len -= DATA_LENGTH;
data_len -= len;
if (tool_i2c_read(cmd_head.data, len) <= 0) {
GTP_ERROR("[READ]Read data failed!");
return FAIL;
ret = -EINVAL;
goto exit;
}
memcpy(&page[loc], &cmd_head.data[GTP_ADDR_LENGTH],
len);
@ -525,15 +578,14 @@ static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
GTP_DEBUG("Return ic type:%s len:%d.", page,
(s32)cmd_head.data_len);
return cmd_head.data_len;
ret = cmd_head.data_len;
goto exit;
/* return sizeof(IC_TYPE_NAME); */
} else if (cmd_head.wr == 4) {
page[0] = show_len >> 8;
page[1] = show_len & 0xff;
page[2] = total_len >> 8;
page[3] = total_len & 0xff;
return cmd_head.data_len;
} else if (cmd_head.wr == 6) {
/* Read error code! */
} else if (cmd_head.wr == 8) { /*Read driver version */
@ -546,6 +598,9 @@ static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
memcpy(page, GTP_DRIVER_VERSION, tmp_len);
page[tmp_len] = 0;
}
ret = cmd_head.data_len;
return cmd_head.data_len;
exit:
mutex_unlock(&lock);
return ret;
}