kgdb patches for 5.10-rc1
A fairly modest set of changes for this cycle. Of particular note are an earlycon fix from Doug Anderson and my own changes to get kgdb/kdb to honour the kprobe blocklist. The later creates a safety rail that strongly encourages developers not to place breakpoints in, for example, arch specific trap handling code. Also included are a couple of small fixes and tweaks: an API update, eliminate a coverity dead code warning, improved handling of search during multi-line printk and a couple of typo corrections. Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org> -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEELzVBU1D3lWq6cKzwfOMlXTn3iKEFAl+IdyAACgkQfOMlXTn3 iKHeTw//RDAWm0IU00z9+ZlTyksTk0vePuYKwgEm8zp+XYvY0NvpgWyZ5MWd8b3K WJmsTfXMHNoPCg3464XCrQDyIhrfhxk0nrdOpgbsQMb7HdjYrnltPdG3l8W9kvVv MjMH98QOBaYAY75nd8pGoPVTOmODrhowWo6+y4me2CnJGKOOV/yHmctBhlOJhbeo TCUIDP/NmC63N8Oziteym1TZ5dhschBb/85qEb72wXaiGEZTaVC9GEFEgCqfADHX 51KxbtZoJWirbXu2aYaK5MHEb/0NWPMItiER7y8ZrTiPHMRre4N5DpCMpKpp3/qd YRtEnNnT+Ay0ijCt2FjznSsEh2ecLI0qSO4QDQz320QJCj7qgcjJ0++yEayrzz8W IxCbwkUP8X5m1srXSxvOTKfuu29wiMCqNkJA0rgjpA2u4Yn5KO0ZRmBoHtW1Sq8E MhbRTixU/vFYosjd/mKubj/f4DFrMILo+FJTqdewBUhT/Q6Vr9l660JzvwWnKKJF e1EHNYtWo4J+EkL9z++5d9PzDl0d56DcE8rfH53Dkg075Wnma3tdq2Z7WxT3M7EP K3U32BI9obu+lPHxl4FtAobCIDjP6NtmmMo3zzzA1fPtXNzAjy7qZ+Ss6POQppkn 7v+PFYdFJ8VKo3PNxMWnFhgwSDOYYxCPjCxs+bjaMBvHNVgg2Ig= =x91W -----END PGP SIGNATURE----- Merge tag 'kgdb-5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/danielt/linux Pull kgdb updates from Daniel Thompson: "A fairly modest set of changes for this cycle. Of particular note are an earlycon fix from Doug Anderson and my own changes to get kgdb/kdb to honour the kprobe blocklist. The later creates a safety rail that strongly encourages developers not to place breakpoints in, for example, arch specific trap handling code. Also included are a couple of small fixes and tweaks: an API update, eliminate a coverity dead code warning, improved handling of search during multi-line printk and a couple of typo corrections" * tag 'kgdb-5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/danielt/linux: kdb: Fix pager search for multi-line strings kernel: debug: Centralize dbg_[de]activate_sw_breakpoints kgdb: Add NOKPROBE labels on the trap handler functions kgdb: Honour the kprobe blocklist when setting breakpoints kernel/debug: Fix spelling mistake in debug_core.c kdb: Use newer api for tasklist scanning kgdb: Make "kgdbcon" work properly with "kgdb_earlycon" kdb: remove unnecessary null check of dbg_io_ops
This commit is contained in:
		
						commit
						49dc6fbce3
					
				| @ -16,6 +16,7 @@ | ||||
| #include <linux/linkage.h> | ||||
| #include <linux/init.h> | ||||
| #include <linux/atomic.h> | ||||
| #include <linux/kprobes.h> | ||||
| #ifdef CONFIG_HAVE_ARCH_KGDB | ||||
| #include <asm/kgdb.h> | ||||
| #endif | ||||
| @ -335,6 +336,23 @@ extern int kgdb_nmicallin(int cpu, int trapnr, void *regs, int err_code, | ||||
| 			  atomic_t *snd_rdy); | ||||
| extern void gdbstub_exit(int status); | ||||
| 
 | ||||
