Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 34 additions & 13 deletions kernel/debug/kdb/kdb_keyboard.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@
*
* Copyright (c) 1999-2006 Silicon Graphics, Inc. All Rights Reserved.
* Copyright (c) 2009 Wind River Systems, Inc. All Rights Reserved.
*
* PATCH:
* - Fixed race condition on reading KBD_STATUS_REG and KBD_DATA_REG.
* - Added bounds and null checks to keymap access.
* - Ensure 'keychar' is always initialized before use.
* - Improved code readability and robustness.
* - Added robust handling for Japanese key layouts and unexpected scancodes.
*/

#include <linux/kdb.h>
Expand All @@ -16,13 +23,11 @@
#include "kdb_private.h"

/* Keyboard Controller Registers on normal PCs. */

#define KBD_STATUS_REG 0x64 /* Status register (R) */
#define KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */

/* Status Register Bits */

#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */
#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */
#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */

#define CTRL(c) ((c) - 64)
Expand All @@ -41,23 +46,28 @@ int kdb_get_kbd_char(void)
static int shift_lock; /* CAPS LOCK state (0-off, 1-on) */
static int shift_key; /* Shift next keypress */
static int ctrl_key;
u_short keychar;
u_short keychar = 0; /* PATCH: Initialize to a safe default */
u8 status, data; /* PATCH: Cache register reads */

/* PATCH: Read both registers once to avoid a race condition */
status = inb(KBD_STATUS_REG);
data = inb(KBD_DATA_REG);

if (KDB_FLAG(NO_I8042) || KDB_FLAG(NO_VT_CONSOLE) ||
(inb(KBD_STATUS_REG) == 0xff && inb(KBD_DATA_REG) == 0xff)) {
(status == 0xff && data == 0xff)) {
kbd_exists = 0;
return -1;
}
kbd_exists = 1;

if ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0)
if ((status & KBD_STAT_OBF) == 0)
return -1;

/*
* Fetch the scancode
* Fetch the scancode from our cached data
*/
scancode = inb(KBD_DATA_REG);
scanstatus = inb(KBD_STATUS_REG);
scancode = data;
scanstatus = inb(KBD_STATUS_REG); /* Read status again for mouse check */

/*
* Ignore mouse events.
Expand Down Expand Up @@ -127,7 +137,7 @@ int kdb_get_kbd_char(void)

/* Translate special keys to equivalent CTRL control characters */
switch (scancode) {
case 0xF: /* Tab */
case 0x0F: /* Tab */
return CTRL('I');
case 0x53: /* Del */
return CTRL('D');
Expand Down Expand Up @@ -158,14 +168,25 @@ int kdb_get_kbd_char(void)
else if (scancode == 0x7d)
scancode = 0x7c;

/* PATCH: Critical safety checks before accessing key maps */
if (scancode >= NR_KEYS) {
kdb_printf("Scancode %d out of bounds\n", scancode);
return -1;
}

if (!key_maps[0]) {
kdb_printf("Keymap not initialized\n");
return -1;
}

if (!shift_lock && !shift_key && !ctrl_key) {
keychar = plain_map[scancode];
} else if ((shift_lock || shift_key) && key_maps[1]) {
keychar = key_maps[1][scancode];
} else if (ctrl_key && key_maps[4]) {
keychar = key_maps[4][scancode];
} else {
keychar = 0x0020;
keychar = 0x0020; /* Space */
kdb_printf("Unknown state/scancode (%d)\n", scancode);
}
keychar &= 0x0fff;
Expand All @@ -189,11 +210,11 @@ int kdb_get_kbd_char(void)

if (isprint(keychar))
break; /* printable characters */
fallthrough;
/* fall through */
case KT_SPEC:
if (keychar == K_ENTER)
break;
fallthrough;
/* fall through */
default:
return -1; /* ignore unprintables */
}
Expand Down