mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 03:32:45 +00:00 
			
		
		
		
	Kernel: Prevent executing I/O instructions in userspace
All threads were running with iomapbase=0 in their TSS, which the CPU interprets as "there's an I/O permission bitmap starting at offset 0 into my TSS". Because of that, any bits that were 1 inside the TSS would allow the thread to execute I/O instructions on the port with that bit index. Fix this by always setting the iomapbase to sizeof(TSS32), and also setting the TSS descriptor's limit to sizeof(TSS32), effectively making the I/O permissions bitmap zero-length. This should make it no longer possible to do I/O from userspace. :^)
This commit is contained in:
		
							parent
							
								
									37329c2009
								
							
						
					
					
						commit
						f598bbbb1d
					
				
					 5 changed files with 21 additions and 6 deletions
				
			
		|  | @ -33,6 +33,7 @@ kinds of crashes. | ||||||
| * `-y`: Write to recently freed memory. (Tests an opportunistic malloc guard.) | * `-y`: Write to recently freed memory. (Tests an opportunistic malloc guard.) | ||||||
| * `-X`: Attempt to execute non-executable memory. (Not mapped with PROT\_EXEC.) | * `-X`: Attempt to execute non-executable memory. (Not mapped with PROT\_EXEC.) | ||||||
| * `-U`: Attempt to trigger an x86 User Mode Instruction Prevention fault. | * `-U`: Attempt to trigger an x86 User Mode Instruction Prevention fault. | ||||||
|  | * `-I`: Use an x86 I/O instruction in userspace. | ||||||
| 
 | 
 | ||||||
| ## Examples | ## Examples | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -705,6 +705,8 @@ int Process::do_exec(String path, Vector<String> arguments, Vector<String> envir | ||||||
|     new_main_thread->make_thread_specific_region({}); |     new_main_thread->make_thread_specific_region({}); | ||||||
| 
 | 
 | ||||||
|     memset(&tss, 0, sizeof(TSS32)); |     memset(&tss, 0, sizeof(TSS32)); | ||||||
|  |     tss.iomapbase = sizeof(TSS32); | ||||||
|  | 
 | ||||||
