mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 17:02:45 +00:00 
			
		
		
		
	Kernel: Fix Process use-after-free in Thread finalization
We leak a ref() onto every user process when constructing them, either via Process::create_user_process(), or via Process::sys$fork(). This ref() is balanced by a corresponding unref() in Thread::WaitBlockCondition::finalize(). Since kernel processes don't have a leaked ref() on them, this led to an extra Process::unref() on kernel processes during finalization. This happened during every boot, with the `init_stage2` process. Found by turning off kfree() scrubbing. :^)
This commit is contained in:
		
							parent
							
								
									6211eb0f9a
								
							
						
					
					
						commit
						859e5741ff
					
				
					 3 changed files with 14 additions and 6 deletions
				
			
		|  | @ -181,6 +181,10 @@ RefPtr<Process> Process::create_user_process(RefPtr<Thread>& first_thread, const | |||
| 
 | ||||
|     register_new(*process); | ||||
|     error = 0; | ||||
| 
 | ||||
|     // NOTE: All user processes have a leaked ref on them. It's balanced by Thread::WaitBlockCondition::finalize().
 | ||||
|     (void)process.leak_ref(); | ||||
| 
 | ||||
|     return process; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -119,9 +119,10 @@ KResultOr<FlatPtr> Process::sys$fork(RegisterState& regs) | |||
|     child_first_thread->set_state(Thread::State::Runnable); | ||||
| 
 | ||||
|     auto child_pid = child->pid().value(); | ||||
|     // We need to leak one reference so we don't destroy the Process,
 | ||||
|     // which will be dropped by Process::reap
 | ||||
| 
 | ||||
|     // NOTE: All user processes have a leaked ref on them. It's balanced by Thread::WaitBlockCondition::finalize().
 | ||||
|     (void)child.leak_ref(); | ||||
| 
 | ||||
|     return child_pid; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -580,11 +580,14 @@ void Thread::WaitBlockCondition::finalize() | |||
|     // Clear the list of threads here so we can drop the references to them
 | ||||
|     m_processes.clear(); | ||||
| 
 | ||||
|     // NOTE: Kernel processes don't have a leaked ref on them.
 | ||||
|     if (!is_kernel_mode()) { | ||||
|         // No more waiters, drop the last reference immediately. This may
 | ||||
|         // cause us to be destructed ourselves!
 | ||||
|         VERIFY(m_process.ref_count() > 0); | ||||
|         m_process.unref(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| Thread::WaitBlocker::WaitBlocker(int wait_options, idtype_t id_type, pid_t id, KResultOr<siginfo_t>& result) | ||||
|     : m_wait_options(wait_options) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling