Merge git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[pandora-kernel.git] / arch / um / os-Linux / start_up.c
index 040cc14..b47e5e7 100644 (file)
@@ -4,27 +4,31 @@
  */
 
 #include <stdio.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 #include <signal.h>
 #include <sched.h>
+#include <fcntl.h>
 #include <errno.h>
-#include <stdarg.h>
-#include <stdlib.h>
 #include <setjmp.h>
 #include <sys/time.h>
 #include <sys/wait.h>
 #include <sys/mman.h>
 #include <asm/unistd.h>
 #include <asm/page.h>
+#include <sys/types.h>
 #include "user_util.h"
 #include "kern_util.h"
 #include "user.h"
 #include "signal_kern.h"
-#include "signal_user.h"
 #include "sysdep/ptrace.h"
 #include "sysdep/sigcontext.h"
 #include "irq_user.h"
 #include "ptrace_user.h"
+#include "mem_user.h"
 #include "time_user.h"
 #include "init.h"
 #include "os.h"
@@ -32,6 +36,8 @@
 #include "choose-mode.h"
 #include "mode.h"
 #include "tempfile.h"
+#include "kern_constants.h"
+
 #ifdef UML_CONFIG_MODE_SKAS
 #include "skas.h"
 #include "skas_ptrace.h"
@@ -109,16 +115,16 @@ static int stop_ptraced_child(int pid, void *stack, int exitcode,
        if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) {
                int exit_with = WEXITSTATUS(status);
                if (exit_with == 2)
-                       printk("check_ptrace : child exited with status 2. "
+                       printf("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 "
+               printf("check_ptrace : child exited with exitcode %d, while "
                      "expecting %d; status 0x%x", exit_with,
                      exitcode, status);
                if (mustpanic)
                        panic("\n");
                else
-                       printk("\n");
+                       printf("\n");
                ret = -1;
        }
 
@@ -128,7 +134,9 @@ static int stop_ptraced_child(int pid, void *stack, int exitcode,
 }
 
 int ptrace_faultinfo = 1;
+int ptrace_ldt = 1;
 int proc_mm = 1;
+int skas_needs_stub = 0;
 
 static int __init skas0_cmd_param(char *str, int* add)
 {
@@ -136,11 +144,22 @@ static int __init skas0_cmd_param(char *str, int* add)
        return 0;
 }
 
+/* The two __uml_setup would conflict, without this stupid alias. */
+
+static int __init mode_skas0_cmd_param(char *str, int* add)
+       __attribute__((alias("skas0_cmd_param")));
+
 __uml_setup("skas0", skas0_cmd_param,
                "skas0\n"
                "    Disables SKAS3 usage, so that SKAS0 is used, unless \n"
                "    you specify mode=tt.\n\n");
 
+__uml_setup("mode=skas0", mode_skas0_cmd_param,
+               "mode=skas0\n"
+               "    Disables SKAS3 usage, so that SKAS0 is used, unless you \n"
+               "    specify mode=tt. Note that this was recently added - on \n"
+               "    older kernels you must use simply \"skas0\".\n\n");
+
 static int force_sysemu_disabled = 0;
 
 static int __init nosysemu_cmd_param(char *str, int* add)
@@ -163,7 +182,7 @@ static void __init check_sysemu(void)
        void *stack;
        int pid, n, status, count=0;
 
-       printk("Checking syscall emulation patch for ptrace...");
+       printf("Checking syscall emulation patch for ptrace...");
        sysemu_supported = 0;
        pid = start_ptraced_child(&stack);
 
@@ -187,10 +206,10 @@ static void __init check_sysemu(void)
                goto fail_stopped;
 
        sysemu_supported = 1;
-       printk("OK\n");
+       printf("OK\n");
        set_using_sysemu(!force_sysemu_disabled);
 
-       printk("Checking advanced syscall emulation patch for ptrace...");
+       printf("Checking advanced syscall emulation patch for ptrace...");
        pid = start_ptraced_child(&stack);
 
        if(ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
@@ -226,7 +245,7 @@ static void __init check_sysemu(void)
                goto fail_stopped;
 
        sysemu_supported = 2;
-       printk("OK\n");
+       printf("OK\n");
 
        if ( !force_sysemu_disabled )
                set_using_sysemu(sysemu_supported);
@@ -235,7 +254,7 @@ static void __init check_sysemu(void)
 fail:
        stop_ptraced_child(pid, stack, 1, 0);
 fail_stopped:
-       printk("missing\n");
+       printf("missing\n");
 }
 
 static void __init check_ptrace(void)
@@ -243,7 +262,7 @@ static void __init check_ptrace(void)
        void *stack;
        int pid, syscall, n, status;
 
-       printk("Checking that ptrace can change system call numbers...");
+       printf("Checking that ptrace can change system call numbers...");
        pid = start_ptraced_child(&stack);
 
        if(ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
@@ -272,13 +291,42 @@ static void __init check_ptrace(void)
                }
        }
        stop_ptraced_child(pid, stack, 0, 1);
-       printk("OK\n");
+       printf("OK\n");
        check_sysemu();
 }
 
+extern int create_tmp_file(unsigned long long len);
+
+static void check_tmpexec(void)
+{
+       void *addr;
+       int err, fd = create_tmp_file(UM_KERN_PAGE_SIZE);
+
+       addr = mmap(NULL, UM_KERN_PAGE_SIZE,
+                   PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0);
+       printf("Checking PROT_EXEC mmap in /tmp...");
+       fflush(stdout);
+       if(addr == MAP_FAILED){
+               err = errno;
+               perror("failed");
+               if(err == EPERM)
+                       printf("/tmp must be not mounted noexec\n");
+               exit(1);
+       }
+       printf("OK\n");
+       munmap(addr, UM_KERN_PAGE_SIZE);
+
+       close(fd);
+}
+
 void os_early_checks(void)
 {
        check_ptrace();
+
+       /* Need to check this early because mmapping happens before the
+        * kernel is running.
+        */
+       check_tmpexec();
 }
 
 static int __init noprocmm_cmd_param(char *str, int* add)