| /*
 | ||||
|  * kgdb and kprobes both use the same (kprobe) blocklist (which makes sense | ||||
|  * given they are both typically hooked up to the same trap meaning on most | ||||
|  * architectures one cannot be used to debug the other) | ||||
|  * | ||||
|  * However on architectures where kprobes is not (yet) implemented we permit | ||||
|  * breakpoints everywhere rather than blocking everything by default. | ||||
|  */ | ||||
| static inline bool kgdb_within_blocklist(unsigned long addr) | ||||
| { | ||||
| #ifdef CONFIG_KGDB_HONOUR_BLOCKLIST | ||||
| 	return within_kprobe_blacklist(addr); | ||||
| #else | ||||
| 	return false; | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| extern int			kgdb_single_step; | ||||
| extern atomic_t			kgdb_active; | ||||
| #define in_dbg_master() \ | ||||
|  | ||||
| @ -80,7 +80,7 @@ static int			exception_level; | ||||
| struct kgdb_io		*dbg_io_ops; | ||||
| static DEFINE_SPINLOCK(kgdb_registration_lock); | ||||
| 
 | ||||
| /* Action for the reboot notifiter, a global allow kdb to change it */ | ||||
| /* Action for the reboot notifier, a global allow kdb to change it */ | ||||
| static int kgdbreboot; | ||||
| /* kgdb console driver is loaded */ | ||||
| static int kgdb_con_registered; | ||||
| @ -94,14 +94,6 @@ int dbg_switch_cpu; | ||||
| /* Use kdb or gdbserver mode */ | ||||
| int dbg_kdb_mode = 1; | ||||
| 
 | ||||
| static int __init opt_kgdb_con(char *str) | ||||
| { | ||||
| 	kgdb_use_con = 1; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| early_param("kgdbcon", opt_kgdb_con); | ||||
| 
 | ||||
| module_param(kgdb_use_con, int, 0644); | ||||
| module_param(kgdbreboot, int, 0644); | ||||
| 
 | ||||
| @ -163,7 +155,7 @@ early_param("nokgdbroundup", opt_nokgdbroundup); | ||||
| 
 | ||||
| /*
 | ||||
|  * Weak aliases for breakpoint management, | ||||
|  * can be overriden by architectures when needed: | ||||
|  * can be overridden by architectures when needed: | ||||
|  */ | ||||
| int __weak kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt) | ||||
| { | ||||
| @ -177,17 +169,23 @@ int __weak kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt) | ||||
| 				 arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE); | ||||
| 	return err; | ||||
| } | ||||
| NOKPROBE_SYMBOL(kgdb_arch_set_breakpoint); | ||||
| 
 | ||||
| int __weak kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt) | ||||
| { | ||||
| 	return copy_to_kernel_nofault((char *)bpt->bpt_addr, | ||||
| 				  (char *)bpt->saved_instr, BREAK_INSTR_SIZE); | ||||
| } | ||||
| NOKPROBE_SYMBOL(kgdb_arch_remove_breakpoint); | ||||
| 
 | ||||
| int __weak kgdb_validate_break_address(unsigned long addr) | ||||
| { | ||||
| 	struct kgdb_bkpt tmp; | ||||
| 	int err; | ||||
| 
 | ||||
| 	if (kgdb_within_blocklist(addr)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	/* Validate setting the breakpoint and then removing it.  If the
 | ||||
| 	 * remove fails, the kernel needs to emit a bad message because we | ||||
| 	 * are deep trouble not being able to put things back the way we | ||||
| @ -208,6 +206,7 @@ unsigned long __weak kgdb_arch_pc(int exception, struct pt_regs *regs) | ||||
| { | ||||
| 	return instruction_pointer(regs); | ||||
| } | ||||
| NOKPROBE_SYMBOL(kgdb_arch_pc); | ||||
| 
 | ||||
| int __weak kgdb_arch_init(void) | ||||
| { | ||||
| @ -218,6 +217,7 @@ int __weak kgdb_skipexception(int exception, struct pt_regs *regs) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| NOKPROBE_SYMBOL(kgdb_skipexception); | ||||
| 
 | ||||
| #ifdef CONFIG_SMP | ||||
| 
 | ||||
| @ -239,6 +239,7 @@ void __weak kgdb_call_nmi_hook(void *ignored) | ||||
| 	 */ | ||||
| 	kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs()); | ||||
| } | ||||
| NOKPROBE_SYMBOL(kgdb_call_nmi_hook); | ||||
| 
 | ||||
| void __weak kgdb_roundup_cpus(void) | ||||
| { | ||||
| @ -272,6 +273,7 @@ void __weak kgdb_roundup_cpus(void) | ||||
| 			kgdb_info[cpu].rounding_up = false; | ||||
| 	} | ||||
| } | ||||
| NOKPROBE_SYMBOL(kgdb_roundup_cpus); | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| @ -298,6 +300,7 @@ static void kgdb_flush_swbreak_addr(unsigned long addr) | ||||
| 	/* Force flush instruction cache if it was outside the mm */ | ||||
| 	flush_icache_range(addr, addr + BREAK_INSTR_SIZE); | ||||
| } | ||||
| NOKPROBE_SYMBOL(kgdb_flush_swbreak_addr); | ||||
| 
 | ||||
