Hi everybody,

I've spent the day debugging a kernel crash in the USB networking code to find 
out the problem was caused by a buffer overrun in the TWL4030 keypad driver. 

The Nokia RX51 board code (arch/arm/mach-omap2/board-rx51-peripherals.c) 
defines a key map for the matrix keypad keyboard. The hardware seems to use 
all of the 8 rows and 8 columns of the keypad, although not all possible 
locations are used.

The TWL4030 supports keypads with at most 8 rows and 8 columns. Most keys are 
defined with a row and column number between 0 and 7, except

        KEY(0xff, 2, KEY_F9),
        KEY(0xff, 4, KEY_F10),
        KEY(0xff, 5, KEY_F11),

The row number is set to 0xff. As the generic matrix keypad support 
(include/linux/input/matrix_keypad.h) supports at most 16 rows and 16 columns, 
it masks all but the lower 4 bits of the row and column numbers in the KEY 
macro.

#define MATRIX_MAX_ROWS         16
#define MATRIX_MAX_COLS         16

#define KEY(row, col, val)      ((((row) & (MATRIX_MAX_ROWS - 1)) << 24) |\
                                 (((col) & (MATRIX_MAX_COLS - 1)) << 16) |\
                                 (val & 0xffff))

This leads to an effective row number equal to 15.

The TWL4030 keypad driver (drivers/input/keyboard/twl4030_keypad.c) allocates 
in twl4030_kp_probe a 8x8 keycodes map, part of the twl4030_keypad structure.

#define TWL4030_MAX_ROWS        8       /* TWL4030 hard limit */
#define TWL4030_MAX_COLS        8
#define TWL4030_ROW_SHIFT       3
#define TWL4030_KEYMAP_SIZE     (TWL4030_MAX_ROWS * TWL4030_MAX_COLS)

struct twl4030_keypad {
        unsigned short  keymap[TWL4030_KEYMAP_SIZE];
...

It then calls matrix_keypad_build_keymap (include/linux/input/matrix_keypad.h) 
to initialize the keycodes map from the keymap defined in platform data. The 
function loops over all the keymap platform data entries, and initializes the 
corresponding keycodes map entry. The entry index is computed with

#define MATRIX_SCAN_CODE(row, col, row_shift)   (((row) << (row_shift)) + 
(col))

called with row_shift set to TWL4030_ROW_SHIFT, defined as 3.

For the 3 keys defined with a row equal to 0xff, the map entry index is then 
equal to (15 << 3) + col, which is bigger than the number of keycodes map 
entries in the twl4030_keypad structure. Writing to that invalid index 
overwrites random memory.

The 0xff row number is used to detect rows completely connected to ground (see 
the comment in twl4030_col_xlate, drivers/input/keyboard/twl4030_keypad.c). 
The related code in twl4030_col_xlate is obviously wrong, returning a column 
number too large for the allocated keycodes map if the hardware keypad has 8 
columns.

I can try to provide a patch, but I'm not familiar enough with the TWL4030 
keypad driver and the generic matrix keypad code to know what the best fix 
would be. Hopefully this should be quite clear for the TWL4030 keypad driver 
developers.

-- 
Regards,

Laurent Pinchart
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to