diff options
author | Xiao Han <xiao.han@orange.fr> | 2016-06-14 10:22:54 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-08-09 09:45:59 -0400 |
commit | 9c6256a5e707a9eb8b91962b550050b13aa75334 (patch) | |
tree | bfd9bd5a35e7648fffe2353e36259b50cb0369cd | |
parent | 28324936f3d672bbf83472fece8f36a158a52276 (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.c | 10 |
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; |