|     tss.eflags = 0x0202; |     tss.eflags = 0x0202; | ||||||
|     tss.eip = entry_eip; |     tss.eip = entry_eip; | ||||||
|     tss.cs = 0x1b; |     tss.cs = 0x1b; | ||||||
|  |  | ||||||
|  | @ -476,10 +476,10 @@ bool Scheduler::context_switch(Thread& thread) | ||||||
|         thread.set_selector(gdt_alloc_entry()); |         thread.set_selector(gdt_alloc_entry()); | ||||||
|         auto& descriptor = get_gdt_entry(thread.selector()); |         auto& descriptor = get_gdt_entry(thread.selector()); | ||||||
|         descriptor.set_base(&thread.tss()); |         descriptor.set_base(&thread.tss()); | ||||||
|         descriptor.set_limit(0xffff); |         descriptor.set_limit(sizeof(TSS32)); | ||||||
|         descriptor.dpl = 0; |         descriptor.dpl = 0; | ||||||
|         descriptor.segment_present = 1; |         descriptor.segment_present = 1; | ||||||
|         descriptor.granularity = 1; |         descriptor.granularity = 0; | ||||||
|         descriptor.zero = 0; |         descriptor.zero = 0; | ||||||
|         descriptor.operation_size = 1; |         descriptor.operation_size = 1; | ||||||
|         descriptor.descriptor_type = 0; |         descriptor.descriptor_type = 0; | ||||||
|  | @ -501,10 +501,10 @@ static void initialize_redirection() | ||||||
| { | { | ||||||
|     auto& descriptor = get_gdt_entry(s_redirection.selector); |     auto& descriptor = get_gdt_entry(s_redirection.selector); | ||||||
|     descriptor.set_base(&s_redirection.tss); |     descriptor.set_base(&s_redirection.tss); | ||||||
|     descriptor.set_limit(0xffff); |     descriptor.set_limit(sizeof(TSS32)); | ||||||
|     descriptor.dpl = 0; |     descriptor.dpl = 0; | ||||||
|     descriptor.segment_present = 1; |     descriptor.segment_present = 1; | ||||||
|     descriptor.granularity = 1; |     descriptor.granularity = 0; | ||||||
|     descriptor.zero = 0; |     descriptor.zero = 0; | ||||||
|     descriptor.operation_size = 1; |     descriptor.operation_size = 1; | ||||||
|     descriptor.descriptor_type = 0; |     descriptor.descriptor_type = 0; | ||||||
|  |  | ||||||
|  | @ -59,6 +59,7 @@ Thread::Thread(Process& process) | ||||||
|     m_fpu_state = (FPUState*)kmalloc_aligned(sizeof(FPUState), 16); |     m_fpu_state = (FPUState*)kmalloc_aligned(sizeof(FPUState), 16); | ||||||
|     memcpy(m_fpu_state, &s_clean_fpu_state, sizeof(FPUState)); |     memcpy(m_fpu_state, &s_clean_fpu_state, sizeof(FPUState)); | ||||||
|     memset(&m_tss, 0, sizeof(m_tss)); |     memset(&m_tss, 0, sizeof(m_tss)); | ||||||
|  |     m_tss.iomapbase = sizeof(TSS32); | ||||||
| 
 | 
 | ||||||
|     // Only IF is set when a process boots.
 |     // Only IF is set when a process boots.
 | ||||||
|     m_tss.eflags = 0x0202; |     m_tss.eflags = 0x0202; | ||||||
|  |  | ||||||
|  | @ -1,5 +1,6 @@ | ||||||
| #include <AK/Function.h> | #include <AK/Function.h> | ||||||
| #include <AK/String.h> | #include <AK/String.h> | ||||||
|  | #include <Kernel/IO.h> | ||||||
| #include <Kernel/Syscall.h> | #include <Kernel/Syscall.h> | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
|  | @ -10,7 +11,7 @@ | ||||||
| 
 | 
 | ||||||
| static void print_usage_and_exit() | static void print_usage_and_exit() | ||||||
| { | { | ||||||
|     printf("usage: crash -[AsdiamfMFTtSxyXU]\n"); |     printf("usage: crash -[AsdiamfMFTtSxyXUI]\n"); | ||||||
|     exit(0); |     exit(0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -99,6 +100,7 @@ int main(int argc, char** argv) | ||||||
|         ReadFromFreedMemoryStillCachedByMalloc, |         ReadFromFreedMemoryStillCachedByMalloc, | ||||||
|         ExecuteNonExecutableMemory, |         ExecuteNonExecutableMemory, | ||||||
|         TriggerUserModeInstructionPrevention, |         TriggerUserModeInstructionPrevention, | ||||||
|  |         UseIOInstruction, | ||||||
|     }; |     }; | ||||||
|     Mode mode = SegmentationViolation; |     Mode mode = SegmentationViolation; | ||||||
| 
 | 
 | ||||||
|  | @ -139,6 +141,8 @@ int main(int argc, char** argv) | ||||||
|         mode = ExecuteNonExecutableMemory; |         mode = ExecuteNonExecutableMemory; | ||||||
|     else if (String(argv[1]) == "-U") |     else if (String(argv[1]) == "-U") | ||||||
|         mode = TriggerUserModeInstructionPrevention; |         mode = TriggerUserModeInstructionPrevention; | ||||||
|  |     else if (String(argv[1]) == "-I") | ||||||
|  |         mode = UseIOInstruction; | ||||||
|     else |     else | ||||||
|         print_usage_and_exit(); |         print_usage_and_exit(); | ||||||
| 
 | 
 | ||||||
|  | @ -330,6 +334,13 @@ int main(int argc, char** argv) | ||||||
|         }).run(run_type); |         }).run(run_type); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     if (mode == UseIOInstruction || mode == TestAllCrashTypes) { | ||||||
|  |         Crash("Attempt to use an I/O instruction", [] { | ||||||
|  |             u8 keyboard_status = IO::in8(0x64); | ||||||
|  |             printf("Keyboard status: %#02x\n", keyboard_status); | ||||||
|  |             return Crash::Failure::DidNotCrash; | ||||||
|  |         }).run(run_type); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 |  | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling