Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

um: defer killing userspace on page table update failures

In some cases we can get to fix_range_common() with mmap_sem held,
and in others we get there without it being held. For example, we
get there with it held from sys_mprotect(), and without it held
from fork_handler().

Avoid any issues in this and simply defer killing the task until
it runs the next time. Do it on the mm so that another task that
shares the same mm can't continue running afterwards.

Cc: stable@vger.kernel.org
Fixes: 468f65976a8d ("um: Fix hung task in fix_range_common()")
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Richard Weinberger <richard@nod.at>

authored by

Johannes Berg and committed by
Richard Weinberger
a7d48886 47da2976

+8 -4
+1
arch/um/include/shared/skas/mm_id.h
··· 12 12 int pid; 13 13 } u; 14 14 unsigned long stack; 15 + int kill; 15 16 }; 16 17 17 18 #endif
+3 -4
arch/um/kernel/tlb.c
··· 352 352 353 353 /* This is not an else because ret is modified above */ 354 354 if (ret) { 355 + struct mm_id *mm_idp = &current->mm->context.id; 356 + 355 357 printk(KERN_ERR "fix_range_common: failed, killing current " 356 358 "process: %d\n", task_tgid_vnr(current)); 357 - /* We are under mmap_lock, release it such that current can terminate */ 358 - mmap_write_unlock(current->mm); 359 - force_sig(SIGKILL); 360 - do_signal(&current->thread.regs); 359 + mm_idp->kill = 1; 361 360 } 362 361 } 363 362
+4
arch/um/os-Linux/skas/process.c
··· 300 300 } 301 301 302 302 int userspace_pid[NR_CPUS]; 303 + int kill_userspace_mm[NR_CPUS]; 303 304 304 305 /** 305 306 * start_userspace() - prepare a new userspace process ··· 394 393 interrupt_end(); 395 394 396 395 while (1) { 396 + if (kill_userspace_mm[0]) 397 + fatal_sigsegv(); 397 398 398 399 /* 399 400 * This can legitimately fail if the process loads a ··· 717 714 void __switch_mm(struct mm_id *mm_idp) 718 715 { 719 716 userspace_pid[0] = mm_idp->u.pid; 717 + kill_userspace_mm[0] = mm_idp->kill; 720 718 }