@@ -305,14 +353,26 @@ __uml_setup("noptracefaultinfo", noptracefaultinfo_cmd_param,
 "    it. To support PTRACE_FAULTINFO, the host needs to be patched\n"
 "    using the current skas3 patch.\n\n");
 
+static int __init noptraceldt_cmd_param(char *str, int* add)
+{
+       ptrace_ldt = 0;
+       return 0;
+}
+
+__uml_setup("noptraceldt", noptraceldt_cmd_param,
+"noptraceldt\n"
+"    Turns off usage of PTRACE_LDT, even if host supports it.\n"
+"    To support PTRACE_LDT, the host needs to be patched using\n"
+"    the current skas3 patch.\n\n");
+
 #ifdef UML_CONFIG_MODE_SKAS
-static inline void check_skas3_ptrace_support(void)
+static inline void check_skas3_ptrace_faultinfo(void)
 {
        struct ptrace_faultinfo fi;
        void *stack;
        int pid, n;
 
-       printf("Checking for the skas3 patch in the host...");
+       printf("  - PTRACE_FAULTINFO...");
        pid = start_ptraced_child(&stack);
 
        n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi);
@@ -334,9 +394,49 @@ static inline void check_skas3_ptrace_support(void)
        stop_ptraced_child(pid, stack, 1, 1);
 }
 
-int can_do_skas(void)
+static inline void check_skas3_ptrace_ldt(void)
+{
+#ifdef PTRACE_LDT
+       void *stack;
+       int pid, n;
+       unsigned char ldtbuf[40];
+       struct ptrace_ldt ldt_op = (struct ptrace_ldt) {
+               .func = 2, /* read default ldt */
+               .ptr = ldtbuf,
+               .bytecount = sizeof(ldtbuf)};
+
+       printf("  - PTRACE_LDT...");
+       pid = start_ptraced_child(&stack);
+
+       n = ptrace(PTRACE_LDT, pid, 0, (unsigned long) &ldt_op);
+       if (n < 0) {
+               if(errno == EIO)
+                       printf("not found\n");
+               else {
+                       perror("not found");
+               }
+               ptrace_ldt = 0;
+       }
+       else {
+               if(ptrace_ldt)
+                       printf("found\n");
+               else
+                       printf("found, but use is disabled\n");
+       }
+
+       stop_ptraced_child(pid, stack, 1, 1);
+#else
+       /* PTRACE_LDT might be disabled via cmdline option.
+        * We want to override this, else we might use the stub
+        * without real need
+        */
+       ptrace_ldt = 1;
+#endif
+}
+
+static inline void check_skas3_proc_mm(void)
 {
-       printf("Checking for /proc/mm...");
+       printf("  - /proc/mm...");
        if (os_access("/proc/mm", OS_ACC_W_OK) < 0) {
                proc_mm = 0;
                printf("not found\n");
@@ -347,8 +447,19 @@ int can_do_skas(void)
                else
                        printf("found\n");
        }
+}
+
+int can_do_skas(void)
+{
+       printf("Checking for the skas3 patch in the host:\n");
+
+       check_skas3_proc_mm();
+       check_skas3_ptrace_faultinfo();
+       check_skas3_ptrace_ldt();
+
+       if(!proc_mm || !ptrace_faultinfo || !ptrace_ldt)
+               skas_needs_stub = 1;
 
-       check_skas3_ptrace_support();
        return 1;
 }
 #else
@@ -357,3 +468,74 @@ int can_do_skas(void)
        return(0);
 }
 #endif
+
+int have_devanon = 0;
+
+/* Runs on boot kernel stack - already safe to use printk. */
+
+void check_devanon(void)
+{
+       int fd;
+
+       printk("Checking for /dev/anon on the host...");
+       fd = open("/dev/anon", O_RDWR);
+       if(fd < 0){
+               printk("Not available (open failed with errno %d)\n", errno);
+               return;
+       }
+
+       printk("OK\n");
+       have_devanon = 1;
+}
+
+int __init parse_iomem(char *str, int *add)
+{
+       struct iomem_region *new;
+       struct uml_stat buf;
+       char *file, *driver;
+       int fd, err, size;
+
+       driver = str;
+       file = strchr(str,',');
+       if(file == NULL){
+               printf("parse_iomem : failed to parse iomem\n");
+               goto out;
+       }
+       *file = '\0';
+       file++;
+       fd = os_open_file(file, of_rdwr(OPENFLAGS()), 0);
+       if(fd < 0){
+               os_print_error(fd, "parse_iomem - Couldn't open io file");
+               goto out;
+       }
+
+       err = os_stat_fd(fd, &buf);
+       if(err < 0){
+               os_print_error(err, "parse_iomem - cannot stat_fd file");
+               goto out_close;
+       }
+
+       new = malloc(sizeof(*new));
+       if(new == NULL){
+               perror("Couldn't allocate iomem_region struct");
+               goto out_close;
+       }
+
+       size = (buf.ust_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1);
+
+       *new = ((struct iomem_region) { .next           = iomem_regions,
+                                       .driver         = driver,
+                                       .fd             = fd,
+                                       .size           = size,
+                                       .phys           = 0,
+                                       .virt           = 0 });
+       iomem_regions = new;
+       iomem_size += new->size + UM_KERN_PAGE_SIZE;
+
+       return(0);
+ out_close:
+       os_close_file(fd);
+ out:
+       return(1);
+}
+