x86/unwind/orc: Fix error handling in __unwind_start()
commit71c9582528upstream. The unwind_state 'error' field is used to inform the reliable unwinding code that the stack trace can't be trusted. Set this field for all errors in __unwind_start(). Also, move the zeroing out of the unwind_state struct to before the ORC table initialization check, to prevent the caller from reading uninitialized data if the ORC table is corrupted. Fixes:af085d9084("stacktrace/x86: add function for detecting reliable stack traces") Fixes:d3a0910401("x86/unwinder/orc: Dont bail on stack overflow") Fixes:98d0c8ebf7("x86/unwind/orc: Prevent unwinding before ORC initialization") Reported-by: Pavel Machek <pavel@denx.de> Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lkml.kernel.org/r/d6ac7215a84ca92b895fdd2e1aa546729417e6e6.1589487277.git.jpoimboe@redhat.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
		
				
					committed by
					
						 Greg Kroah-Hartman
						Greg Kroah-Hartman
					
				
			
			
				
	
			
			
			
						parent
						
							e550fa72dd
						
					
				
				
					commit
					0cb155717e
				
			| @@ -505,23 +505,23 @@ EXPORT_SYMBOL_GPL(unwind_next_frame); | ||||
| void __unwind_start(struct unwind_state *state, struct task_struct *task, | ||||
| 		    struct pt_regs *regs, unsigned long *first_frame) | ||||
| { | ||||
| 	if (!orc_init) | ||||
| 		goto done; | ||||
| 
 | ||||
| 	memset(state, 0, sizeof(*state)); | ||||
| 	state->task = task; | ||||
| 
 | ||||
| 	if (!orc_init) | ||||
| 		goto err; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Refuse to unwind the stack of a task while it's executing on another | ||||
| 	 * CPU.  This check is racy, but that's ok: the unwinder has other | ||||
| 	 * checks to prevent it from going off the rails. | ||||
| 	 */ | ||||
| 	if (task_on_another_cpu(task)) | ||||
| 		goto done; | ||||
| 		goto err; | ||||
| 
 | ||||
| 	if (regs) { | ||||
| 		if (user_mode(regs)) | ||||
| 			goto done; | ||||
| 			goto the_end; | ||||
| 
 | ||||
| 		state->ip = regs->ip; | ||||
| 		state->sp = kernel_stack_pointer(regs); | ||||
| @@ -554,6 +554,7 @@ void __unwind_start(struct unwind_state *state, struct task_struct *task, | ||||
| 		 * generate some kind of backtrace if this happens. | ||||
| 		 */ | ||||
| 		void *next_page = (void *)PAGE_ALIGN((unsigned long)state->sp); | ||||
| 		state->error = true; | ||||
| 		if (get_stack_info(next_page, state->task, &state->stack_info, | ||||
| 				   &state->stack_mask)) | ||||
| 			return; | ||||
| @@ -579,8 +580,9 @@ void __unwind_start(struct unwind_state *state, struct task_struct *task, | ||||
| 
 | ||||
| 	return; | ||||
| 
 | ||||
| done: | ||||
| err: | ||||
| 	state->error = true; | ||||
| the_end: | ||||
| 	state->stack_info.type = STACK_TYPE_UNKNOWN; | ||||
| 	return; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(__unwind_start); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user