Bug 98925

Summary: [PATCH] heap-buffer-overflow in libtsm tsm_screen_tab_left()
Product: kmscon Reporter: Kuang-che Wu <kcwu>
Component: libtsmAssignee: David Herrmann <dh.herrmann>
Status: NEW --- QA Contact:
Severity: normal    
Priority: medium    
Version: unspecified   
Hardware: Other   
OS: All   
Whiteboard:
i915 platform: i915 features:
Attachments: testcase

Description Kuang-che Wu 2016-12-01 14:01:33 UTC
Created attachment 128300 [details]
testcase

testcase attached. detail reproduce steps please see 
https://github.com/google/oss-fuzz/blob/master/docs/reproducing.md
and
https://github.com/google/oss-fuzz/tree/master/projects/libtsm

What happened
1. cursor_x=79 and tsm_screen_write() an unicode character (width=2).
1098         move_cursor(con, con->cursor_x + len, con->cursor_y);
cursor_x became 81.

2. tsm_screen_tab_left()
1318         x = con->cursor_x;
1319         for (i = 0; i < num; ++i) {
1320                 for (j = x - 1; j > 0; --j) {
1321                         if (con->tab_ruler[j])
x=81 at line 1318. j=x-1. Buffer overflow read when access tab_ruler[80] because the size of tab_ruler is only 80.

Here is my patch, simply limit max of x to size_x. I think this is correct fix because this pattern exists in libtsm many times.

diff --git a/src/tsm/tsm-screen.c b/src/tsm/tsm-screen.c
index 2004d9f..aacdf8e 100644
--- a/src/tsm/tsm-screen.c
+++ b/src/tsm/tsm-screen.c
@@ -1316,6 +1316,8 @@ void tsm_screen_tab_left(struct tsm_screen *con, unsigned int num)
        screen_inc_age(con);

        x = con->cursor_x;
+       if (x > con->size_x)
+               x = con->size_x;
        for (i = 0; i < num; ++i) {
                for (j = x - 1; j > 0; --j) {
                        if (con->tab_ruler[j])




Finally, following is ASAN report.
==294918==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60700000df90 at pc 0x0000005038d8 bp 0x7ffc4f901ab0 sp 0x7ffc4f901aa8
READ of size 1 at 0x60700000df90 thread T0
    #0 0x5038d7 in tsm_screen_tab_left /oss-fuzz/projects/libtsm/libtsm/src/tsm/tsm-screen.c:1321:8
    #1 0x517110 in do_csi /oss-fuzz/projects/libtsm/libtsm/src/tsm/tsm-vte.c:1722:3
    #2 0x513368 in do_action /oss-fuzz/projects/libtsm/libtsm/src/tsm/tsm-vte.c:1812:4
    #3 0x5131b2 in do_trans /oss-fuzz/projects/libtsm/libtsm/src/tsm/tsm-vte.c:1858:3
    #4 0x50e250 in parse_data /oss-fuzz/projects/libtsm/libtsm/src/tsm/tsm-vte.c:2002:4
    #5 0x50db71 in tsm_vte_input /oss-fuzz/projects/libtsm/libtsm/src/tsm/tsm-vte.c:2237:5
    #6 0x4f6bb7 in LLVMFuzzerTestOneInput /oss-fuzz/projects/libtsm/libtsm/../libtsm_fuzzer.c:44:3
    #7 0x529b57 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /fuzz/Fuzzer/./FuzzerLoop.cpp:515:13
    #8 0x529d45 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long) /fuzz/Fuzzer/./FuzzerLoop.cpp:469:3
    #9 0x520875 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /fuzz/Fuzzer/./FuzzerDriver.cpp:272:3
    #10 0x5225a9 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /fuzz/Fuzzer/./FuzzerDriver.cpp:482:9
    #11 0x5207d0 in main /fuzz/Fuzzer/./FuzzerMain.cpp:20:10
    #12 0x7f847e40cf44 in __libc_start_main /build/eglibc-oGUzwX/eglibc-2.19/csu/libc-start.c:287
    #13 0x41b797 in _start (/oss-fuzz/projects/libtsm/libtsm_fuzzer+0x41b797)

0x60700000df90 is located 0 bytes to the right of 80-byte region [0x60700000df40,0x60700000df90)
allocated by thread T0 here:
    #0 0x4c5e9d in realloc (/oss-fuzz/projects/libtsm/libtsm_fuzzer+0x4c5e9d)
    #1 0x4fa28c in tsm_screen_resize /oss-fuzz/projects/libtsm/libtsm/src/tsm/tsm-screen.c:652:15
    #2 0x4f951f in tsm_screen_new /oss-fuzz/projects/libtsm/libtsm/src/tsm/tsm-screen.c:490:8
    #3 0x4f6acb in LLVMFuzzerTestOneInput /oss-fuzz/projects/libtsm/libtsm/../libtsm_fuzzer.c:39:3
    #4 0x529b57 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /fuzz/Fuzzer/./FuzzerLoop.cpp:515:13
    #5 0x529d45 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long) /fuzz/Fuzzer/./FuzzerLoop.cpp:469:3
    #6 0x520875 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /fuzz/Fuzzer/./FuzzerDriver.cpp:272:3
    #7 0x5225a9 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /fuzz/Fuzzer/./FuzzerDriver.cpp:482:9
    #8 0x5207d0 in main /fuzz/Fuzzer/./FuzzerMain.cpp:20:10
    #9 0x7f847e40cf44 in __libc_start_main /build/eglibc-oGUzwX/eglibc-2.19/csu/libc-start.c:287

SUMMARY: AddressSanitizer: heap-buffer-overflow /oss-fuzz/projects/libtsm/libtsm/src/tsm/tsm-screen.c:1321:8 in tsm_screen_tab_left
Shadow bytes around the buggy address:
  0x0c0e7fff9ba0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0e7fff9bb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0e7fff9bc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0e7fff9bd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0e7fff9be0: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
=>0x0c0e7fff9bf0: 00 00[fa]fa fa fa 00 00 00 00 00 00 00 00 00 fa
  0x0c0e7fff9c00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0e7fff9c10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0e7fff9c20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0e7fff9c30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0e7fff9c40: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==294918==ABORTING

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.