Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / arch / x86_64 / ia32 / ptrace32.c
index f115f64..23a4515 100644 (file)
@@ -17,7 +17,9 @@
 #include <linux/syscalls.h>
 #include <linux/unistd.h>
 #include <linux/mm.h>
+#include <linux/ptrace.h>
 #include <asm/ptrace.h>
+#include <asm/compat.h>
 #include <asm/uaccess.h>
 #include <asm/user32.h>
 #include <asm/user.h>
 #include <asm/debugreg.h>
 #include <asm/i387.h>
 #include <asm/fpu32.h>
-#include <linux/ptrace.h>
-#include <linux/mm.h>
 
-/* determines which flags the user has access to. */
-/* 1 = access 0 = no access */
-#define FLAG_MASK 0x44dd5UL
+/*
+ * Determines which flags the user has access to [1 = access, 0 = no access].
+ * Prohibits changing ID(21), VIP(20), VIF(19), VM(17), IOPL(12-13), IF(9).
+ * Also masks reserved bits (31-22, 15, 5, 3, 1).
+ */
+#define FLAG_MASK 0x54dd5UL
 
 #define R32(l,q) \
        case offsetof(struct user32, regs.l): stack[offsetof(struct pt_regs, q)/8] = val; break
 static int putreg32(struct task_struct *child, unsigned regno, u32 val)
 {
        int i;
-       __u64 *stack = (__u64 *)(child->thread.rsp0 - sizeof(struct pt_regs)); 
+       __u64 *stack = (__u64 *)task_pt_regs(child);
 
        switch (regno) {
        case offsetof(struct user32, regs.fs):
                if (val && (val & 3) != 3) return -EIO; 
-               child->thread.fs = val & 0xffff; 
+               child->thread.fsindex = val & 0xffff;
                break;
        case offsetof(struct user32, regs.gs):
                if (val && (val & 3) != 3) return -EIO; 
-               child->thread.gs = val & 0xffff;
+               child->thread.gsindex = val & 0xffff;
                break;
        case offsetof(struct user32, regs.ds):
                if (val && (val & 3) != 3) return -EIO; 
@@ -109,7 +112,8 @@ static int putreg32(struct task_struct *child, unsigned regno, u32 val)
 
        case offsetof(struct user32, u_debugreg[7]):
                val &= ~DR_CONTROL_RESERVED;
-               /* You are not expected to understand this ... I don't neither. */
+               /* See arch/i386/kernel/ptrace.c for an explanation of
+                * this awkward check.*/
                for(i=0; i<4; i++)
                        if ((0x5454 >> ((val >> (16 + 4*i)) & 0xf)) & 1)
                               return -EIO;
@@ -133,14 +137,14 @@ static int putreg32(struct task_struct *child, unsigned regno, u32 val)
 
 static int getreg32(struct task_struct *child, unsigned regno, u32 *val)
 {
-       __u64 *stack = (__u64 *)(child->thread.rsp0 - sizeof(struct pt_regs)); 
+       __u64 *stack = (__u64 *)task_pt_regs(child);
 
        switch (regno) {
        case offsetof(struct user32, regs.fs):
-               *val = child->thread.fs
+               *val = child->thread.fsindex;
                break;
        case offsetof(struct user32, regs.gs):
-               *val = child->thread.gs;
+               *val = child->thread.gsindex;
                break;
        case offsetof(struct user32, regs.ds):
                *val = child->thread.ds;
@@ -195,40 +199,11 @@ static int getreg32(struct task_struct *child, unsigned regno, u32 *val)
 
 #undef R32
 
-static struct task_struct *find_target(int request, int pid, int *err)
-{ 
-       struct task_struct *child;
-
-       *err = -EPERM; 
-       if (pid == 1)
-               return NULL; 
-
-       *err = -ESRCH;
-       read_lock(&tasklist_lock);
-       child = find_task_by_pid(pid);
-       if (child)
-               get_task_struct(child);
-       read_unlock(&tasklist_lock);
-       if (child) { 
-               *err = -EPERM;
-               if (child->pid == 1) 
-                       goto out;
-               *err = ptrace_check_attach(child, request == PTRACE_KILL); 
-               if (*err < 0) 
-                       goto out;
-               return child; 
-       } 
- out:
-       if (child)
-       put_task_struct(child);
-       return NULL; 
-       
-} 
-
 asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
 {
        struct task_struct *child;
        struct pt_regs *childregs; 
+       void __user *datap = compat_ptr(data);
        int ret;
        __u32 val;
 
@@ -248,15 +223,22 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
        case PTRACE_GETFPREGS:
        case PTRACE_SETFPXREGS:
        case PTRACE_GETFPXREGS:
+       case PTRACE_GETEVENTMSG:
                break;
-               
        } 
 
-       child = find_target(request, pid, &ret);
-       if (!child)
-               return ret;
+       if (request == PTRACE_TRACEME)
+               return ptrace_traceme();
+
+       child = ptrace_get_task_struct(pid);
+       if (IS_ERR(child))
+               return PTR_ERR(child);
+
+       ret = ptrace_check_attach(child, request == PTRACE_KILL);
+       if (ret < 0)
+               goto out;
 
-       childregs = (struct pt_regs *)(child->thread.rsp0 - sizeof(struct pt_regs)); 
+       childregs = task_pt_regs(child);
 
        switch (request) {
        case PTRACE_PEEKDATA:
@@ -265,7 +247,7 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
                if (access_process_vm(child, addr, &val, sizeof(u32), 0)!=sizeof(u32))
                        ret = -EIO;
                else
-                       ret = put_user(val, (unsigned int *)(u64)data); 
+                       ret = put_user(val, (unsigned int __user *)datap); 
                break; 
 
        case PTRACE_POKEDATA:
@@ -278,7 +260,7 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
        case PTRACE_PEEKUSR:
                ret = getreg32(child, addr, &val);
                if (ret == 0)
-                       ret = put_user(val, (__u32 *)(unsigned long) data);
+                       ret = put_user(val, (__u32 __user *)datap);
                break;
 
        case PTRACE_POKEUSR:
@@ -287,15 +269,15 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
 
        case PTRACE_GETREGS: { /* Get all gp regs from the child. */
                int i;
-               if (!access_ok(VERIFY_WRITE, (unsigned *)(unsigned long)data, 16*4)) {
+               if (!access_ok(VERIFY_WRITE, datap, 16*4)) {
                        ret = -EIO;
                        break;
                }
                ret = 0;
                for ( i = 0; i <= 16*4 ; i += sizeof(__u32) ) {
                        getreg32(child, i, &val);
-                       ret |= __put_user(val,(u32 *) (unsigned long) data);
-                       data += sizeof(u32);
+                       ret |= __put_user(val,(u32 __user *)datap);
+                       datap += sizeof(u32);
                }
                break;
        }
@@ -303,40 +285,40 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
        case PTRACE_SETREGS: { /* Set all gp regs in the child. */
                unsigned long tmp;
                int i;
-               if (!access_ok(VERIFY_READ, (unsigned *)(unsigned long)data, 16*4)) {
+               if (!access_ok(VERIFY_READ, datap, 16*4)) {
                        ret = -EIO;
                        break;
                }
                ret = 0; 
                for ( i = 0; i <= 16*4; i += sizeof(u32) ) {
-                       ret |= __get_user(tmp, (u32 *) (unsigned long) data);
+                       ret |= __get_user(tmp, (u32 __user *)datap);
                        putreg32(child, i, tmp);
-                       data += sizeof(u32);
+                       datap += sizeof(u32);
                }
                break;
        }
 
        case PTRACE_GETFPREGS:
                ret = -EIO; 
-               if (!access_ok(VERIFY_READ, (void *)(u64)data
+               if (!access_ok(VERIFY_READ, compat_ptr(data)
                               sizeof(struct user_i387_struct)))
                        break;
-               save_i387_ia32(child, (void *)(u64)data, childregs, 1);
+               save_i387_ia32(child, datap, childregs, 1);
                ret = 0; 
                        break;
 
        case PTRACE_SETFPREGS:
                ret = -EIO;
-               if (!access_ok(VERIFY_WRITE, (void *)(u64)data
+               if (!access_ok(VERIFY_WRITE, datap
                               sizeof(struct user_i387_struct)))
                        break;
                ret = 0;
                /* don't check EFAULT to be bug-to-bug compatible to i386 */
-               restore_i387_ia32(child, (void *)(u64)data, 1);
+               restore_i387_ia32(child, datap, 1);
                break;
 
        case PTRACE_GETFPXREGS: { 
-               struct user32_fxsr_struct *u = (void *)(u64)data; 
+               struct user32_fxsr_struct __user *u = datap;
                init_fpu(child); 
                ret = -EIO;
                if (!access_ok(VERIFY_WRITE, u, sizeof(*u)))
@@ -349,24 +331,29 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
                break; 
        } 
        case PTRACE_SETFPXREGS: { 
-               struct user32_fxsr_struct *u = (void *)(u64)data; 
+               struct user32_fxsr_struct __user *u = datap;
                unlazy_fpu(child);
                ret = -EIO;
                if (!access_ok(VERIFY_READ, u, sizeof(*u)))
                        break;
                /* no checking to be bug-to-bug compatible with i386 */
                __copy_from_user(&child->thread.i387.fxsave, u, sizeof(*u));
-               child->used_math = 1;
+               set_stopped_child_used_math(child);
                child->thread.i387.fxsave.mxcsr &= mxcsr_feature_mask;
                ret = 0; 
                break;
        }
 
+       case PTRACE_GETEVENTMSG:
+               ret = put_user(child->ptrace_message,(unsigned int __user *)compat_ptr(data));
+               break;
+
        default:
                ret = -EINVAL;
                break;
        }
 
+ out:
        put_task_struct(child);
        return ret;
 }