]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/um/sys-i386/ldt.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/shaggy...
[linux-2.6-omap-h63xx.git] / arch / um / sys-i386 / ldt.c
index dc755b0b9db8e6a6728ac82d1c1fc943909b9659..36b5c2c13289fd900e96f48d87c667f552b49721 100644 (file)
  */
 
 #include "linux/config.h"
+#include "linux/sched.h"
 #include "linux/slab.h"
+#include "linux/types.h"
 #include "asm/uaccess.h"
 #include "asm/ptrace.h"
+#include "asm/smp.h"
+#include "asm/ldt.h"
 #include "choose-mode.h"
 #include "kern.h"
+#include "mode_kern.h"
 
 #ifdef CONFIG_MODE_TT
-extern int modify_ldt(int func, void *ptr, unsigned long bytecount);
 
-/* XXX this needs copy_to_user and copy_from_user */
+extern int modify_ldt(int func, void *ptr, unsigned long bytecount);
 
-int sys_modify_ldt_tt(int func, void __user *ptr, unsigned long bytecount)
+static int do_modify_ldt_tt(int func, void *ptr, unsigned long bytecount)
 {
-       if (!access_ok(VERIFY_READ, ptr, bytecount))
-               return -EFAULT;
-
        return modify_ldt(func, ptr, bytecount);
 }
+
 #endif
 
 #ifdef CONFIG_MODE_SKAS
-extern int userspace_pid[];
 
+#include "skas.h"
 #include "skas_ptrace.h"
 
-int sys_modify_ldt_skas(int func, void __user *ptr, unsigned long bytecount)
+static int do_modify_ldt_skas(int func, void *ptr, unsigned long bytecount)
 {
        struct ptrace_ldt ldt;
-       void *buf;
-       int res, n;
+       u32 cpu;
+       int res;
 
-       buf = kmalloc(bytecount, GFP_KERNEL);
-       if(buf == NULL)
-               return(-ENOMEM);
+       ldt = ((struct ptrace_ldt) { .func      = func,
+                                    .ptr       = ptr,
+                                    .bytecount = bytecount });
 
-       res = 0;
+       cpu = get_cpu();
+       res = ptrace(PTRACE_LDT, userspace_pid[cpu], 0, (unsigned long) &ldt);
+       put_cpu();
+
+       return res;
+}
+#endif
+
+int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
+{
+       struct user_desc info;
+       int res = 0;
+       void *buf = NULL;
+       void *p = NULL; /* What we pass to host. */
 
        switch(func){
        case 1:
-       case 0x11:
-               res = copy_from_user(buf, ptr, bytecount);
-               break;
-       }
+       case 0x11: /* write_ldt */
+               /* Do this check now to avoid overflows. */
+               if (bytecount != sizeof(struct user_desc)) {
+                       res = -EINVAL;
+                       goto out;
+               }
+
+               if(copy_from_user(&info, ptr, sizeof(info))) {
+                       res = -EFAULT;
+                       goto out;
+               }
 
-       if(res != 0){
-               res = -EFAULT;
+               p = &info;
+               break;
+       case 0:
+       case 2: /* read_ldt */
+
+               /* The use of info avoids kmalloc on the write case, not on the
+                * read one. */
+               buf = kmalloc(bytecount, GFP_KERNEL);
+               if (!buf) {
+                       res = -ENOMEM;
+                       goto out;
+               }
+               p = buf;
+               break;
+       default:
+               res = -ENOSYS;
                goto out;
        }
 
-       ldt = ((struct ptrace_ldt) { .func      = func,
-                                    .ptr       = buf,
-                                    .bytecount = bytecount });
-#warning Need to look up userspace_pid by cpu
-       res = ptrace(PTRACE_LDT, userspace_pid[0], 0, (unsigned long) &ldt);
+       res = CHOOSE_MODE_PROC(do_modify_ldt_tt, do_modify_ldt_skas, func,
+                               p, bytecount);
        if(res < 0)
                goto out;
 
        switch(func){
        case 0:
        case 2:
-               n = res;
-               res = copy_to_user(ptr, buf, n);
-               if(res != 0)
+               /* Modify_ldt was for reading and returned the number of read
+                * bytes.*/
+               if(copy_to_user(ptr, p, res))
                        res = -EFAULT;
-               else 
-                       res = n;
                break;
        }
 
- out:
+out:
        kfree(buf);
-       return(res);
+       return res;
 }
-#endif
-
-int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
-{
-       return(CHOOSE_MODE_PROC(sys_modify_ldt_tt, sys_modify_ldt_skas, func, 
-                               ptr, bytecount));
-}
-
-
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */