Commit aa929135 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for_linus-3.19-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/kgdb

Pull kgdb/kdb fixes from Jason Wessel:
 "These have been around since 3.17 and in kgdb-next for the last 9
  weeks and some will go back to -stable.

  Summary of changes:

  Cleanups
   - kdb: Remove unused command flags, repeat flags and KDB_REPEAT_NONE

  Fixes
   - kgdb/kdb: Allow access on a single core, if a CPU round up is
     deemed impossible, which will allow inspection of the now "trashed"
     kernel
   - kdb: Add enable mask for the command groups
   - kdb: access controls to restrict sensitive commands"

* tag 'for_linus-3.19-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/kgdb:
  kernel/debug/debug_core.c: Logging clean-up
  kgdb: timeout if secondary CPUs ignore the roundup
  kdb: Allow access to sensitive commands to be restricted by default
  kdb: Add enable mask for groups of commands
  kdb: Categorize kdb commands (similar to SysRq categorization)
  kdb: Remove KDB_REPEAT_NONE flag
  kdb: Use KDB_REPEAT_* values as flags
  kdb: Rename kdb_register_repeat() to kdb_register_flags()
  kdb: Rename kdb_repeat_t to kdb_cmdflags_t, cmd_repeat to cmd_flags
  kdb: Remove currently unused kdbtab_t->cmd_flags
