mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 09:19:51 +00:00
[PATCH] uml: fix error output during early boot
The startup code panics a lot if anything goes wrong early on. This is wrong for several reasons, like the kernel isn't running, so you can't really be calling into it yet, but the harm comes from useful error messages being trapped in the printk ring where no one will ever see them. This patch changes these panics to perror and printf in wrappers which also exit. Normal, informational, prints are also wrapped so that fflush(stdout) is called after each one. This is so the output appears in the correct sequence in the event of an error. Signed-off-by: Jeff Dike <jdike@addtoit.com> Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
9683da91e2
commit
3a150e1da8
1 changed files with 92 additions and 62 deletions
|
@ -73,6 +73,34 @@ static int ptrace_child(void *arg)
|
||||||
_exit(ret);
|
_exit(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void fatal_perror(char *str)
|
||||||
|
{
|
||||||
|
perror(str);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fatal(char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list list;
|
||||||
|
|
||||||
|
va_start(list, fmt);
|
||||||
|
vprintf(fmt, list);
|
||||||
|
va_end(list);
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void non_fatal(char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list list;
|
||||||
|
|
||||||
|
va_start(list, fmt);
|
||||||
|
vprintf(fmt, list);
|
||||||
|
va_end(list);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
static int start_ptraced_child(void **stack_out)
|
static int start_ptraced_child(void **stack_out)
|
||||||
{
|
{
|
||||||
void *stack;
|
void *stack;
|
||||||
|
@ -82,16 +110,16 @@ static int start_ptraced_child(void **stack_out)
|
||||||
stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
|
stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
if(stack == MAP_FAILED)
|
if(stack == MAP_FAILED)
|
||||||
panic("check_ptrace : mmap failed, errno = %d", errno);
|
fatal_perror("check_ptrace : mmap failed");
|
||||||
sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
|
sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
|
||||||
pid = clone(ptrace_child, (void *) sp, SIGCHLD, NULL);
|
pid = clone(ptrace_child, (void *) sp, SIGCHLD, NULL);
|
||||||
if(pid < 0)
|
if(pid < 0)
|
||||||
panic("start_ptraced_child : clone failed, errno = %d", errno);
|
fatal_perror("start_ptraced_child : clone failed");
|
||||||
CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
|
CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
|
||||||
if(n < 0)
|
if(n < 0)
|
||||||
panic("check_ptrace : clone failed, errno = %d", errno);
|
fatal_perror("check_ptrace : clone failed");
|
||||||
if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
|
if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
|
||||||
panic("check_ptrace : expected SIGSTOP, got status = %d",
|
fatal("check_ptrace : expected SIGSTOP, got status = %d",
|
||||||
status);
|
status);
|
||||||
|
|
||||||
*stack_out = stack;
|
*stack_out = stack;
|
||||||
|
@ -105,31 +133,30 @@ static int start_ptraced_child(void **stack_out)
|
||||||
* must work anyway!
|
* must work anyway!
|
||||||
*/
|
*/
|
||||||
static int stop_ptraced_child(int pid, void *stack, int exitcode,
|
static int stop_ptraced_child(int pid, void *stack, int exitcode,
|
||||||
int mustpanic)
|
int mustexit)
|
||||||
{
|
{
|
||||||
int status, n, ret = 0;
|
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);
|
fatal_perror("stop_ptraced_child : ptrace failed");
|
||||||
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)) {
|
||||||
int exit_with = WEXITSTATUS(status);
|
int exit_with = WEXITSTATUS(status);
|
||||||
if (exit_with == 2)
|
if (exit_with == 2)
|
||||||
printf("check_ptrace : child exited with status 2. "
|
non_fatal("check_ptrace : child exited with status 2. "
|
||||||
"Serious trouble happening! Try updating your "
|
"Serious trouble happening! Try updating "
|
||||||
"host skas patch!\nDisabling SYSEMU support.");
|
"your host skas patch!\nDisabling SYSEMU "
|
||||||
printf("check_ptrace : child exited with exitcode %d, while "
|
"support.");
|
||||||
"expecting %d; status 0x%x", exit_with,
|
non_fatal("check_ptrace : child exited with exitcode %d, while "
|
||||||
|
"expecting %d; status 0x%x\n", exit_with,
|
||||||
exitcode, status);
|
exitcode, status);
|
||||||
if (mustpanic)
|
if (mustexit)
|
||||||
panic("\n");
|
exit(1);
|
||||||
else
|
|
||||||
printf("\n");
|
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(munmap(stack, PAGE_SIZE) < 0)
|
if(munmap(stack, PAGE_SIZE) < 0)
|
||||||
panic("check_ptrace : munmap failed, errno = %d", errno);
|
fatal_perror("check_ptrace : munmap failed");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,7 +211,7 @@ static void __init check_sysemu(void)
|
||||||
void *stack;
|
void *stack;
|
||||||
int pid, n, status, count=0;
|
int pid, n, status, count=0;
|
||||||
|
|
||||||
printf("Checking syscall emulation patch for ptrace...");
|
non_fatal("Checking syscall emulation patch for ptrace...");
|
||||||
sysemu_supported = 0;
|
sysemu_supported = 0;
|
||||||
pid = start_ptraced_child(&stack);
|
pid = start_ptraced_child(&stack);
|
||||||
|
|
||||||
|
@ -193,31 +220,30 @@ static void __init check_sysemu(void)
|
||||||
|
|
||||||
CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
|
CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
panic("check_sysemu : wait failed, errno = %d", errno);
|
fatal_perror("check_sysemu : wait failed");
|
||||||
if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
|
if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
|
||||||
panic("check_sysemu : expected SIGTRAP, "
|
fatal("check_sysemu : expected SIGTRAP, got status = %d",
|
||||||
"got status = %d", status);
|
status);
|
||||||
|
|
||||||
n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET,
|
n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET,
|
||||||
os_getpid());
|
os_getpid());
|
||||||
if(n < 0)
|
if(n < 0)
|
||||||
panic("check_sysemu : failed to modify system "
|
fatal_perror("check_sysemu : failed to modify system call "
|
||||||
"call return, errno = %d", errno);
|
"return");
|
||||||
|
|
||||||
if (stop_ptraced_child(pid, stack, 0, 0) < 0)
|
if (stop_ptraced_child(pid, stack, 0, 0) < 0)
|
||||||
goto fail_stopped;
|
goto fail_stopped;
|
||||||
|
|
||||||
sysemu_supported = 1;
|
sysemu_supported = 1;
|
||||||
printf("OK\n");
|
non_fatal("OK\n");
|
||||||
set_using_sysemu(!force_sysemu_disabled);
|
set_using_sysemu(!force_sysemu_disabled);
|
||||||
|
|
||||||
printf("Checking advanced syscall emulation patch for ptrace...");
|
non_fatal("Checking advanced syscall emulation patch for ptrace...");
|
||||||
pid = start_ptraced_child(&stack);
|
pid = start_ptraced_child(&stack);
|
||||||
|
|
||||||
if(ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
|
if((ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
|
||||||
(void *) PTRACE_O_TRACESYSGOOD) < 0)
|
(void *) PTRACE_O_TRACESYSGOOD) < 0))
|
||||||
panic("check_ptrace: PTRACE_OLDSETOPTIONS failed, errno = %d",
|
fatal_perror("check_ptrace: PTRACE_OLDSETOPTIONS failed");
|
||||||
errno);
|
|
||||||
|
|
||||||
while(1){
|
while(1){
|
||||||
count++;
|
count++;
|
||||||
|
@ -225,29 +251,30 @@ static void __init check_sysemu(void)
|
||||||
goto fail;
|
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);
|
fatal_perror("check_ptrace : wait failed");
|
||||||
|
|
||||||
if(WIFSTOPPED(status) && (WSTOPSIG(status) == (SIGTRAP|0x80))){
|
if(WIFSTOPPED(status) && (WSTOPSIG(status) == (SIGTRAP|0x80))){
|
||||||
if (!count)
|
if (!count)
|
||||||
panic("check_ptrace : SYSEMU_SINGLESTEP "
|
fatal("check_ptrace : SYSEMU_SINGLESTEP "
|
||||||
"doesn't singlestep");
|
"doesn't singlestep");
|
||||||
n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET,
|
n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET,
|
||||||
os_getpid());
|
os_getpid());
|
||||||
if(n < 0)
|
if(n < 0)
|
||||||
panic("check_sysemu : failed to modify system "
|
fatal_perror("check_sysemu : failed to modify "
|
||||||
"call return, errno = %d", errno);
|
"system call return");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP))
|
else if(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP))
|
||||||
count++;
|
count++;
|
||||||
else
|
else
|
||||||
panic("check_ptrace : expected SIGTRAP or "
|
fatal("check_ptrace : expected SIGTRAP or "
|
||||||
"(SIGTRAP | 0x80), got status = %d", status);
|
"(SIGTRAP | 0x80), got status = %d", status);
|
||||||
}
|
}
|
||||||
if (stop_ptraced_child(pid, stack, 0, 0) < 0)
|
if (stop_ptraced_child(pid, stack, 0, 0) < 0)
|
||||||
goto fail_stopped;
|
goto fail_stopped;
|
||||||
|
|
||||||
sysemu_supported = 2;
|
sysemu_supported = 2;
|
||||||
printf("OK\n");
|
non_fatal("OK\n");
|
||||||
|
|
||||||
if ( !force_sysemu_disabled )
|
if ( !force_sysemu_disabled )
|
||||||
set_using_sysemu(sysemu_supported);
|
set_using_sysemu(sysemu_supported);
|
||||||
|
@ -256,7 +283,7 @@ static void __init check_sysemu(void)
|
||||||
fail:
|
fail:
|
||||||
stop_ptraced_child(pid, stack, 1, 0);
|
stop_ptraced_child(pid, stack, 1, 0);
|
||||||
fail_stopped:
|
fail_stopped:
|
||||||
printf("missing\n");
|
non_fatal("missing\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __init check_ptrace(void)
|
static void __init check_ptrace(void)
|
||||||
|
@ -264,21 +291,24 @@ static void __init check_ptrace(void)
|
||||||
void *stack;
|
void *stack;
|
||||||
int pid, syscall, n, status;
|
int pid, syscall, n, status;
|
||||||
|
|
||||||
printf("Checking that ptrace can change system call numbers...");
|
non_fatal("Checking that ptrace can change system call numbers...");
|
||||||
pid = start_ptraced_child(&stack);
|
pid = start_ptraced_child(&stack);
|
||||||
|
|
||||||
if(ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
|
if((ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
|
||||||
panic("check_ptrace: PTRACE_OLDSETOPTIONS failed, errno = %d", errno);
|
(void *) PTRACE_O_TRACESYSGOOD) < 0))
|
||||||
|
fatal_perror("check_ptrace: PTRACE_OLDSETOPTIONS failed");
|
||||||
|
|
||||||
while(1){
|
while(1){
|
||||||
if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
|
if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
|
||||||
panic("check_ptrace : ptrace failed, errno = %d",
|
fatal_perror("check_ptrace : ptrace failed");
|
||||||
errno);
|
|
||||||
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);
|
fatal_perror("check_ptrace : wait failed");
|
||||||
if(!WIFSTOPPED(status) || (WSTOPSIG(status) != (SIGTRAP|0x80)))
|
|
||||||
panic("check_ptrace : expected (SIGTRAP|0x80), "
|
if(!WIFSTOPPED(status) ||
|
||||||
|
(WSTOPSIG(status) != (SIGTRAP | 0x80)))
|
||||||
|
fatal("check_ptrace : expected (SIGTRAP|0x80), "
|
||||||
"got status = %d", status);
|
"got status = %d", status);
|
||||||
|
|
||||||
syscall = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET,
|
syscall = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET,
|
||||||
|
@ -287,13 +317,13 @@ static void __init check_ptrace(void)
|
||||||
n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET,
|
n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET,
|
||||||
__NR_getppid);
|
__NR_getppid);
|
||||||
if(n < 0)
|
if(n < 0)
|
||||||
panic("check_ptrace : failed to modify system "
|
fatal_perror("check_ptrace : failed to modify "
|
||||||
"call, errno = %d", errno);
|
"system call");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stop_ptraced_child(pid, stack, 0, 1);
|
stop_ptraced_child(pid, stack, 0, 1);
|
||||||
printf("OK\n");
|
non_fatal("OK\n");
|
||||||
check_sysemu();
|
check_sysemu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,22 +382,22 @@ static inline void check_skas3_ptrace_faultinfo(void)
|
||||||
void *stack;
|
void *stack;
|
||||||
int pid, n;
|
int pid, n;
|
||||||
|
|
||||||
printf(" - PTRACE_FAULTINFO...");
|
non_fatal(" - PTRACE_FAULTINFO...");
|
||||||
pid = start_ptraced_child(&stack);
|
pid = start_ptraced_child(&stack);
|
||||||
|
|
||||||
n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi);
|
n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi);
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
ptrace_faultinfo = 0;
|
ptrace_faultinfo = 0;
|
||||||
if(errno == EIO)
|
if(errno == EIO)
|
||||||
printf("not found\n");
|
non_fatal("not found\n");
|
||||||
else
|
else
|
||||||
perror("not found");
|
perror("not found");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!ptrace_faultinfo)
|
if (!ptrace_faultinfo)
|
||||||
printf("found but disabled on command line\n");
|
non_fatal("found but disabled on command line\n");
|
||||||
else
|
else
|
||||||
printf("found\n");
|
non_fatal("found\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
init_registers(pid);
|
init_registers(pid);
|
||||||
|
@ -385,13 +415,13 @@ static inline void check_skas3_ptrace_ldt(void)
|
||||||
.ptr = ldtbuf,
|
.ptr = ldtbuf,
|
||||||
.bytecount = sizeof(ldtbuf)};
|
.bytecount = sizeof(ldtbuf)};
|
||||||
|
|
||||||
printf(" - PTRACE_LDT...");
|
non_fatal(" - PTRACE_LDT...");
|
||||||
pid = start_ptraced_child(&stack);
|
pid = start_ptraced_child(&stack);
|
||||||
|
|
||||||
n = ptrace(PTRACE_LDT, pid, 0, (unsigned long) &ldt_op);
|
n = ptrace(PTRACE_LDT, pid, 0, (unsigned long) &ldt_op);
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
if(errno == EIO)
|
if(errno == EIO)
|
||||||
printf("not found\n");
|
non_fatal("not found\n");
|
||||||
else {
|
else {
|
||||||
perror("not found");
|
perror("not found");
|
||||||
}
|
}
|
||||||
|
@ -399,9 +429,9 @@ static inline void check_skas3_ptrace_ldt(void)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(ptrace_ldt)
|
if(ptrace_ldt)
|
||||||
printf("found\n");
|
non_fatal("found\n");
|
||||||
else
|
else
|
||||||
printf("found, but use is disabled\n");
|
non_fatal("found, but use is disabled\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
stop_ptraced_child(pid, stack, 1, 1);
|
stop_ptraced_child(pid, stack, 1, 1);
|
||||||
|
@ -416,22 +446,22 @@ static inline void check_skas3_ptrace_ldt(void)
|
||||||
|
|
||||||
static inline void check_skas3_proc_mm(void)
|
static inline void check_skas3_proc_mm(void)
|
||||||
{
|
{
|
||||||
printf(" - /proc/mm...");
|
non_fatal(" - /proc/mm...");
|
||||||
if (access("/proc/mm", W_OK) < 0) {
|
if (access("/proc/mm", W_OK) < 0) {
|
||||||
proc_mm = 0;
|
proc_mm = 0;
|
||||||
printf("not found\n");
|
perror("not found");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!proc_mm)
|
if (!proc_mm)
|
||||||
printf("found but disabled on command line\n");
|
non_fatal("found but disabled on command line\n");
|
||||||
else
|
else
|
||||||
printf("found\n");
|
non_fatal("found\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int can_do_skas(void)
|
int can_do_skas(void)
|
||||||
{
|
{
|
||||||
printf("Checking for the skas3 patch in the host:\n");
|
non_fatal("Checking for the skas3 patch in the host:\n");
|
||||||
|
|
||||||
check_skas3_proc_mm();
|
check_skas3_proc_mm();
|
||||||
check_skas3_ptrace_faultinfo();
|
check_skas3_ptrace_faultinfo();
|
||||||
|
|
Loading…
Reference in a new issue