| /*
 | ||||
|  * SW breakpoint management: | ||||
| @ -325,6 +328,7 @@ int dbg_activate_sw_breakpoints(void) | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
| NOKPROBE_SYMBOL(dbg_activate_sw_breakpoints); | ||||
| 
 | ||||
| int dbg_set_sw_break(unsigned long addr) | ||||
| { | ||||
| @ -388,6 +392,7 @@ int dbg_deactivate_sw_breakpoints(void) | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
| NOKPROBE_SYMBOL(dbg_deactivate_sw_breakpoints); | ||||
| 
 | ||||
| int dbg_remove_sw_break(unsigned long addr) | ||||
| { | ||||
| @ -509,6 +514,7 @@ static int kgdb_io_ready(int print_wait) | ||||
| 	} | ||||
| 	return 1; | ||||
| } | ||||
| NOKPROBE_SYMBOL(kgdb_io_ready); | ||||
| 
 | ||||
| static int kgdb_reenter_check(struct kgdb_state *ks) | ||||
| { | ||||
| @ -556,6 +562,7 @@ static int kgdb_reenter_check(struct kgdb_state *ks) | ||||
| 
 | ||||
| 	return 1; | ||||
| } | ||||
| NOKPROBE_SYMBOL(kgdb_reenter_check); | ||||
| 
 | ||||
| static void dbg_touch_watchdogs(void) | ||||
| { | ||||
| @ -563,6 +570,7 @@ static void dbg_touch_watchdogs(void) | ||||
| 	clocksource_touch_watchdog(); | ||||
| 	rcu_cpu_stall_reset(); | ||||
| } | ||||
| NOKPROBE_SYMBOL(dbg_touch_watchdogs); | ||||
| 
 | ||||
| static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs, | ||||
| 		int exception_state) | ||||
| @ -752,6 +760,8 @@ cpu_master_loop: | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	dbg_activate_sw_breakpoints(); | ||||
| 
 | ||||
| 	/* Call the I/O driver's post_exception routine */ | ||||
| 	if (dbg_io_ops->post_exception) | ||||
| 		dbg_io_ops->post_exception(); | ||||
| @ -794,6 +804,7 @@ kgdb_restore: | ||||
| 
 | ||||
| 	return kgdb_info[cpu].ret_state; | ||||
| } | ||||
| NOKPROBE_SYMBOL(kgdb_cpu_enter); | ||||
| 
 | ||||
