From ee280b59e95cdd6ebec4519aa9b616e58de79f76 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Tue, 4 Aug 2009 23:15:05 +0000 Subject: [PATCH] Prevent the user TLB invalidation function from being preempted by turning off interrupts when invoking it. The user TLB invalidation function essentially only reads and writes back control register 3 (cr3) which holds the physical address of the current page directory. Still a preemption between the read and the write can cause problems when the last thread of a team dies and therefore the team is deleted. The context switch on preemption would decrement the refcount of the object that holds the page directory. Then the team address space is deleted causing the context switch returning to that thread to not re-acquire a reference to the object. At that point the page directory as set in cr3 is the one of the previously run thread (which is fine, as all share the kernel space mappings we need). Now when the preempted thread continues though, it would overwrite cr3 with the physical page directory address from before the context switch still stored in eax, therefore setting the page directory to the one of the dying thread that now doesn't have the corresponding reference. Further progressing the thread would release the last reference causing the deletion of the object and freeing of the, now active again, page directory. The memory getting overwritten (by deadbeef) now completely corrupts the page directory causing basically any memory access to fault, in the end resulting in a triplefault. This should fix bug #3399. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@32118 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/system/kernel/arch/x86/arch_cpu.cpp | 5 ++++- src/system/kernel/arch/x86/arch_vm_translation_map.cpp | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/system/kernel/arch/x86/arch_cpu.cpp b/src/system/kernel/arch/x86/arch_cpu.cpp index d9048eaa9f..d46586ec19 100644 --- a/src/system/kernel/arch/x86/arch_cpu.cpp +++ b/src/system/kernel/arch/x86/arch_cpu.cpp @@ -731,8 +731,11 @@ arch_cpu_global_TLB_invalidate(void) // of the global page bit x86_write_cr4(flags & ~IA32_CR4_GLOBAL_PAGES); x86_write_cr4(flags | IA32_CR4_GLOBAL_PAGES); - } else + } else { + cpu_status state = disable_interrupts(); arch_cpu_user_TLB_invalidate(); + restore_interrupts(state); + } } diff --git a/src/system/kernel/arch/x86/arch_vm_translation_map.cpp b/src/system/kernel/arch/x86/arch_vm_translation_map.cpp index cabe6a66d9..17149c58b5 100644 --- a/src/system/kernel/arch/x86/arch_vm_translation_map.cpp +++ b/src/system/kernel/arch/x86/arch_vm_translation_map.cpp @@ -632,7 +632,9 @@ flush_tmap(vm_translation_map *map) smp_send_broadcast_ici(SMP_MSG_GLOBAL_INVALIDATE_PAGES, 0, 0, 0, NULL, SMP_MSG_FLAG_SYNC); } else { + cpu_status state = disable_interrupts(); arch_cpu_user_TLB_invalidate(); + restore_interrupts(state); int cpu = smp_get_current_cpu(); uint32 cpuMask = map->arch_data->active_on_cpus