aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXiao Han <xiao.han@orange.fr>2016-06-14 10:22:54 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-08-09 09:45:59 -0400
commit9c6256a5e707a9eb8b91962b550050b13aa75334 (patch)
treebfd9bd5a35e7648fffe2353e36259b50cb0369cd
parent28324936f3d672bbf83472fece8f36a158a52276 (diff)
usb: misc: ftdi-elan: Fix off-by-one memory corruptions
This patch fixes fives off-by-one bugs in the ftdi-elan driver code. The bug can be triggered by plugging a USB adapter for CardBus 3G cards (model U132 manufactured by Elan Digital Systems, Ltd), causing a kernel panic. The fix was tested on Ubuntu 14.04.4 with 4.7.0-rc14.2.0-27-generic+ and 4.4.0-22-generic+ kernel. In the ftdi_elan_synchronize function, an off-by-one memory corruption occurs when packet_bytes is equal or bigger than m. After having read m bytes, that is bytes_read is equal to m, " ..\x00" is still copied to the stack variable causing an out bounds write of 4 bytes, which overwrites the stack canary and results in a kernel panic. This off-by-one requires physical access to the machine. It is not exploitable since we have no control on the overwritten data. Similar off-by-one bugs have been observed in 4 other functions: ftdi_elan_stuck_waiting, ftdi_elan_read, ftdi_elan_edset_output and ftdi_elan_flush_input_fifo. Reported-by: Alex Palesandro <palexster@gmail.com> Signed-off-by: Xiao Han <xiao.han@orange.fr> Tested-by: Paul Chaignon <pchaigno@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/misc/ftdi-elan.c10
1 files changed, 5 insertions, 5 deletions
diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c
index 52c27cab78c3..9b5b3b2281ca 100644
--- a/drivers/usb/misc/ftdi-elan.c
+++ b/drivers/usb/misc/ftdi-elan.c
@@ -665,7 +665,7 @@ static ssize_t ftdi_elan_read(struct file *file, char __user *buffer,
665{ 665{
666 char data[30 *3 + 4]; 666 char data[30 *3 + 4];
667 char *d = data; 667 char *d = data;
668 int m = (sizeof(data) - 1) / 3; 668 int m = (sizeof(data) - 1) / 3 - 1;
669 int bytes_read = 0; 669 int bytes_read = 0;
670 int retry_on_empty = 10; 670 int retry_on_empty = 10;
671 int retry_on_timeout = 5; 671 int retry_on_timeout = 5;
@@ -1684,7 +1684,7 @@ wait:if (ftdi->disconnected > 0) {
1684 int i = 0; 1684 int i = 0;
1685 char data[30 *3 + 4]; 1685 char data[30 *3 + 4];
1686 char *d = data; 1686 char *d = data;
1687 int m = (sizeof(data) - 1) / 3; 1687 int m = (sizeof(data) - 1) / 3 - 1;
1688 int l = 0; 1688 int l = 0;
1689 struct u132_target *target = &ftdi->target[ed]; 1689 struct u132_target *target = &ftdi->target[ed];
1690 struct u132_command *command = &ftdi->command[ 1690 struct u132_command *command = &ftdi->command[
@@ -1876,7 +1876,7 @@ more:{
1876 if (packet_bytes > 2) { 1876 if (packet_bytes > 2) {
1877 char diag[30 *3 + 4]; 1877 char diag[30 *3 + 4];
1878 char *d = diag; 1878 char *d = diag;
1879 int m = (sizeof(diag) - 1) / 3; 1879 int m = (sizeof(diag) - 1) / 3 - 1;
1880 char *b = ftdi->bulk_in_buffer; 1880 char *b = ftdi->bulk_in_buffer;
1881 int bytes_read = 0; 1881 int bytes_read = 0;
1882 diag[0] = 0; 1882 diag[0] = 0;
@@ -2053,7 +2053,7 @@ static int ftdi_elan_synchronize(struct usb_ftdi *ftdi)
2053 if (packet_bytes > 2) { 2053 if (packet_bytes > 2) {
2054 char diag[30 *3 + 4]; 2054 char diag[30 *3 + 4];
2055 char *d = diag; 2055 char *d = diag;
2056 int m = (sizeof(diag) - 1) / 3; 2056 int m = (sizeof(diag) - 1) / 3 - 1;
2057 char *b = ftdi->bulk_in_buffer; 2057 char *b = ftdi->bulk_in_buffer;
2058 int bytes_read = 0; 2058 int bytes_read = 0;
2059 unsigned char c = 0; 2059 unsigned char c = 0;
@@ -2155,7 +2155,7 @@ more:{
2155 if (packet_bytes > 2) { 2155 if (packet_bytes > 2) {
2156 char diag[30 *3 + 4]; 2156 char diag[30 *3 + 4];
2157 char *d = diag; 2157 char *d = diag;
2158 int m = (sizeof(diag) - 1) / 3; 2158 int m = (sizeof(diag) - 1) / 3 - 1;
2159 char *b = ftdi->bulk_in_buffer; 2159 char *b = ftdi->bulk_in_buffer;
2160 int bytes_read = 0; 2160 int bytes_read = 0;
2161 diag[0] = 0; 2161 diag[0] = 0;