| /*
 | ||||
|  * kgdb_handle_exception() - main entry point from a kernel exception | ||||
| @ -838,6 +849,7 @@ out: | ||||
| 		arch_kgdb_ops.enable_nmi(1); | ||||
| 	return ret; | ||||
| } | ||||
| NOKPROBE_SYMBOL(kgdb_handle_exception); | ||||
| 
 | ||||
| /*
 | ||||
|  * GDB places a breakpoint at this function to know dynamically loaded objects. | ||||
| @ -872,6 +884,7 @@ int kgdb_nmicallback(int cpu, void *regs) | ||||
| #endif | ||||
| 	return 1; | ||||
| } | ||||
| NOKPROBE_SYMBOL(kgdb_nmicallback); | ||||
| 
 | ||||
| int kgdb_nmicallin(int cpu, int trapnr, void *regs, int err_code, | ||||
| 							atomic_t *send_ready) | ||||
| @ -897,6 +910,7 @@ int kgdb_nmicallin(int cpu, int trapnr, void *regs, int err_code, | ||||
| #endif | ||||
| 	return 1; | ||||
| } | ||||
| NOKPROBE_SYMBOL(kgdb_nmicallin); | ||||
| 
 | ||||
| static void kgdb_console_write(struct console *co, const char *s, | ||||
|    unsigned count) | ||||
| @ -920,6 +934,20 @@ static struct console kgdbcons = { | ||||
| 	.index		= -1, | ||||
| }; | ||||
| 
 | ||||
| static int __init opt_kgdb_con(char *str) | ||||
| { | ||||
| 	kgdb_use_con = 1; | ||||
| 
 | ||||
| 	if (kgdb_io_module_registered && !kgdb_con_registered) { | ||||
| 		register_console(&kgdbcons); | ||||
| 		kgdb_con_registered = 1; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| early_param("kgdbcon", opt_kgdb_con); | ||||
| 
 | ||||
| #ifdef CONFIG_MAGIC_SYSRQ | ||||
| static void sysrq_handle_dbg(int key) | ||||
| { | ||||
|  | ||||
| @ -725,7 +725,7 @@ static void gdb_cmd_query(struct kgdb_state *ks) | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		do_each_thread(g, p) { | ||||
| 		for_each_process_thread(g, p) { | ||||
| 			if (i >= ks->thr_query && !finished) { | ||||
| 				int_to_threadref(thref, p->pid); | ||||
| 				ptr = pack_threadid(ptr, thref); | ||||
| @ -735,7 +735,7 @@ static void gdb_cmd_query(struct kgdb_state *ks) | ||||
| 					finished = 1; | ||||
| 			} | ||||
| 			i++; | ||||
| 		} while_each_thread(g, p); | ||||
| 		} | ||||
| 
 | ||||
| 		*(--ptr) = '\0'; | ||||
| 		break; | ||||
| @ -1061,7 +1061,6 @@ int gdb_serial_stub(struct kgdb_state *ks) | ||||
| 				error_packet(remcom_out_buffer, -EINVAL); | ||||
| 				break; | ||||
| 			} | ||||
| 			dbg_activate_sw_breakpoints(); | ||||
| 			fallthrough;	/* to default processing */ | ||||
| 		default: | ||||
| default_handle: | ||||
|  | ||||
| @ -306,6 +306,15 @@ static int kdb_bp(int argc, const char **argv) | ||||
| 	if (!template.bp_addr) | ||||
| 		return KDB_BADINT; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * This check is redundant (since the breakpoint machinery should | ||||
| 	 * be doing the same check during kdb_bp_install) but gives the | ||||
| 	 * user immediate feedback. | ||||
| 	 */ | ||||
| 	diag = kgdb_validate_break_address(template.bp_addr); | ||||
| 	if (diag) | ||||
| 		return diag; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Find an empty bp structure to allocate | ||||
| 	 */ | ||||
|  | ||||
| @ -149,14 +149,14 @@ kdb_bt(int argc, const char **argv) | ||||
| 				return 0; | ||||
| 		} | ||||
| 		/* Now the inactive tasks */ | ||||
| 		kdb_do_each_thread(g, p) { | ||||
| 		for_each_process_thread(g, p) { | ||||
| 			if (KDB_FLAG(CMD_INTERRUPT)) | ||||
| 				return 0; | ||||
| 			if (task_curr(p)) | ||||
| 				continue; | ||||
| 			if (kdb_bt1(p, mask, btaprompt)) | ||||
| 				return 0; | ||||
| 		} kdb_while_each_thread(g, p); | ||||
| 		} | ||||
| 	} else if (strcmp(argv[0], "btp") == 0) { | ||||
| 		struct task_struct *p; | ||||
| 		unsigned long pid; | ||||
|  | ||||
| @ -147,7 +147,6 @@ int kdb_stub(struct kgdb_state *ks) | ||||
| 		return DBG_PASS_EVENT; | ||||
| 	} | ||||
| 	kdb_bp_install(ks->linux_regs); | ||||
| 	dbg_activate_sw_breakpoints(); | ||||
| 	/* Set the exit state to a single step or a continue */ | ||||
| 	if (KDB_STATE(DOING_SS)) | ||||
| 		gdbstub_state(ks, "s"); | ||||
| @ -167,7 +166,6 @@ int kdb_stub(struct kgdb_state *ks) | ||||
| 		 * differently vs the gdbstub | ||||
| 		 */ | ||||
| 		kgdb_single_step = 0; | ||||
| 		dbg_deactivate_sw_breakpoints(); | ||||
| 		return DBG_SWITCH_CPU_EVENT; | ||||
| 	} | ||||
| 	return kgdb_info[ks->cpu].ret_state; | ||||
|  | ||||
| @ -545,18 +545,18 @@ static int kdb_search_string(char *searched, char *searchfor) | ||||
| static void kdb_msg_write(const char *msg, int msg_len) | ||||
| { | ||||
| 	struct console *c; | ||||
| 	const char *cp; | ||||
| 	int len; | ||||
| 
 | ||||
| 	if (msg_len == 0) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (dbg_io_ops) { | ||||
| 		const char *cp = msg; | ||||
| 		int len = msg_len; | ||||
| 	cp = msg; | ||||
| 	len = msg_len; | ||||
| 
 | ||||
| 		while (len--) { | ||||
| 			dbg_io_ops->write_char(*cp); | ||||
| 			cp++; | ||||
| 		} | ||||
| 	while (len--) { | ||||
| 		dbg_io_ops->write_char(*cp); | ||||
| 		cp++; | ||||
| 	} | ||||
| 
 | ||||
| 	for_each_console(c) { | ||||
| @ -706,12 +706,16 @@ int vkdb_printf(enum kdb_msgsrc src, const char *fmt, va_list ap) | ||||
| 			size_avail = sizeof(kdb_buffer) - len; | ||||
| 			goto kdb_print_out; | ||||
| 		} | ||||
| 		if (kdb_grepping_flag >= KDB_GREPPING_FLAG_SEARCH) | ||||
| 		if (kdb_grepping_flag >= KDB_GREPPING_FLAG_SEARCH) { | ||||
| 			/*
 | ||||
| 			 * This was a interactive search (using '/' at more | ||||
| 			 * prompt) and it has completed. Clear the flag. | ||||
| 			 * prompt) and it has completed. Replace the \0 with | ||||
| 			 * its original value to ensure multi-line strings | ||||
| 			 * are handled properly, and return to normal mode. | ||||
| 			 */ | ||||
| 			*cphold = replaced_byte; | ||||
| 			kdb_grepping_flag = 0; | ||||
| 		} | ||||
| 		/*
 | ||||
| 		 * at this point the string is a full line and | ||||
| 		 * should be printed, up to the null. | ||||
|  | ||||
| @ -2299,10 +2299,10 @@ void kdb_ps_suppressed(void) | ||||
| 		if (kdb_task_state(p, mask_I)) | ||||
| 			++idle; | ||||
| 	} | ||||
| 	kdb_do_each_thread(g, p) { | ||||
| 	for_each_process_thread(g, p) { | ||||
| 		if (kdb_task_state(p, mask_M)) | ||||
| 			++daemon; | ||||
| 	} kdb_while_each_thread(g, p); | ||||
| 	} | ||||
| 	if (idle || daemon) { | ||||
| 		if (idle) | ||||
| 			kdb_printf("%d idle process%s (state I)%s\n", | ||||
| @ -2370,12 +2370,12 @@ static int kdb_ps(int argc, const char **argv) | ||||
| 	} | ||||
| 	kdb_printf("\n"); | ||||
| 	/* Now the real tasks */ | ||||
| 	kdb_do_each_thread(g, p) { | ||||
| 	for_each_process_thread(g, p) { | ||||
| 		if (KDB_FLAG(CMD_INTERRUPT)) | ||||
| 			return 0; | ||||
| 		if (kdb_task_state(p, mask)) | ||||
| 			kdb_ps1(p); | ||||
| 	} kdb_while_each_thread(g, p); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| @ -230,10 +230,6 @@ extern struct task_struct *kdb_curr_task(int); | ||||
| 
 | ||||
| #define kdb_task_has_cpu(p) (task_curr(p)) | ||||
| 
 | ||||
| /* Simplify coexistence with NPTL */ | ||||
| #define	kdb_do_each_thread(g, p) do_each_thread(g, p) | ||||
| #define	kdb_while_each_thread(g, p) while_each_thread(g, p) | ||||
| 
 | ||||
| #define GFP_KDB (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL) | ||||
| 
 | ||||
| extern void *debug_kmalloc(size_t size, gfp_t flags); | ||||
|  | ||||
| @ -24,6 +24,21 @@ menuconfig KGDB | ||||
| 
 | ||||
| if KGDB | ||||
| 
 | ||||
| config KGDB_HONOUR_BLOCKLIST | ||||
| 	bool "KGDB: use kprobe blocklist to prohibit unsafe breakpoints" | ||||
| 	depends on HAVE_KPROBES | ||||
| 	depends on MODULES | ||||
| 	select KPROBES | ||||
| 	default y | ||||
| 	help | ||||
| 	  If set to Y the debug core will use the kprobe blocklist to | ||||
| 	  identify symbols where it is unsafe to set breakpoints. | ||||
| 	  In particular this disallows instrumentation of functions | ||||
| 	  called during debug trap handling and thus makes it very | ||||
| 	  difficult to inadvertently provoke recursive trap handling. | ||||
| 
 | ||||
| 	  If unsure, say Y. | ||||
| 
 | ||||
| config KGDB_SERIAL_CONSOLE | ||||
| 	tristate "KGDB: use kgdb over the serial console" | ||||
| 	select CONSOLE_POLL | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user