Commit a328c343 authored by Paolo \'Blaisorblade\' Giarrusso's avatar Paolo \'Blaisorblade\' Giarrusso Committed by Linus Torvalds

[PATCH] uml: more careful test startup

From: Paolo 'Blaisorblade' Giarrusso <blaisorblade_spam@yahoo.it>
      Bodo Stroesser <bodo.stroesser@fujitsu-siemens.com>

While testing the host ptrace(2) features, we modify the stack frame of a test
child which is doing a syscall (namely getpid).  Either we override the
syscall number or the return value, which become the parent's pid, or we
don't, and the return value is the child's pid.

Actually, we only compared the return value with the child's pid, so we did
not notice a bug where the return value happened to be different from both.
So I added a stricter test here.
Signed-off-by: default avatarPaolo 'Blaisorblade' Giarrusso <blaisorblade_spam@yahoo.it>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent b9232fc4
...@@ -137,14 +137,31 @@ int start_fork_tramp(void *thread_arg, unsigned long temp_stack, ...@@ -137,14 +137,31 @@ int start_fork_tramp(void *thread_arg, unsigned long temp_stack,
static int ptrace_child(void *arg) static int ptrace_child(void *arg)
{ {
int pid = os_getpid(); int ret;
int pid = os_getpid(), ppid = getppid();
int sc_result;
if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){ if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
perror("ptrace"); perror("ptrace");
os_kill_process(pid, 0); os_kill_process(pid, 0);
} }
os_stop_process(pid); os_stop_process(pid);
_exit(os_getpid() == pid);
/*This syscall will be intercepted by the parent. Don't call more than
* once, please.*/
sc_result = os_getpid();
if (sc_result == pid)
ret = 1; /*Nothing modified by the parent, we are running
normally.*/
else if (sc_result == ppid)
ret = 0; /*Expected in check_ptrace and check_sysemu when they
succeed in modifying the stack frame*/
else
ret = 2; /*Serious trouble! This could be caused by a bug in
host 2.6 SKAS3/2.6 patch before release -V6, together
with a bug in the UML code itself.*/
_exit(ret);
} }
static int start_ptraced_child(void **stack_out) static int start_ptraced_child(void **stack_out)
...@@ -172,18 +189,36 @@ static int start_ptraced_child(void **stack_out) ...@@ -172,18 +189,36 @@ static int start_ptraced_child(void **stack_out)
return(pid); return(pid);
} }
static void stop_ptraced_child(int pid, void *stack, int exitcode) /* When testing for SYSEMU support, if it is one of the broken versions, we must
* just avoid using sysemu, not panic, but only if SYSEMU features are broken.
* So only for SYSEMU features we test mustpanic, while normal host features
* must work anyway!*/
static int stop_ptraced_child(int pid, void *stack, int exitcode, int mustpanic)
{ {
int status, n; int status, n, ret = 0;
if(ptrace(PTRACE_CONT, pid, 0, 0) < 0) if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
panic("check_ptrace : ptrace failed, errno = %d", errno); panic("check_ptrace : ptrace failed, errno = %d", errno);
CATCH_EINTR(n = waitpid(pid, &status, 0)); CATCH_EINTR(n = waitpid(pid, &status, 0));
if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) {
panic("check_ptrace : child exited with status 0x%x", status); int exit_with = WEXITSTATUS(status);
if (exit_with == 2)
printk("check_ptrace : child exited with status 2. "
"Serious trouble happening! Try updating your "
"host skas patch!\nDisabling SYSEMU support.");
printk("check_ptrace : child exited with exitcode %d, while "
"expecting %d; status 0x%x", exit_with,
exitcode, status);
if (mustpanic)
panic("\n");
else
printk("\n");
ret = -1;
}
if(munmap(stack, PAGE_SIZE) < 0) if(munmap(stack, PAGE_SIZE) < 0)
panic("check_ptrace : munmap failed, errno = %d", errno); panic("check_ptrace : munmap failed, errno = %d", errno);
return ret;
} }
static int force_sysemu_disabled = 0; static int force_sysemu_disabled = 0;
...@@ -213,33 +248,36 @@ static void __init check_sysemu(void) ...@@ -213,33 +248,36 @@ static void __init check_sysemu(void)
printk("Checking syscall emulation patch for ptrace..."); printk("Checking syscall emulation patch for ptrace...");
sysemu_supported = 0; sysemu_supported = 0;
pid = start_ptraced_child(&stack); pid = start_ptraced_child(&stack);
if(ptrace(PTRACE_SYSEMU, pid, 0, 0) >= 0) {
if(ptrace(PTRACE_SYSEMU, pid, 0, 0) < 0)
goto fail;
CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
if (n < 0) if (n < 0)
panic("check_ptrace : wait failed, errno = %d", errno); panic("check_sysemu : wait failed, errno = %d", errno);
if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
panic("check_ptrace : expected SIGTRAP, " panic("check_sysemu : expected SIGTRAP, "
"got status = %d", status); "got status = %d", status);
n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET,
os_getpid()); os_getpid());
if(n < 0) if(n < 0)
panic("check_ptrace : failed to modify system " panic("check_sysemu : failed to modify system "
"call return, errno = %d", errno); "call return, errno = %d", errno);
stop_ptraced_child(pid, stack, 0); if (stop_ptraced_child(pid, stack, 0, 0) < 0)
goto fail_stopped;
sysemu_supported = 1; sysemu_supported = 1;
printk("OK\n"); printk("OK\n");
} set_using_sysemu(!force_sysemu_disabled);
else return;
{
stop_ptraced_child(pid, stack, 1); fail:
stop_ptraced_child(pid, stack, 1, 0);
fail_stopped:
sysemu_supported = 0; sysemu_supported = 0;
printk("missing\n"); printk("missing\n");
}
set_using_sysemu(!force_sysemu_disabled);
} }
void __init check_ptrace(void) void __init check_ptrace(void)
...@@ -272,7 +310,7 @@ void __init check_ptrace(void) ...@@ -272,7 +310,7 @@ void __init check_ptrace(void)
break; break;
} }
} }
stop_ptraced_child(pid, stack, 0); stop_ptraced_child(pid, stack, 0, 1);
printk("OK\n"); printk("OK\n");
check_sysemu(); check_sysemu();
} }
...@@ -320,7 +358,7 @@ int can_do_skas(void) ...@@ -320,7 +358,7 @@ int can_do_skas(void)
else printf("found\n"); else printf("found\n");
init_registers(pid); init_registers(pid);
stop_ptraced_child(pid, stack, 1); stop_ptraced_child(pid, stack, 1, 1);
printf("Checking for /proc/mm..."); printf("Checking for /proc/mm...");
if(os_access("/proc/mm", OS_ACC_W_OK) < 0){ if(os_access("/proc/mm", OS_ACC_W_OK) < 0){
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
#include "mode.h" #include "mode.h"
#include "proc_mm.h" #include "proc_mm.h"
static atomic_t using_sysemu; static atomic_t using_sysemu = ATOMIC_INIT(0);
int sysemu_supported; int sysemu_supported;
void set_using_sysemu(int value) void set_using_sysemu(int value)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment