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
This commit is contained in:
Michael Lotz
2009-08-04 23:15:05 +00:00
parent c771baca29
commit ee280b59e9
2 changed files with 6 additions and 1 deletions
+4 -1
View File
@@ -731,8 +731,11 @@ arch_cpu_global_TLB_invalidate(void)
// of the global page bit // of the global page bit
x86_write_cr4(flags & ~IA32_CR4_GLOBAL_PAGES); x86_write_cr4(flags & ~IA32_CR4_GLOBAL_PAGES);
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(); arch_cpu_user_TLB_invalidate();
restore_interrupts(state);
}
} }
@@ -632,7 +632,9 @@ flush_tmap(vm_translation_map *map)
smp_send_broadcast_ici(SMP_MSG_GLOBAL_INVALIDATE_PAGES, 0, 0, 0, smp_send_broadcast_ici(SMP_MSG_GLOBAL_INVALIDATE_PAGES, 0, 0, 0,
NULL, SMP_MSG_FLAG_SYNC); NULL, SMP_MSG_FLAG_SYNC);
} else { } else {
cpu_status state = disable_interrupts();
arch_cpu_user_TLB_invalidate(); arch_cpu_user_TLB_invalidate();
restore_interrupts(state);
int cpu = smp_get_current_cpu(); int cpu = smp_get_current_cpu();
uint32 cpuMask = map->arch_data->active_on_cpus uint32 cpuMask = map->arch_data->active_on_cpus