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 01202b7..23a4515 100644 (file)
 #include <asm/i387.h>
 #include <asm/fpu32.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,36 +199,6 @@ 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;
@@ -249,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();
 
-       childregs = (struct pt_regs *)(child->thread.rsp0 - sizeof(struct pt_regs)); 
+       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 = task_pt_regs(child);
 
        switch (request) {
        case PTRACE_PEEKDATA:
@@ -357,17 +338,22 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
                        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;
 }