Skip to content

Commit

Permalink
[PATCH] uml: fix hang in TT mode on fault
Browse files Browse the repository at this point in the history
The current code doesn't handle well general protection faults on the host -
it thinks that cr2 is always the address of a page fault.  While actually, on
general protection faults, that address is not accessible, so we'd better
assume we couldn't satisfy the fault.  Currently instead we think we've fixed
it, so we go back, retry the instruction and fault again endlessly.

This leads to the kernel hanging when doing copy_from_user(dest, -1, ...) in
TT mode, since reading *(-1) causes a GFP, and we don't support kernel
preemption.

Thanks to Luo Xin for testing UML with LTP and reporting the failures he got.

Cc: Luo Xin <luothing@sina.com>
Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Cc: Jeff Dike <jdike@addtoit.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
  • Loading branch information
Paolo 'Blaisorblade' Giarrusso authored and Linus Torvalds committed Sep 23, 2005
1 parent 69e1e68 commit 546fe1c
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 3 deletions.
11 changes: 10 additions & 1 deletion arch/um/kernel/trap_kern.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "asm/a.out.h"
#include "asm/current.h"
#include "asm/irq.h"
#include "sysdep/sigcontext.h"
#include "user_util.h"
#include "kern_util.h"
#include "kern.h"
Expand Down Expand Up @@ -125,7 +126,15 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc)
}
else if(current->mm == NULL)
panic("Segfault with no mm");
err = handle_page_fault(address, ip, is_write, is_user, &si.si_code);

if (SEGV_IS_FIXABLE(&fi))
err = handle_page_fault(address, ip, is_write, is_user, &si.si_code);
else {
err = -EFAULT;
/* A thread accessed NULL, we get a fault, but CR2 is invalid.
* This code is used in __do_copy_from_user() of TT mode. */
address = 0;
}

catcher = current->thread.fault_catcher;
if(!err)
Expand Down
11 changes: 9 additions & 2 deletions arch/um/kernel/tt/uaccess_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,15 @@ int __do_copy_from_user(void *to, const void *from, int n,
__do_copy, &faulted);
TASK_REGS(get_current())->tt = save;

if(!faulted) return(0);
else return(n - (fault - (unsigned long) from));
if(!faulted)
return 0;
else if (fault)
return n - (fault - (unsigned long) from);
else
/* In case of a general protection fault, we don't have the
* fault address, so NULL is used instead. Pretend we didn't
* copy anything. */
return n;
}

static void __do_strncpy(void *dst, const void *src, int count)
Expand Down

0 comments on commit 546fe1c

Please sign in to comment.