linux-old/arch/x86_64/ia32/ptrace32.c
<<
>>
Prefs
   1/* 
   2 * 32bit ptrace for x86-64.
   3 *
   4 * Copyright 2001,2002 Andi Kleen, SuSE Labs.
   5 * Some parts copied from arch/i386/kernel/ptrace.c. See that file for earlier 
   6 * copyright.
   7 * 
   8 * This allows to access 64bit processes too; but there is no way to see the extended 
   9 * register contents.
  10 *
  11 * $Id: ptrace32.c,v 1.19 2004/01/29 03:31:13 ak Exp $
  12 */ 
  13
  14#include <linux/kernel.h>
  15#include <linux/stddef.h>
  16#include <linux/sched.h>
  17#include <linux/mm.h>
  18#include <asm/ptrace.h>
  19#include <asm/uaccess.h>
  20#include <asm/user32.h>
  21#include <asm/user.h>
  22#include <asm/errno.h>
  23#include <asm/debugreg.h>
  24#include <asm/i387.h>
  25#include <asm/fpu32.h>
  26#include <linux/mm.h>
  27
  28/* determines which flags the user has access to. */
  29/* 1 = access 0 = no access */
  30#define FLAG_MASK 0x44dd5UL
  31
  32#define R32(l,q) \
  33        case offsetof(struct user32, regs.l): stack[offsetof(struct pt_regs, q)/8] = val; break
  34
  35static int putreg32(struct task_struct *child, unsigned regno, u32 val)
  36{
  37        int i;
  38        __u64 *stack = (__u64 *)(child->thread.rsp0 - sizeof(struct pt_regs)); 
  39
  40        switch (regno) {
  41        case offsetof(struct user32, regs.fs):
  42        if (val && (val & 3) != 3) return -EIO;
  43        child->thread.fs = val & 0xffff; 
  44                break;
  45        case offsetof(struct user32, regs.gs):
  46            if (val && (val & 3) != 3) return -EIO;
  47                child->thread.gs = val & 0xffff;
  48                break;
  49        case offsetof(struct user32, regs.ds):
  50                if (val && (val & 3) != 3) return -EIO; 
  51                child->thread.ds = val & 0xffff;
  52                break;
  53        case offsetof(struct user32, regs.es):
  54                child->thread.es = val & 0xffff;
  55                break;
  56    case offsetof(struct user32, regs.ss):
  57                if ((val & 3) != 3) return -EIO; 
  58        stack[offsetof(struct pt_regs, ss)/8] = val & 0xffff;
  59        break;
  60        case offsetof(struct user32, regs.cs):
  61                if ((val & 3) != 3) return -EIO;
  62                stack[offsetof(struct pt_regs, cs)/8] = val & 0xffff;
  63                break;
  64
  65        R32(ebx, rbx); 
  66        R32(ecx, rcx);
  67        R32(edx, rdx);
  68        R32(edi, rdi);
  69        R32(esi, rsi);
  70        R32(ebp, rbp);
  71        R32(eax, rax);
  72        R32(orig_eax, orig_rax);
  73        R32(eip, rip);
  74        R32(esp, rsp);
  75
  76        case offsetof(struct user32, regs.eflags): { 
  77                __u64 *flags = &stack[offsetof(struct pt_regs, eflags)/8];
  78                val &= FLAG_MASK;
  79                *flags = val | (*flags & ~FLAG_MASK);
  80                break;
  81        }
  82
  83        case offsetof(struct user32, u_debugreg[4]): 
  84        case offsetof(struct user32, u_debugreg[5]):
  85                return -EIO;
  86
  87        case offsetof(struct user32, u_debugreg[0]) ...
  88             offsetof(struct user32, u_debugreg[3]):
  89        case offsetof(struct user32, u_debugreg[6]):
  90                child->thread.debugreg
  91                        [(regno-offsetof(struct user32, u_debugreg[0]))/4] 
  92                        = val; 
  93                break; 
  94
  95        case offsetof(struct user32, u_debugreg[7]):
  96                val &= ~DR_CONTROL_RESERVED;
  97                /* You are not expected to understand this ... I don't neither. */
  98                for(i=0; i<4; i++)
  99                        if ((0x5454 >> ((val >> (16 + 4*i)) & 0xf)) & 1)
 100                               return -EIO;
 101                child->thread.debugreg[7] = val; 
 102                break; 
 103                    
 104        default:
 105                if (regno > sizeof(struct user32) || (regno & 3))
 106                        return -EIO;
 107               
 108                /* Other dummy fields in the virtual user structure are ignored */ 
 109                break;          
 110        }
 111        return 0;
 112}
 113
 114#undef R32
 115
 116#define R32(l,q) \
 117        case offsetof(struct user32, regs.l): *val = stack[offsetof(struct pt_regs, q)/8]; break
 118
 119static int getreg32(struct task_struct *child, unsigned regno, u32 *val)
 120{
 121        __u64 *stack = (__u64 *)(child->thread.rsp0 - sizeof(struct pt_regs)); 
 122
 123        switch (regno) {
 124        case offsetof(struct user32, regs.fs):
 125                *val = child->thread.fs; 
 126                break;
 127        case offsetof(struct user32, regs.gs):
 128                *val = child->thread.gs;
 129                break;
 130        case offsetof(struct user32, regs.ds):
 131                *val = child->thread.ds;
 132                break;
 133        case offsetof(struct user32, regs.es):
 134                *val = child->thread.es;
 135                break;
 136
 137        R32(cs, cs);
 138        R32(ss, ss);
 139        R32(ebx, rbx); 
 140        R32(ecx, rcx);
 141        R32(edx, rdx);
 142        R32(edi, rdi);
 143        R32(esi, rsi);
 144        R32(ebp, rbp);
 145        R32(eax, rax);
 146        R32(orig_eax, orig_rax);
 147        R32(eip, rip);
 148        R32(eflags, eflags);
 149        R32(esp, rsp);
 150
 151        case offsetof(struct user32, u_debugreg[0]) ... offsetof(struct user32, u_debugreg[7]):
 152                *val = child->thread.debugreg[(regno-offsetof(struct user32, u_debugreg[0]))/4]; 
 153                break; 
 154                    
 155        default:
 156                if (regno > sizeof(struct user32) || (regno & 3))
 157                        return -EIO;
 158
 159                /* Other dummy fields in the virtual user structure are ignored */ 
 160                *val = 0;
 161                break;          
 162        }
 163        return 0;
 164}
 165
 166#undef R32
 167
 168static struct task_struct *find_target(int request, int pid, int *err)
 169{ 
 170        struct task_struct *child;
 171
 172        *err = -EPERM; 
 173        if (pid == 1)
 174                return NULL; 
 175
 176        *err = -ESRCH;
 177        read_lock(&tasklist_lock);
 178        child = find_task_by_pid(pid);
 179        if (child)
 180                get_task_struct(child);
 181        read_unlock(&tasklist_lock);
 182        if (child) { 
 183                *err = -EPERM;
 184                if (pid == 1) 
 185                        goto out;
 186                *err = ptrace_check_attach(child, request == PTRACE_KILL); 
 187                if (*err < 0) 
 188                        goto out;
 189                return child; 
 190
 191 out:
 192                free_task_struct(child);
 193        } 
 194        return NULL; 
 195        
 196} 
 197
 198extern asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, unsigned long data);
 199
 200asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
 201{
 202        struct task_struct *child;
 203        struct pt_regs *childregs; 
 204        int ret;
 205        __u32 val;
 206
 207        switch (request) { 
 208        case PTRACE_TRACEME:
 209        case PTRACE_ATTACH:
 210        case PTRACE_SYSCALL:
 211        case PTRACE_CONT:
 212        case PTRACE_KILL:
 213        case PTRACE_SINGLESTEP:
 214        case PTRACE_DETACH:
 215        case PTRACE_SETOPTIONS:
 216                ret = sys_ptrace(request, pid, addr, data); 
 217                return ret;
 218
 219        case PTRACE_PEEKTEXT:
 220        case PTRACE_PEEKDATA:
 221        case PTRACE_POKEDATA:
 222        case PTRACE_POKETEXT:
 223        case PTRACE_POKEUSR:       
 224        case PTRACE_PEEKUSR:
 225        case PTRACE_GETREGS:
 226        case PTRACE_SETREGS:
 227        case PTRACE_SETFPREGS:
 228        case PTRACE_GETFPREGS:
 229        case PTRACE_SETFPXREGS:
 230        case PTRACE_GETFPXREGS:
 231                break;
 232                
 233        default:
 234                return -EIO;
 235        } 
 236
 237        child = find_target(request, pid, &ret);
 238        if (!child)
 239                return ret;
 240        
 241        childregs = (struct pt_regs *)(child->thread.rsp0 - sizeof(struct pt_regs)); 
 242
 243        switch (request) {
 244        case PTRACE_PEEKDATA:
 245        case PTRACE_PEEKTEXT:
 246                ret = 0;
 247                if (access_process_vm(child, addr, &val, sizeof(u32), 0)!=sizeof(u32))
 248                        ret = -EIO;
 249                else
 250                        ret = put_user(val, (unsigned int *)(u64)data); 
 251                break; 
 252
 253        case PTRACE_POKEDATA:
 254        case PTRACE_POKETEXT:
 255                ret = 0;
 256                if (access_process_vm(child, addr, &data, sizeof(u32), 1)!=sizeof(u32))
 257                        ret = -EIO; 
 258                break;
 259
 260        case PTRACE_PEEKUSR:
 261                ret = getreg32(child, addr, &val);
 262                if (ret == 0)
 263                        ret = put_user(val, (__u32 *)(unsigned long) data);
 264                break;
 265
 266        case PTRACE_POKEUSR:
 267                ret = putreg32(child, addr, data);
 268                break;
 269
 270        case PTRACE_GETREGS: { /* Get all gp regs from the child. */
 271                int i;
 272                if (!access_ok(VERIFY_WRITE, (unsigned *)(unsigned long)data, 16*4)) {
 273                        ret = -EIO;
 274                        break;
 275                }
 276                ret = 0;
 277                for ( i = 0; i <= 16*4 ; i += sizeof(__u32) ) {
 278                        getreg32(child, i, &val);
 279                        ret |= __put_user(val,(u32 *) (unsigned long) data);
 280                        data += sizeof(u32);
 281                }
 282                break;
 283        }
 284
 285        case PTRACE_SETREGS: { /* Set all gp regs in the child. */
 286                unsigned long tmp;
 287                int i;
 288                if (!access_ok(VERIFY_READ, (unsigned *)(unsigned long)data, 16*4)) {
 289                        ret = -EIO;
 290                        break;
 291                }
 292                ret = 0; 
 293                for ( i = 0; i <= 16*4; i += sizeof(u32) ) {
 294                        ret |= __get_user(tmp, (u32 *) (unsigned long) data);
 295                        putreg32(child, i, tmp);
 296                        data += sizeof(u32);
 297                }
 298                break;
 299        }
 300
 301        case PTRACE_GETFPREGS:
 302                ret = -EIO; 
 303                if (!access_ok(VERIFY_READ, (void *)(u64)data, 
 304                               sizeof(struct user_i387_struct)))
 305                        break;
 306                save_i387_ia32(child, (void *)(u64)data, childregs, 1);
 307                ret = 0; 
 308                break;
 309
 310        case PTRACE_SETFPREGS:
 311                ret = -EIO;
 312                if (!access_ok(VERIFY_WRITE, (void *)(u64)data, 
 313                               sizeof(struct user_i387_struct)))
 314                        break;
 315                ret = 0;
 316                /* don't check EFAULT to be bug-to-bug compatible to i386 */
 317                restore_i387_ia32(child, (void *)(u64)data, 1);
 318                break;
 319
 320        case PTRACE_GETFPXREGS: { 
 321                struct user32_fxsr_struct *u = (void *)(u64)data; 
 322                init_fpu(child); 
 323                ret = -EIO;
 324                if (!access_ok(VERIFY_WRITE, u, sizeof(*u)))
 325                        break;
 326                        ret = -EFAULT;
 327                if (__copy_to_user(u, &child->thread.i387.fxsave, sizeof(*u)))
 328                        break;
 329                ret = __put_user(childregs->cs, &u->fcs);
 330                ret |= __put_user(child->thread.ds, &u->fos); 
 331                break; 
 332        } 
 333        case PTRACE_SETFPXREGS: { 
 334                struct user32_fxsr_struct *u = (void *)(u64)data; 
 335                unlazy_fpu(child);
 336                ret = -EIO;
 337                if (!access_ok(VERIFY_READ, u, sizeof(*u)))
 338                        break;
 339                /* no checking to be bug-to-bug compatible with i386 */
 340                __copy_from_user(&child->thread.i387.fxsave, u, sizeof(*u));
 341                child->used_math = 1;
 342                child->thread.i387.fxsave.mxcsr &= 0xffbf;
 343                ret = 0; 
 344                break; 
 345        } 
 346
 347        default:
 348                ret = -EINVAL;
 349                break;
 350        }
 351
 352        free_task_struct(child);
 353        return ret;
 354}
 355
 356
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.