parents dc9319f5 0f16996c
...@@ -13,11 +13,54 @@ ...@@ -13,11 +13,54 @@
* Copyright (C) 2009 Jason Wessel <jason.wessel@windriver.com> * Copyright (C) 2009 Jason Wessel <jason.wessel@windriver.com>
*/ */
/* Shifted versions of the command enable bits are be used if the command
* has no arguments (see kdb_check_flags). This allows commands, such as
* go, to have different permissions depending upon whether it is called
* with an argument.
*/
#define KDB_ENABLE_NO_ARGS_SHIFT 10
typedef enum { typedef enum {
KDB_REPEAT_NONE = 0, /* Do not repeat this command */ KDB_ENABLE_ALL = (1 << 0), /* Enable everything */
KDB_REPEAT_NO_ARGS, /* Repeat the command without arguments */ KDB_ENABLE_MEM_READ = (1 << 1),
KDB_REPEAT_WITH_ARGS, /* Repeat the command including its arguments */ KDB_ENABLE_MEM_WRITE = (1 << 2),
} kdb_repeat_t; KDB_ENABLE_REG_READ = (1 << 3),
KDB_ENABLE_REG_WRITE = (1 << 4),
KDB_ENABLE_INSPECT = (1 << 5),
KDB_ENABLE_FLOW_CTRL = (1 << 6),
KDB_ENABLE_SIGNAL = (1 << 7),
KDB_ENABLE_REBOOT = (1 << 8),
/* User exposed values stop here, all remaining flags are
* exclusively used to describe a commands behaviour.
*/
KDB_ENABLE_ALWAYS_SAFE = (1 << 9),
KDB_ENABLE_MASK = (1 << KDB_ENABLE_NO_ARGS_SHIFT) - 1,
KDB_ENABLE_ALL_NO_ARGS = KDB_ENABLE_ALL << KDB_ENABLE_NO_ARGS_SHIFT,
KDB_ENABLE_MEM_READ_NO_ARGS = KDB_ENABLE_MEM_READ
<< KDB_ENABLE_NO_ARGS_SHIFT,
KDB_ENABLE_MEM_WRITE_NO_ARGS = KDB_ENABLE_MEM_WRITE
<< KDB_ENABLE_NO_ARGS_SHIFT,
KDB_ENABLE_REG_READ_NO_ARGS = KDB_ENABLE_REG_READ
<< KDB_ENABLE_NO_ARGS_SHIFT,
KDB_ENABLE_REG_WRITE_NO_ARGS = KDB_ENABLE_REG_WRITE
<< KDB_ENABLE_NO_ARGS_SHIFT,
KDB_ENABLE_INSPECT_NO_ARGS = KDB_ENABLE_INSPECT
<< KDB_ENABLE_NO_ARGS_SHIFT,
KDB_ENABLE_FLOW_CTRL_NO_ARGS = KDB_ENABLE_FLOW_CTRL
<< KDB_ENABLE_NO_ARGS_SHIFT,
KDB_ENABLE_SIGNAL_NO_ARGS = KDB_ENABLE_SIGNAL
<< KDB_ENABLE_NO_ARGS_SHIFT,
KDB_ENABLE_REBOOT_NO_ARGS = KDB_ENABLE_REBOOT
<< KDB_ENABLE_NO_ARGS_SHIFT,
KDB_ENABLE_ALWAYS_SAFE_NO_ARGS = KDB_ENABLE_ALWAYS_SAFE
<< KDB_ENABLE_NO_ARGS_SHIFT,
KDB_ENABLE_MASK_NO_ARGS = KDB_ENABLE_MASK << KDB_ENABLE_NO_ARGS_SHIFT,
KDB_REPEAT_NO_ARGS = 0x40000000, /* Repeat the command w/o arguments */
KDB_REPEAT_WITH_ARGS = 0x80000000, /* Repeat the command with args */
} kdb_cmdflags_t;
typedef int (*kdb_func_t)(int, const char **); typedef int (*kdb_func_t)(int, const char **);
...@@ -62,6 +105,7 @@ extern atomic_t kdb_event; ...@@ -62,6 +105,7 @@ extern atomic_t kdb_event;
#define KDB_BADLENGTH (-19) #define KDB_BADLENGTH (-19)
#define KDB_NOBP (-20) #define KDB_NOBP (-20)
#define KDB_BADADDR (-21) #define KDB_BADADDR (-21)
#define KDB_NOPERM (-22)
/* /*
* kdb_diemsg * kdb_diemsg
...@@ -146,17 +190,17 @@ static inline const char *kdb_walk_kallsyms(loff_t *pos) ...@@ -146,17 +190,17 @@ static inline const char *kdb_walk_kallsyms(loff_t *pos)
/* Dynamic kdb shell command registration */ /* Dynamic kdb shell command registration */
extern int kdb_register(char *, kdb_func_t, char *, char *, short); extern int kdb_register(char *, kdb_func_t, char *, char *, short);
extern int kdb_register_repeat(char *, kdb_func_t, char *, char *, extern int kdb_register_flags(char *, kdb_func_t, char *, char *,
short, kdb_repeat_t); short, kdb_cmdflags_t);
extern int kdb_unregister(char *); extern int kdb_unregister(char *);
#else /* ! CONFIG_KGDB_KDB */ #else /* ! CONFIG_KGDB_KDB */
static inline __printf(1, 2) int kdb_printf(const char *fmt, ...) { return 0; } static inline __printf(1, 2) int kdb_printf(const char *fmt, ...) { return 0; }
static inline void kdb_init(int level) {} static inline void kdb_init(int level) {}
static inline int kdb_register(char *cmd, kdb_func_t func, char *usage, static inline int kdb_register(char *cmd, kdb_func_t func, char *usage,
char *help, short minlen) { return 0; } char *help, short minlen) { return 0; }
static inline int kdb_register_repeat(char *cmd, kdb_func_t func, char *usage, static inline int kdb_register_flags(char *cmd, kdb_func_t func, char *usage,
char *help, short minlen, char *help, short minlen,
kdb_repeat_t repeat) { return 0; } kdb_cmdflags_t flags) { return 0; }
static inline int kdb_unregister(char *cmd) { return 0; } static inline int kdb_unregister(char *cmd) { return 0; }
#endif /* CONFIG_KGDB_KDB */ #endif /* CONFIG_KGDB_KDB */
enum { enum {
......
...@@ -27,6 +27,9 @@ ...@@ -27,6 +27,9 @@
* version 2. This program is licensed "as is" without any warranty of any * version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied. * kind, whether express or implied.
*/ */
#define pr_fmt(fmt) "KGDB: " fmt
#include <linux/pid_namespace.h> #include <linux/pid_namespace.h>
#include <linux/clocksource.h> #include <linux/clocksource.h>
#include <linux/serial_core.h> #include <linux/serial_core.h>
...@@ -196,8 +199,8 @@ int __weak kgdb_validate_break_address(unsigned long addr) ...@@ -196,8 +199,8 @@ int __weak kgdb_validate_break_address(unsigned long addr)
return err; return err;
err = kgdb_arch_remove_breakpoint(&tmp); err = kgdb_arch_remove_breakpoint(&tmp);
if (err) if (err)
printk(KERN_ERR "KGDB: Critical breakpoint error, kernel " pr_err("Critical breakpoint error, kernel memory destroyed at: %lx\n",
"memory destroyed at: %lx", addr); addr);
return err; return err;
} }
...@@ -256,8 +259,8 @@ int dbg_activate_sw_breakpoints(void) ...@@ -256,8 +259,8 @@ int dbg_activate_sw_breakpoints(void)
error = kgdb_arch_set_breakpoint(&kgdb_break[i]); error = kgdb_arch_set_breakpoint(&kgdb_break[i]);
if (error) { if (error) {
ret = error; ret = error;
printk(KERN_INFO "KGDB: BP install failed: %lx", pr_info("BP install failed: %lx\n",
kgdb_break[i].bpt_addr); kgdb_break[i].bpt_addr);
continue; continue;
} }
...@@ -319,8 +322,8 @@ int dbg_deactivate_sw_breakpoints(void) ...@@ -319,8 +322,8 @@ int dbg_deactivate_sw_breakpoints(void)
continue; continue;
error = kgdb_arch_remove_breakpoint(&kgdb_break[i]); error = kgdb_arch_remove_breakpoint(&kgdb_break[i]);
if (error) { if (error) {
printk(KERN_INFO "KGDB: BP remove failed: %lx\n", pr_info("BP remove failed: %lx\n",
kgdb_break[i].bpt_addr); kgdb_break[i].bpt_addr);
ret = error; ret = error;
} }
...@@ -367,7 +370,7 @@ int dbg_remove_all_break(void) ...@@ -367,7 +370,7 @@ int dbg_remove_all_break(void)
goto setundefined; goto setundefined;
error = kgdb_arch_remove_breakpoint(&kgdb_break[i]); error = kgdb_arch_remove_breakpoint(&kgdb_break[i]);
if (error) if (error)
printk(KERN_ERR "KGDB: breakpoint remove failed: %lx\n", pr_err("breakpoint remove failed: %lx\n",
kgdb_break[i].bpt_addr); kgdb_break[i].bpt_addr);
setundefined: setundefined:
kgdb_break[i].state = BP_UNDEFINED; kgdb_break[i].state = BP_UNDEFINED;
...@@ -400,9 +403,9 @@ static int kgdb_io_ready(int print_wait) ...@@ -400,9 +403,9 @@ static int kgdb_io_ready(int print_wait)
if (print_wait) { if (print_wait) {
#ifdef CONFIG_KGDB_KDB #ifdef CONFIG_KGDB_KDB
if (!dbg_kdb_mode) if (!dbg_kdb_mode)
printk(KERN_CRIT "KGDB: waiting... or $3#33 for KDB\n"); pr_crit("waiting... or $3#33 for KDB\n");
#else #else
printk(KERN_CRIT "KGDB: Waiting for remote debugger\n"); pr_crit("Waiting for remote debugger\n");
#endif #endif
} }
return 1; return 1;
...@@ -430,8 +433,7 @@ static int kgdb_reenter_check(struct kgdb_state *ks) ...@@ -430,8 +433,7 @@ static int kgdb_reenter_check(struct kgdb_state *ks)
exception_level = 0; exception_level = 0;
kgdb_skipexception(ks->ex_vector, ks->linux_regs); kgdb_skipexception(ks->ex_vector, ks->linux_regs);
dbg_activate_sw_breakpoints(); dbg_activate_sw_breakpoints();
printk(KERN_CRIT "KGDB: re-enter error: breakpoint removed %lx\n", pr_crit("re-enter error: breakpoint removed %lx\n", addr);
addr);
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
return 1; return 1;
...@@ -444,7 +446,7 @@ static int kgdb_reenter_check(struct kgdb_state *ks) ...@@ -444,7 +446,7 @@ static int kgdb_reenter_check(struct kgdb_state *ks)
panic("Recursive entry to debugger"); panic("Recursive entry to debugger");
} }
printk(KERN_CRIT "KGDB: re-enter exception: ALL breakpoints killed\n"); pr_crit("re-enter exception: ALL breakpoints killed\n");
#ifdef CONFIG_KGDB_KDB #ifdef CONFIG_KGDB_KDB
/* Allow kdb to debug itself one level */ /* Allow kdb to debug itself one level */
return 0; return 0;
...@@ -471,6 +473,7 @@ static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs, ...@@ -471,6 +473,7 @@ static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs,
int cpu; int cpu;
int trace_on = 0; int trace_on = 0;
int online_cpus = num_online_cpus(); int online_cpus = num_online_cpus();
u64 time_left;
kgdb_info[ks->cpu].enter_kgdb++; kgdb_info[ks->cpu].enter_kgdb++;
kgdb_info[ks->cpu].exception_state |= exception_state; kgdb_info[ks->cpu].exception_state |= exception_state;
...@@ -595,9 +598,13 @@ static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs, ...@@ -595,9 +598,13 @@ static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs,
/* /*
* Wait for the other CPUs to be notified and be waiting for us: * Wait for the other CPUs to be notified and be waiting for us:
*/ */
while (kgdb_do_roundup && (atomic_read(&masters_in_kgdb) + time_left = loops_per_jiffy * HZ;
atomic_read(&slaves_in_kgdb)) != online_cpus) while (kgdb_do_roundup && --time_left &&
(atomic_read(&masters_in_kgdb) + atomic_read(&slaves_in_kgdb)) !=
online_cpus)
cpu_relax(); cpu_relax();
if (!time_left)
pr_crit("KGDB: Timed out waiting for secondary CPUs.\n");
/* /*
* At this point the primary processor is completely * At this point the primary processor is completely
...@@ -795,15 +802,15 @@ static struct console kgdbcons = { ...@@ -795,15 +802,15 @@ static struct console kgdbcons = {
static void sysrq_handle_dbg(int key) static void sysrq_handle_dbg(int key)
{ {
if (!dbg_io_ops) { if (!dbg_io_ops) {
printk(KERN_CRIT "ERROR: No KGDB I/O module available\n"); pr_crit("ERROR: No KGDB I/O module available\n");
return; return;
} }
if (!kgdb_connected) { if (!kgdb_connected) {
#ifdef CONFIG_KGDB_KDB #ifdef CONFIG_KGDB_KDB
if (!dbg_kdb_mode) if (!dbg_kdb_mode)
printk(KERN_CRIT "KGDB or $3#33 for KDB\n"); pr_crit("KGDB or $3#33 for KDB\n");
#else #else
printk(KERN_CRIT "Entering KGDB\n"); pr_crit("Entering KGDB\n");
#endif #endif
} }
...@@ -945,7 +952,7 @@ static void kgdb_initial_breakpoint(void) ...@@ -945,7 +952,7 @@ static void kgdb_initial_breakpoint(void)
{ {
kgdb_break_asap = 0; kgdb_break_asap = 0;
printk(KERN_CRIT "kgdb: Waiting for connection from remote gdb...\n"); pr_crit("Waiting for connection from remote gdb...\n");
kgdb_breakpoint(); kgdb_breakpoint();
} }
...@@ -964,8 +971,7 @@ int kgdb_register_io_module(struct kgdb_io *new_dbg_io_ops) ...@@ -964,8 +971,7 @@ int kgdb_register_io_module(struct kgdb_io *new_dbg_io_ops)
if (dbg_io_ops) { if (dbg_io_ops) {
spin_unlock(&kgdb_registration_lock); spin_unlock(&kgdb_registration_lock);
printk(KERN_ERR "kgdb: Another I/O driver is already " pr_err("Another I/O driver is already registered with KGDB\n");
"registered with KGDB.\n");
return -EBUSY; return -EBUSY;
} }
...@@ -981,8 +987,7 @@ int kgdb_register_io_module(struct kgdb_io *new_dbg_io_ops) ...@@ -981,8 +987,7 @@ int kgdb_register_io_module(struct kgdb_io *new_dbg_io_ops)
spin_unlock(&kgdb_registration_lock); spin_unlock(&kgdb_registration_lock);
printk(KERN_INFO "kgdb: Registered I/O driver %s.\n", pr_info("Registered I/O driver %s\n", new_dbg_io_ops->name);
new_dbg_io_ops->name);
/* Arm KGDB now. */ /* Arm KGDB now. */
kgdb_register_callbacks(); kgdb_register_callbacks();
...@@ -1017,8 +1022,7 @@ void kgdb_unregister_io_module(struct kgdb_io *old_dbg_io_ops) ...@@ -1017,8 +1022,7 @@ void kgdb_unregister_io_module(struct kgdb_io *old_dbg_io_ops)
spin_unlock(&kgdb_registration_lock); spin_unlock(&kgdb_registration_lock);
printk(KERN_INFO pr_info("Unregistered I/O driver %s, debugger disabled\n",
"kgdb: Unregistered I/O driver %s, debugger disabled.\n",
old_dbg_io_ops->name); old_dbg_io_ops->name);
} }
EXPORT_SYMBOL_GPL(kgdb_unregister_io_module); EXPORT_SYMBOL_GPL(kgdb_unregister_io_module);
......
...@@ -531,22 +531,29 @@ void __init kdb_initbptab(void) ...@@ -531,22 +531,29 @@ void __init kdb_initbptab(void)
for (i = 0, bp = kdb_breakpoints; i < KDB_MAXBPT; i++, bp++) for (i = 0, bp = kdb_breakpoints; i < KDB_MAXBPT; i++, bp++)
bp->bp_free = 1; bp->bp_free = 1;
kdb_register_repeat("bp", kdb_bp, "[<vaddr>]", kdb_register_flags("bp", kdb_bp, "[<vaddr>]",
"Set/Display breakpoints", 0, KDB_REPEAT_NO_ARGS); "Set/Display breakpoints", 0,
kdb_register_repeat("bl", kdb_bp, "[<vaddr>]", KDB_ENABLE_FLOW_CTRL | KDB_REPEAT_NO_ARGS);
"Display breakpoints", 0, KDB_REPEAT_NO_ARGS); kdb_register_flags("bl", kdb_bp, "[<vaddr>]",
"Display breakpoints", 0,
KDB_ENABLE_FLOW_CTRL | KDB_REPEAT_NO_ARGS);
if (arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT) if (arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT)
kdb_register_repeat("bph", kdb_bp, "[<vaddr>]", kdb_register_flags("bph", kdb_bp, "[<vaddr>]",
"[datar [length]|dataw [length]] Set hw brk", 0, KDB_REPEAT_NO_ARGS); "[datar [length]|dataw [length]] Set hw brk", 0,
kdb_register_repeat("bc", kdb_bc, "<bpnum>", KDB_ENABLE_FLOW_CTRL | KDB_REPEAT_NO_ARGS);
"Clear Breakpoint", 0, KDB_REPEAT_NONE); kdb_register_flags("bc", kdb_bc, "<bpnum>",
kdb_register_repeat("be", kdb_bc, "<bpnum>", "Clear Breakpoint", 0,
"Enable Breakpoint", 0, KDB_REPEAT_NONE); KDB_ENABLE_FLOW_CTRL);
kdb_register_repeat("bd", kdb_bc, "<bpnum>", kdb_register_flags("be", kdb_bc, "<bpnum>",
"Disable Breakpoint", 0, KDB_REPEAT_NONE); "Enable Breakpoint", 0,
KDB_ENABLE_FLOW_CTRL);
kdb_register_repeat("ss", kdb_ss, "", kdb_register_flags("bd", kdb_bc, "<bpnum>",
"Single Step", 1, KDB_REPEAT_NO_ARGS); "Disable Breakpoint", 0,
KDB_ENABLE_FLOW_CTRL);
kdb_register_flags("ss", kdb_ss, "",
"Single Step", 1,
KDB_ENABLE_FLOW_CTRL | KDB_REPEAT_NO_ARGS);
/* /*
* Architecture dependent initialization. * Architecture dependent initialization.
*/ */
......
...@@ -129,6 +129,10 @@ int kdb_stub(struct kgdb_state *ks) ...@@ -129,6 +129,10 @@ int kdb_stub(struct kgdb_state *ks)
ks->pass_exception = 1; ks->pass_exception = 1;
KDB_FLAG_SET(CATASTROPHIC); KDB_FLAG_SET(CATASTROPHIC);
} }
/* set CATASTROPHIC if the system contains unresponsive processors */
for_each_online_cpu(i)
if (!kgdb_info[i].enter_kgdb)
KDB_FLAG_SET(CATASTROPHIC);
if (KDB_STATE(SSBPT) && reason == KDB_REASON_SSTEP) { if (KDB_STATE(SSBPT) && reason == KDB_REASON_SSTEP) {
KDB_STATE_CLEAR(SSBPT); KDB_STATE_CLEAR(SSBPT);
KDB_STATE_CLEAR(DOING_SS); KDB_STATE_CLEAR(DOING_SS);
......
This diff is collapsed.
...@@ -172,10 +172,9 @@ typedef struct _kdbtab { ...@@ -172,10 +172,9 @@ typedef struct _kdbtab {
kdb_func_t cmd_func; /* Function to execute command */ kdb_func_t cmd_func; /* Function to execute command */
char *cmd_usage; /* Usage String for this command */ char *cmd_usage; /* Usage String for this command */
char *cmd_help; /* Help message for this command */ char *cmd_help; /* Help message for this command */
short cmd_flags; /* Parsing flags */
short cmd_minlen; /* Minimum legal # command short cmd_minlen; /* Minimum legal # command
* chars required */ * chars required */
kdb_repeat_t cmd_repeat; /* Does command auto repeat on enter? */ kdb_cmdflags_t cmd_flags; /* Command behaviour flags */
} kdbtab_t; } kdbtab_t;
extern int kdb_bt(int, const char **); /* KDB display back trace */ extern int kdb_bt(int, const char **); /* KDB display back trace */
......
...@@ -132,8 +132,8 @@ static int kdb_ftdump(int argc, const char **argv) ...@@ -132,8 +132,8 @@ static int kdb_ftdump(int argc, const char **argv)
static __init int kdb_ftrace_register(void) static __init int kdb_ftrace_register(void)
{ {
kdb_register_repeat("ftdump", kdb_ftdump, "[skip_#lines] [cpu]", kdb_register_flags("ftdump", kdb_ftdump, "[skip_#lines] [cpu]",
"Dump ftrace log", 0, KDB_REPEAT_NONE); "Dump ftrace log", 0, KDB_ENABLE_ALWAYS_SAFE);
return 0; return 0;
} }
......
...@@ -73,6 +73,31 @@ config KGDB_KDB ...@@ -73,6 +73,31 @@ config KGDB_KDB
help help
KDB frontend for kernel KDB frontend for kernel
config KDB_DEFAULT_ENABLE
hex "KDB: Select kdb command functions to be enabled by default"
depends on KGDB_KDB
default 0x1
help
Specifiers which kdb commands are enabled by default. This may
be set to 1 or 0 to enable all commands or disable almost all
commands.
Alternatively the following bitmask applies:
0x0002 - allow arbitrary reads from memory and symbol lookup
0x0004 - allow arbitrary writes to memory
0x0008 - allow current register state to be inspected
0x0010 - allow current register state to be modified
0x0020 - allow passive inspection (backtrace, process list, lsmod)
0x0040 - allow flow control management (breakpoint, single step)
0x0080 - enable signalling of processes
0x0100 - allow machine to be rebooted
The config option merely sets the default at boot time. Both
issuing 'echo X > /sys/module/kdb/parameters/cmd_enable' or
setting with kdb.cmd_enable=X kernel command line option will
override the default settings.
config KDB_KEYBOARD config KDB_KEYBOARD
bool "KGDB_KDB: keyboard as input device" bool "KGDB_KDB: keyboard as input device"
depends on VT && KGDB_KDB depends on VT && KGDB_KDB
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment