Exemple #1
0
asmlinkage void do_ptrace(struct pt_regs *regs)
{
    int request = regs->u_regs[UREG_I0];
    pid_t pid = regs->u_regs[UREG_I1];
    unsigned long addr = regs->u_regs[UREG_I2];
    unsigned long data = regs->u_regs[UREG_I3];
    unsigned long addr2 = regs->u_regs[UREG_I4];
    struct task_struct *child;
    int ret;

    if (test_thread_flag(TIF_32BIT)) {
        addr &= 0xffffffffUL;
        data &= 0xffffffffUL;
        addr2 &= 0xffffffffUL;
    }
    lock_kernel();
#ifdef DEBUG_PTRACE
    {
        char *s;

        if ((request >= 0) && (request <= 24))
            s = pt_rq [request];
        else
            s = "unknown";

        if (request == PTRACE_POKEDATA && data == 0x91d02001) {
            printk ("do_ptrace: breakpoint pid=%d, addr=%016lx addr2=%016lx\n",
                    pid, addr, addr2);
        } else
            printk("do_ptrace: rq=%s(%d) pid=%d addr=%016lx data=%016lx addr2=%016lx\n",
                   s, request, pid, addr, data, addr2);
    }
#endif
    if (request == PTRACE_TRACEME) {
        int ret;

        /* are we already being traced? */
        if (current->ptrace & PT_PTRACED) {
            pt_error_return(regs, EPERM);
            goto out;
        }
        ret = security_ptrace(current->parent, current);
        if (ret) {
            pt_error_return(regs, -ret);
            goto out;
        }

        /* set the ptrace bit in the process flags. */
        current->ptrace |= PT_PTRACED;
        pt_succ_return(regs, 0);
        goto out;
    }
#ifndef ALLOW_INIT_TRACING
    if (pid == 1) {
        /* Can't dork with init. */
        pt_error_return(regs, EPERM);
        goto out;
    }
#endif
    read_lock(&tasklist_lock);
    child = find_task_by_pid(pid);
    if (child)
        get_task_struct(child);
    read_unlock(&tasklist_lock);

    if (!child) {
        pt_error_return(regs, ESRCH);
        goto out;
    }

    if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH)
            || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) {
        if (ptrace_attach(child)) {
            pt_error_return(regs, EPERM);
            goto out_tsk;
        }
        pt_succ_return(regs, 0);
        goto out_tsk;
    }

    ret = ptrace_check_attach(child, request == PTRACE_KILL);
    if (ret < 0) {
        pt_error_return(regs, -ret);
        goto out_tsk;
    }

    if (!(test_thread_flag(TIF_32BIT))	&&
            ((request == PTRACE_READDATA64)		||
             (request == PTRACE_WRITEDATA64)		||
             (request == PTRACE_READTEXT64)		||
             (request == PTRACE_WRITETEXT64)		||
             (request == PTRACE_PEEKTEXT64)		||
             (request == PTRACE_POKETEXT64)		||
             (request == PTRACE_PEEKDATA64)		||
             (request == PTRACE_POKEDATA64))) {
        addr = regs->u_regs[UREG_G2];
        addr2 = regs->u_regs[UREG_G3];
        request -= 30; /* wheee... */
    }

    switch(request) {
    case PTRACE_PEEKTEXT: /* read word at location addr. */
    case PTRACE_PEEKDATA: {
        unsigned long tmp64;
        unsigned int tmp32;
        int res, copied;

        res = -EIO;
        if (test_thread_flag(TIF_32BIT)) {
            copied = access_process_vm(child, addr,
                                       &tmp32, sizeof(tmp32), 0);
            tmp64 = (unsigned long) tmp32;
            if (copied == sizeof(tmp32))
                res = 0;
        } else {
            copied = access_process_vm(child, addr,
                                       &tmp64, sizeof(tmp64), 0);
            if (copied == sizeof(tmp64))
                res = 0;
        }
        if (res < 0)
            pt_error_return(regs, -res);
        else
            pt_os_succ_return(regs, tmp64, (long *) data);
        goto flush_and_out;
    }

    case PTRACE_POKETEXT: /* write the word at location addr. */
    case PTRACE_POKEDATA: {
        unsigned long tmp64;
        unsigned int tmp32;
        int copied, res = -EIO;

        if (test_thread_flag(TIF_32BIT)) {
            tmp32 = data;
            copied = access_process_vm(child, addr,
                                       &tmp32, sizeof(tmp32), 1);
            if (copied == sizeof(tmp32))
                res = 0;
        } else {
            tmp64 = data;
            copied = access_process_vm(child, addr,
                                       &tmp64, sizeof(tmp64), 1);
            if (copied == sizeof(tmp64))
                res = 0;
        }
        if (res < 0)
            pt_error_return(regs, -res);
        else
            pt_succ_return(regs, res);
        goto flush_and_out;
    }

    case PTRACE_GETREGS: {
        struct pt_regs32 *pregs = (struct pt_regs32 *) addr;
        struct pt_regs *cregs = child->thread_info->kregs;
        int rval;

        if (__put_user(tstate_to_psr(cregs->tstate), (&pregs->psr)) ||
                __put_user(cregs->tpc, (&pregs->pc)) ||
                __put_user(cregs->tnpc, (&pregs->npc)) ||
                __put_user(cregs->y, (&pregs->y))) {
            pt_error_return(regs, EFAULT);
            goto out_tsk;
        }
        for (rval = 1; rval < 16; rval++)
            if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) {
                pt_error_return(regs, EFAULT);
                goto out_tsk;
            }
        pt_succ_return(regs, 0);
#ifdef DEBUG_PTRACE
        printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]);
#endif
        goto out_tsk;
    }

    case PTRACE_GETREGS64: {
        struct pt_regs *pregs = (struct pt_regs *) addr;
        struct pt_regs *cregs = child->thread_info->kregs;
        unsigned long tpc = cregs->tpc;
        int rval;

        if ((child->thread_info->flags & _TIF_32BIT) != 0)
            tpc &= 0xffffffff;
        if (__put_user(cregs->tstate, (&pregs->tstate)) ||
                __put_user(tpc, (&pregs->tpc)) ||
                __put_user(cregs->tnpc, (&pregs->tnpc)) ||
                __put_user(cregs->y, (&pregs->y))) {
            pt_error_return(regs, EFAULT);
            goto out_tsk;
        }
        for (rval = 1; rval < 16; rval++)
            if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) {
                pt_error_return(regs, EFAULT);
                goto out_tsk;
            }
        pt_succ_return(regs, 0);
#ifdef DEBUG_PTRACE
        printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]);
#endif
        goto out_tsk;
    }

    case PTRACE_SETREGS: {
        struct pt_regs32 *pregs = (struct pt_regs32 *) addr;
        struct pt_regs *cregs = child->thread_info->kregs;
        unsigned int psr, pc, npc, y;
        int i;

        /* Must be careful, tracing process can only set certain
         * bits in the psr.
         */
        if (__get_user(psr, (&pregs->psr)) ||
                __get_user(pc, (&pregs->pc)) ||
                __get_user(npc, (&pregs->npc)) ||
                __get_user(y, (&pregs->y))) {
            pt_error_return(regs, EFAULT);
            goto out_tsk;
        }
        cregs->tstate &= ~(TSTATE_ICC);
        cregs->tstate |= psr_to_tstate_icc(psr);
        if (!((pc | npc) & 3)) {
            cregs->tpc = pc;
            cregs->tnpc = npc;
        }
        cregs->y = y;
        for (i = 1; i < 16; i++) {
            if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
                pt_error_return(regs, EFAULT);
                goto out_tsk;
            }
        }
        pt_succ_return(regs, 0);
        goto out_tsk;
    }

    case PTRACE_SETREGS64: {
        struct pt_regs *pregs = (struct pt_regs *) addr;
        struct pt_regs *cregs = child->thread_info->kregs;
        unsigned long tstate, tpc, tnpc, y;
        int i;

        /* Must be careful, tracing process can only set certain
         * bits in the psr.
         */
        if (__get_user(tstate, (&pregs->tstate)) ||
                __get_user(tpc, (&pregs->tpc)) ||
                __get_user(tnpc, (&pregs->tnpc)) ||
                __get_user(y, (&pregs->y))) {
            pt_error_return(regs, EFAULT);
            goto out_tsk;
        }
        if ((child->thread_info->flags & _TIF_32BIT) != 0) {
            tpc &= 0xffffffff;
            tnpc &= 0xffffffff;
        }
        tstate &= (TSTATE_ICC | TSTATE_XCC);
        cregs->tstate &= ~(TSTATE_ICC | TSTATE_XCC);
        cregs->tstate |= tstate;
        if (!((tpc | tnpc) & 3)) {
            cregs->tpc = tpc;
            cregs->tnpc = tnpc;
        }
        cregs->y = y;
        for (i = 1; i < 16; i++) {
            if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
                pt_error_return(regs, EFAULT);
                goto out_tsk;
            }
        }
        pt_succ_return(regs, 0);
        goto out_tsk;
    }

    case PTRACE_GETFPREGS: {
        struct fps {
            unsigned int regs[32];
            unsigned int fsr;
            unsigned int flags;
            unsigned int extra;
            unsigned int fpqd;
            struct fq {
                unsigned int insnaddr;
                unsigned int insn;
            } fpq[16];
        } *fps = (struct fps *) addr;
        unsigned long *fpregs = child->thread_info->fpregs;

        if (copy_to_user(&fps->regs[0], fpregs,
                         (32 * sizeof(unsigned int))) ||
                __put_user(child->thread_info->xfsr[0], (&fps->fsr)) ||
                __put_user(0, (&fps->fpqd)) ||
                __put_user(0, (&fps->flags)) ||
                __put_user(0, (&fps->extra)) ||
                clear_user(&fps->fpq[0], 32 * sizeof(unsigned int))) {
            pt_error_return(regs, EFAULT);
            goto out_tsk;
        }
        pt_succ_return(regs, 0);
        goto out_tsk;
    }

    case PTRACE_GETFPREGS64: {
        struct fps {
            unsigned int regs[64];
            unsigned long fsr;
        } *fps = (struct fps *) addr;
        unsigned long *fpregs = child->thread_info->fpregs;

        if (copy_to_user(&fps->regs[0], fpregs,
                         (64 * sizeof(unsigned int))) ||
                __put_user(child->thread_info->xfsr[0], (&fps->fsr))) {
            pt_error_return(regs, EFAULT);
            goto out_tsk;
        }
        pt_succ_return(regs, 0);
        goto out_tsk;
    }

    case PTRACE_SETFPREGS: {
        struct fps {
            unsigned int regs[32];
            unsigned int fsr;
            unsigned int flags;
            unsigned int extra;
            unsigned int fpqd;
            struct fq {
                unsigned int insnaddr;
                unsigned int insn;
            } fpq[16];
        } *fps = (struct fps *) addr;
        unsigned long *fpregs = child->thread_info->fpregs;
        unsigned fsr;

        if (copy_from_user(fpregs, &fps->regs[0],
                           (32 * sizeof(unsigned int))) ||
                __get_user(fsr, (&fps->fsr))) {
            pt_error_return(regs, EFAULT);
            goto out_tsk;
        }
        child->thread_info->xfsr[0] &= 0xffffffff00000000UL;
        child->thread_info->xfsr[0] |= fsr;
        if (!(child->thread_info->fpsaved[0] & FPRS_FEF))
            child->thread_info->gsr[0] = 0;
        child->thread_info->fpsaved[0] |= (FPRS_FEF | FPRS_DL);
        pt_succ_return(regs, 0);
        goto out_tsk;
    }

    case PTRACE_SETFPREGS64: {
        struct fps {
            unsigned int regs[64];
            unsigned long fsr;
        } *fps = (struct fps *) addr;
        unsigned long *fpregs = child->thread_info->fpregs;

        if (copy_from_user(fpregs, &fps->regs[0],
                           (64 * sizeof(unsigned int))) ||
                __get_user(child->thread_info->xfsr[0], (&fps->fsr))) {
            pt_error_return(regs, EFAULT);
            goto out_tsk;
        }
        if (!(child->thread_info->fpsaved[0] & FPRS_FEF))
            child->thread_info->gsr[0] = 0;
        child->thread_info->fpsaved[0] |= (FPRS_FEF | FPRS_DL | FPRS_DU);
        pt_succ_return(regs, 0);
        goto out_tsk;
    }

    case PTRACE_READTEXT:
    case PTRACE_READDATA: {
        int res = ptrace_readdata(child, addr,
                                  (void *)addr2, data);
        if (res == data) {
            pt_succ_return(regs, 0);
            goto flush_and_out;
        }
        if (res >= 0)
            res = -EIO;
        pt_error_return(regs, -res);
        goto flush_and_out;
    }

    case PTRACE_WRITETEXT:
    case PTRACE_WRITEDATA: {
        int res = ptrace_writedata(child, (void *) addr2,
                                   addr, data);
        if (res == data) {
            pt_succ_return(regs, 0);
            goto flush_and_out;
        }
        if (res >= 0)
            res = -EIO;
        pt_error_return(regs, -res);
        goto flush_and_out;
    }
    case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
        addr = 1;

    case PTRACE_CONT: { /* restart after signal. */
        if (data > _NSIG) {
            pt_error_return(regs, EIO);
            goto out_tsk;
        }
        if (addr != 1) {
            unsigned long pc_mask = ~0UL;

            if ((child->thread_info->flags & _TIF_32BIT) != 0)
                pc_mask = 0xffffffff;

            if (addr & 3) {
                pt_error_return(regs, EINVAL);
                goto out_tsk;
            }
#ifdef DEBUG_PTRACE
            printk ("Original: %016lx %016lx\n",
                    child->thread_info->kregs->tpc,
                    child->thread_info->kregs->tnpc);
            printk ("Continuing with %016lx %016lx\n", addr, addr+4);
#endif
            child->thread_info->kregs->tpc = (addr & pc_mask);
            child->thread_info->kregs->tnpc = ((addr + 4) & pc_mask);
        }

        if (request == PTRACE_SYSCALL) {
            set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
        } else {
            clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
        }

        child->exit_code = data;
#ifdef DEBUG_PTRACE
        printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n", child->comm,
               child->pid, child->exit_code,
               child->thread_info->kregs->tpc,
               child->thread_info->kregs->tnpc);

#endif
        wake_up_process(child);
        pt_succ_return(regs, 0);
        goto out_tsk;
    }

    /*
     * make the child exit.  Best I can do is send it a sigkill.
     * perhaps it should be put in the status that it wants to
     * exit.
     */
    case PTRACE_KILL: {
        if (child->state == TASK_ZOMBIE) {	/* already dead */
            pt_succ_return(regs, 0);
            goto out_tsk;
        }
        child->exit_code = SIGKILL;
        wake_up_process(child);
        pt_succ_return(regs, 0);
        goto out_tsk;
    }

    case PTRACE_SUNDETACH: { /* detach a process that was attached. */
        int error = ptrace_detach(child, data);
        if (error) {
            pt_error_return(regs, EIO);
            goto out_tsk;
        }
        pt_succ_return(regs, 0);
        goto out_tsk;
    }

    /* PTRACE_DUMPCORE unsupported... */

    default: {
        int err = ptrace_request(child, request, addr, data);
        if (err)
            pt_error_return(regs, -err);
        else
            pt_succ_return(regs, 0);
        goto out_tsk;
    }
    }
flush_and_out:
    {
        unsigned long va;

        if (tlb_type == cheetah || tlb_type == cheetah_plus) {
            for (va = 0; va < (1 << 16); va += (1 << 5))
                spitfire_put_dcache_tag(va, 0x0);
            /* No need to mess with I-cache on Cheetah. */
        } else {
            for (va =  0; va < L1DCACHE_SIZE; va += 32)
                spitfire_put_dcache_tag(va, 0x0);
            if (request == PTRACE_PEEKTEXT ||
                    request == PTRACE_POKETEXT ||
                    request == PTRACE_READTEXT ||
                    request == PTRACE_WRITETEXT) {
                for (va =  0; va < (PAGE_SIZE << 1); va += 32)
                    spitfire_put_icache_tag(va, 0x0);
                __asm__ __volatile__("flush %g6");
            }
        }
    }
out_tsk:
    if (child)
        put_task_struct(child);
out:
    unlock_kernel();
}
Exemple #2
0
/* 
 * Note that this implementation of ptrace behaves differently from vanilla
 * ptrace.  Contrary to what the man page says, in the PTRACE_PEEKTEXT,
 * PTRACE_PEEKDATA, and PTRACE_PEEKUSER requests the data variable is not
 * ignored.  Instead, the data variable is expected to point at a location
 * (in user space) where the result of the ptrace call is written (instead of
 * being returned).
 */
asmlinkage int 
sys_ptrace(long request, long pid, long addr, long data)
{
	struct task_struct *child;
	int ret;
	unsigned long __user *datap = (unsigned long __user *)data;

	lock_kernel();
	ret = -EPERM;
	
	if (request == PTRACE_TRACEME) {
		if (current->ptrace & PT_PTRACED)
			goto out;

		current->ptrace |= PT_PTRACED;
		ret = 0;
		goto out;
	}
	
	ret = -ESRCH;
	read_lock(&tasklist_lock);
	child = find_task_by_pid(pid);
	
	if (child)
		get_task_struct(child);
	
	read_unlock(&tasklist_lock);
	
	if (!child)
		goto out;
	
	ret = -EPERM;
	
	if (pid == 1)		/* Leave the init process alone! */
		goto out_tsk;
	
	if (request == PTRACE_ATTACH) {
		ret = ptrace_attach(child);
		goto out_tsk;
	}
	
	ret = ptrace_check_attach(child, request == PTRACE_KILL);
	if (ret < 0)
		goto out_tsk;

	switch (request) {
		/* Read word at location address. */ 
		case PTRACE_PEEKTEXT:
		case PTRACE_PEEKDATA: {
			unsigned long tmp;
			int copied;

			copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
			ret = -EIO;
			
			if (copied != sizeof(tmp))
				break;
			
			ret = put_user(tmp,datap);
			break;
		}

		/* Read the word at location address in the USER area. */
		case PTRACE_PEEKUSR: {
			unsigned long tmp;

			ret = -EIO;
			if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
				break;

			tmp = get_reg(child, addr >> 2);
			ret = put_user(tmp, datap);
			break;
		}
		
		/* Write the word at location address. */
		case PTRACE_POKETEXT:
		case PTRACE_POKEDATA:
			ret = 0;
			
			if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
				break;
			
			ret = -EIO;
			break;
 
 		/* Write the word at location address in the USER area. */
		case PTRACE_POKEUSR:
			ret = -EIO;
			if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
				break;

			addr >>= 2;

			if (addr == PT_DCCR) {
				/* don't allow the tracing process to change stuff like
				 * interrupt enable, kernel/user bit, dma enables etc.
				 */
				data &= DCCR_MASK;
				data |= get_reg(child, PT_DCCR) & ~DCCR_MASK;
			}
			if (put_reg(child, addr, data))
				break;
			ret = 0;
			break;

		case PTRACE_SYSCALL:
		case PTRACE_CONT:
			ret = -EIO;
			
			if (!valid_signal(data))
				break;
                        
			if (request == PTRACE_SYSCALL) {
				set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
			}
			else {
				clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
			}
			
			child->exit_code = data;
			
			/* TODO: make sure any pending breakpoint is killed */
			wake_up_process(child);
			ret = 0;
			
			break;
		
 		/* Make the child exit by sending it a sigkill. */
		case PTRACE_KILL:
			ret = 0;
			
			if (child->state == TASK_ZOMBIE)
				break;
			
			child->exit_code = SIGKILL;
			
			/* TODO: make sure any pending breakpoint is killed */
			wake_up_process(child);
			break;

		/* Set the trap flag. */
		case PTRACE_SINGLESTEP:
			ret = -EIO;
			
			if (!valid_signal(data))
				break;
			
			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);

			/* TODO: set some clever breakpoint mechanism... */

			child->exit_code = data;
			wake_up_process(child);
			ret = 0;
			break;

		case PTRACE_DETACH:
			ret = ptrace_detach(child, data);
			break;

		/* Get all GP registers from the child. */
		case PTRACE_GETREGS: {
		  	int i;
			unsigned long tmp;
			
			for (i = 0; i <= PT_MAX; i++) {
				tmp = get_reg(child, i);
				
				if (put_user(tmp, datap)) {
					ret = -EFAULT;
					goto out_tsk;
				}
				
				data += sizeof(long);
			}

			ret = 0;
			break;
		}

		/* Set all GP registers in the child. */
		case PTRACE_SETREGS: {
			int i;
			unsigned long tmp;
			
			for (i = 0; i <= PT_MAX; i++) {
				if (get_user(tmp, datap)) {
					ret = -EFAULT;
					goto out_tsk;
				}
				
				if (i == PT_DCCR) {
					tmp &= DCCR_MASK;
					tmp |= get_reg(child, PT_DCCR) & ~DCCR_MASK;
				}
				
				put_reg(child, i, tmp);
				data += sizeof(long);
			}
			
			ret = 0;
			break;
		}

		default:
			ret = ptrace_request(child, request, addr, data);
			break;
	}
out_tsk:
	put_task_struct(child);
out:
	unlock_kernel();
	return ret;
}
Exemple #3
0
int sys_ptrace(long request, long pid, long addr, long data)
{
	struct task_struct *child;
	int ret = -EPERM;

	lock_kernel();
	if (request == PTRACE_TRACEME) {
		/* are we already being traced? */
		if (current->ptrace & PT_PTRACED)
			goto out;
		ret = security_ptrace(current->parent, current);
		if (ret)
			goto out;
		/* set the ptrace bit in the process flags. */
		current->ptrace |= PT_PTRACED;
		ret = 0;
		goto out;
	}
	ret = -ESRCH;
	read_lock(&tasklist_lock);
	child = find_task_by_pid(pid);
	if (child)
		get_task_struct(child);
	read_unlock(&tasklist_lock);
	if (!child)
		goto out;

	ret = -EPERM;
	if (pid == 1)		/* you may not mess with init */
		goto out_tsk;

	if (request == PTRACE_ATTACH) {
		ret = ptrace_attach(child);
		goto out_tsk;
	}

	ret = ptrace_check_attach(child, request == PTRACE_KILL);
	if (ret < 0)
		goto out_tsk;

	switch (request) {
	/* when I and D space are separate, these will need to be fixed. */
	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
	case PTRACE_PEEKDATA: {
		unsigned long tmp;
		int copied;

		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
		ret = -EIO;
		if (copied != sizeof(tmp))
			break;
		ret = put_user(tmp,(unsigned long __user *) data);
		break;
	}

	/* read the word at location addr in the USER area. */
	case PTRACE_PEEKUSR: {
		unsigned long index;
		unsigned long tmp;

		ret = -EIO;
		/* convert to index and check */
		index = (unsigned long) addr >> 3;
		if ((addr & 7) || (index > PT_FPSCR))
			break;

		if (index < PT_FPR0) {
			tmp = get_reg(child, (int)index);
		} else {
			flush_fp_to_thread(child);
			tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0];
		}
		ret = put_user(tmp,(unsigned long __user *) data);
		break;
	}

	/* If I and D space are separate, this will have to be fixed. */
	case PTRACE_POKETEXT: /* write the word at location addr. */
	case PTRACE_POKEDATA:
		ret = 0;
		if (access_process_vm(child, addr, &data, sizeof(data), 1)
				== sizeof(data))
			break;
		ret = -EIO;
		break;

	/* write the word at location addr in the USER area */
	case PTRACE_POKEUSR: {
		unsigned long index;

		ret = -EIO;
		/* convert to index and check */
		index = (unsigned long) addr >> 3;
		if ((addr & 7) || (index > PT_FPSCR))
			break;

		if (index == PT_ORIG_R3)
			break;
		if (index < PT_FPR0) {
			ret = put_reg(child, index, data);
		} else {
			flush_fp_to_thread(child);
			((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data;
			ret = 0;
		}
		break;
	}

	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
	case PTRACE_CONT: { /* restart after signal. */
		ret = -EIO;
		if (!valid_signal(data))
			break;
		if (request == PTRACE_SYSCALL)
			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		else
			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		child->exit_code = data;
		/* make sure the single step bit is not set. */
		clear_single_step(child);
		wake_up_process(child);
		ret = 0;
		break;
	}

	/*
	 * make the child exit.  Best I can do is send it a sigkill.
	 * perhaps it should be put in the status that it wants to
	 * exit.
	 */
	case PTRACE_KILL: {
		ret = 0;
		if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
			break;
		child->exit_code = SIGKILL;
		/* make sure the single step bit is not set. */
		clear_single_step(child);
		wake_up_process(child);
		break;
	}

	case PTRACE_SINGLESTEP: {  /* set the trap flag. */
		ret = -EIO;
		if (!valid_signal(data))
			break;
		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		set_single_step(child);
		child->exit_code = data;
		/* give it a chance to run. */
		wake_up_process(child);
		ret = 0;
		break;
	}

	case PTRACE_DETACH:
		ret = ptrace_detach(child, data);
		break;

	case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
		int i;
		unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
		unsigned long __user *tmp = (unsigned long __user *)addr;

		for (i = 0; i < 32; i++) {
			ret = put_user(*reg, tmp);
			if (ret)
				break;
			reg++;
			tmp++;
		}
		break;
	}

	case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
		int i;
		unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
		unsigned long __user *tmp = (unsigned long __user *)addr;

		for (i = 0; i < 32; i++) {
			ret = get_user(*reg, tmp);
			if (ret)
				break;
			reg++;
			tmp++;
		}
		break;
	}

	case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
		int i;
		unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
		unsigned long __user *tmp = (unsigned long __user *)addr;

		flush_fp_to_thread(child);

		for (i = 0; i < 32; i++) {
			ret = put_user(*reg, tmp);
			if (ret)
				break;
			reg++;
			tmp++;
		}
		break;
	}

	case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
		int i;
		unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
		unsigned long __user *tmp = (unsigned long __user *)addr;

		flush_fp_to_thread(child);

		for (i = 0; i < 32; i++) {
			ret = get_user(*reg, tmp);
			if (ret)
				break;
			reg++;
			tmp++;
		}
		break;
	}

	default:
		ret = ptrace_request(child, request, addr, data);
		break;
	}
out_tsk:
	put_task_struct(child);
out:
	unlock_kernel();
	return ret;
}
/* tid is the actual task/thread id (née pid, stored as ->pid),
   pid/tgid is that 2.6 thread group id crap (stored as ->tgid) */
asmlinkage long sys_vperfctr_open(int tid, int creat)
{
	struct file *filp;
	struct task_struct *tsk;
	struct vperfctr *perfctr;
	int err;
	int fd;

	if (!vperfctr_fs_init_done())
		return -ENODEV;
	filp = vperfctr_get_filp();
	if (!filp)
		return -ENOMEM;
	err = fd = get_unused_fd();
	if (err < 0)
		goto err_filp;
	perfctr = NULL;
	if (creat) {
		perfctr = get_empty_vperfctr(); /* may sleep */
		if (IS_ERR(perfctr)) {
			err = PTR_ERR(perfctr);
			goto err_fd;
		}
	}
	tsk = current;

	if (tid != 0 && tid != tsk->pid) { /* remote? */
		// tasklist_lock is to access the linked list of task_struct structures exclusively
		read_lock(&tasklist_lock);
		//tsk = find_task_by_pid(tid);
		tsk = find_task_by_pid_ns(tid, current->nsproxy->pid_ns);
		if (tsk)
			get_task_struct(tsk);
		read_unlock(&tasklist_lock);
		err = -ESRCH;
		if (!tsk)
			goto err_perfctr;
		err = ptrace_check_attach(tsk, 0);
		if (err < 0)
			goto err_tsk;
	}
	if (creat) {
		/* check+install must be atomic to prevent remote-control races */
		task_lock(tsk);
		if (!tsk->thread.perfctr) {
			perfctr->owner = tsk;
			tsk->thread.perfctr = perfctr;
			err = 0;
		} else
			err = -EEXIST;
		task_unlock(tsk);
		if (err)
			goto err_tsk;
	} else {
		perfctr = tsk->thread.perfctr;
		/* XXX: Old API needed to allow NULL perfctr here.
		   Do we want to keep or change that rule? */
	}
	filp->private_data = perfctr;
	if (perfctr)
		atomic_inc(&perfctr->count);
	if (tsk != current)
		put_task_struct(tsk);
	#if 0
	if (perfctr) {
    	printk ("sys_vperfctr_open(): fd = %d, perfctr is NOT null\n", fd);
	}
	else {
    	printk ("sys_vperfctr_open(): fd = %d, perfctr is null\n", fd);
	}
	#endif
	fd_install(fd, filp);
	return fd;
 err_tsk:
	if (tsk != current)
		put_task_struct(tsk);
 err_perfctr:
	if (perfctr)	/* can only occur if creat != 0 */
		put_vperfctr(perfctr);
 err_fd:
	put_unused_fd(fd);
 err_filp:
	fput(filp);
	return err;
}
Exemple #5
0
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
{
	struct task_struct *child;
	int ret;

	lock_kernel();
	ret = -EPERM;
	if (request == PTRACE_TRACEME) {
		/* are we already being traced? */
		if (current->ptrace & PT_PTRACED)
			goto out;
		/* set the ptrace bit in the process flags. */
		current->ptrace |= PT_PTRACED;
		ret = 0;
		goto out;
	}
	ret = -ESRCH;
	read_lock(&tasklist_lock);
	child = find_task_by_pid(pid);
	if (child)
		get_task_struct(child);
	read_unlock(&tasklist_lock);
	if (!child)
		goto out;

	ret = -EPERM;
	if (pid == 1)		/* you may not mess with init */
		goto out_tsk;

	if (request == PTRACE_ATTACH) {
		ret = ptrace_attach(child);
		goto out_tsk;
	}
	ret = ptrace_check_attach(child, request == PTRACE_KILL);
	if (ret < 0)
		goto out_tsk;

	switch (request) {
		case PTRACE_PEEKTEXT: /* read word at location addr. */ 
		case PTRACE_PEEKDATA: {
			unsigned long tmp;

			ret = read_long(child, addr, &tmp);
			if (ret < 0)
				break ;
			ret = put_user(tmp, (unsigned long *) data);
			break ;
		}

	/* read the word at location addr in the USER area. */
		case PTRACE_PEEKUSR: {
			unsigned long tmp = 0;
			
			if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) {
				ret = -EIO;
				break ;
			}
			
		        ret = 0;  /* Default return condition */
			addr = addr >> 2; /* temporary hack. */

			if (addr < H8300_REGS_NO)
				tmp = h8300_get_reg(child, addr);
			else {
				switch(addr) {
				case 49:
					tmp = child->mm->start_code;
					break ;
				case 50:
					tmp = child->mm->start_data;
					break ;
				case 51:
					tmp = child->mm->end_code;
					break ;
				case 52:
					tmp = child->mm->end_data;
					break ;
				default:
					ret = -EIO;
				}
			}
			if (!ret)
				ret = put_user(tmp,(unsigned long *) data);
			break ;
		}

      /* when I and D space are separate, this will have to be fixed. */
		case PTRACE_POKETEXT: /* write the word at location addr. */
		case PTRACE_POKEDATA:
			ret = 0;
			if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
				break;
			ret = -EIO;
			break;

		case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
			if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) {
				ret = -EIO;
				break ;
			}
			addr = addr >> 2; /* temporary hack. */
			    
			if (addr == PT_ORIG_ER0) {
				ret = -EIO;
				break ;
			}
			if (addr < H8300_REGS_NO) {
				ret = h8300_put_reg(child, addr, data);
				break ;
			}
			ret = -EIO;
			break ;
		case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
		case PTRACE_CONT: { /* restart after signal. */
			ret = -EIO;
			if ((unsigned long) data >= _NSIG)
				break ;
			if (request == PTRACE_SYSCALL)
				set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
			else
				clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
			child->exit_code = data;
			wake_up_process(child);
			/* make sure the single step bit is not set. */
			h8300_disable_trace(child);
			ret = 0;
		}

/*
 * make the child exit.  Best I can do is send it a sigkill. 
 * perhaps it should be put in the status that it wants to 
 * exit.
 */
		case PTRACE_KILL: {

			ret = 0;
			if (child->exit_state == EXIT_ZOMBIE) /* already dead */
				break;
			child->exit_code = SIGKILL;
			h8300_disable_trace(child);
			wake_up_process(child);
			break;
		}

		case PTRACE_SINGLESTEP: {  /* set the trap flag. */
			ret = -EIO;
			if ((unsigned long) data > _NSIG)
				break;
			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
			child->exit_code = data;
			h8300_enable_trace(child);
			wake_up_process(child);
			ret = 0;
			break;
		}

		case PTRACE_DETACH:	/* detach a process that was attached. */
			ret = ptrace_detach(child, data);
			break;

		case PTRACE_GETREGS: { /* Get all gp regs from the child. */
		  	int i;
			unsigned long tmp;
			for (i = 0; i < H8300_REGS_NO; i++) {
			    tmp = h8300_get_reg(child, i);
			    if (put_user(tmp, (unsigned long *) data)) {
				ret = -EFAULT;
				break;
			    }
			    data += sizeof(long);
			}
			ret = 0;
			break;
		}

		case PTRACE_SETREGS: { /* Set all gp regs in the child. */
			int i;
			unsigned long tmp;
			for (i = 0; i < H8300_REGS_NO; i++) {
			    if (get_user(tmp, (unsigned long *) data)) {
				ret = -EFAULT;
				break;
			    }
			    h8300_put_reg(child, i, tmp);
			    data += sizeof(long);
			}
			ret = 0;
			break;
		}

		default:
			ret = -EIO;
			break;
	}
out_tsk:
	put_task_struct(child);
out:
	unlock_kernel();
	return ret;
}
Exemple #6
0
int sys_ptrace(long request, long pid, long addr, long data)
{
	struct task_struct *child;
	int ret = -EPERM;

	lock_kernel();
	if (request == PTRACE_TRACEME) {
		/* are we already being traced? */
		if (current->ptrace & PT_PTRACED)
			goto out;
		/* set the ptrace bit in the process flags. */
		current->ptrace |= PT_PTRACED;
		ret = 0;
		goto out;
	}
	ret = -ESRCH;
	read_lock(&tasklist_lock);
	child = find_task_by_pid(pid);
	if (child)
		get_task_struct(child);
	read_unlock(&tasklist_lock);
	if (!child)
		goto out;

	ret = -EPERM;
	if (pid == 1)		/* you may not mess with init */
		goto out_tsk;

	if (request == PTRACE_ATTACH) {
		ret = ptrace_attach(child);
		goto out_tsk;
	}

	ret = ptrace_check_attach(child, request == PTRACE_KILL);
	if (ret < 0)
		goto out_tsk;

	switch (request) {
	/* when I and D space are separate, these will need to be fixed. */
	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
	case PTRACE_PEEKDATA: {
		unsigned long tmp;
		int copied;

		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
		ret = -EIO;
		if (copied != sizeof(tmp))
			break;
		ret = put_user(tmp,(unsigned long *) data);
		break;
	}

	/* read the word at location addr in the USER area. */
	/* XXX this will need fixing for 64-bit */
	case PTRACE_PEEKUSR: {
		unsigned long index, tmp;

		ret = -EIO;
		/* convert to index and check */
		index = (unsigned long) addr >> 2;
		if ((addr & 3) || index > PT_FPSCR)
			break;

		if (index < PT_FPR0) {
			tmp = get_reg(child, (int) index);
		} else {
			if (child->thread.regs != NULL
			    && child->thread.regs->msr & MSR_FP)
				giveup_fpu(child);
			tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0];
		}
		ret = put_user(tmp,(unsigned long *) data);
		break;
	}

	/* If I and D space are separate, this will have to be fixed. */
	case PTRACE_POKETEXT: /* write the word at location addr. */
	case PTRACE_POKEDATA:
		ret = 0;
		if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
			break;
		ret = -EIO;
		break;

	/* write the word at location addr in the USER area */
	/* XXX this will need fixing for 64-bit */
	case PTRACE_POKEUSR: {
		unsigned long index;

		ret = -EIO;
		/* convert to index and check */
		index = (unsigned long) addr >> 2;
		if ((addr & 3) || index > PT_FPSCR)
			break;

		if (index == PT_ORIG_R3)
			break;
		if (index < PT_FPR0) {
			ret = put_reg(child, index, data);
		} else {
			if (child->thread.regs != NULL
			    && child->thread.regs->msr & MSR_FP)
				giveup_fpu(child);
			((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data;
			ret = 0;
		}
		break;
	}

	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
	case PTRACE_CONT: { /* restart after signal. */
		ret = -EIO;
		if ((unsigned long) data > _NSIG)
			break;
		if (request == PTRACE_SYSCALL)
			child->ptrace |= PT_TRACESYS;
		else
			child->ptrace &= ~PT_TRACESYS;
		child->exit_code = data;
		/* make sure the single step bit is not set. */
		clear_single_step(child);
		wake_up_process(child);
		ret = 0;
		break;
	}

/*
 * make the child exit.  Best I can do is send it a sigkill. 
 * perhaps it should be put in the status that it wants to 
 * exit.
 */
	case PTRACE_KILL: {
		ret = 0;
		if (child->state == TASK_ZOMBIE)	/* already dead */
			break;
		child->exit_code = SIGKILL;
		/* make sure the single step bit is not set. */
		clear_single_step(child);
		wake_up_process(child);
		break;
	}

	case PTRACE_SINGLESTEP: {  /* set the trap flag. */
		ret = -EIO;
		if ((unsigned long) data > _NSIG)
			break;
		child->ptrace &= ~PT_TRACESYS;
		set_single_step(child);
		child->exit_code = data;
		/* give it a chance to run. */
		wake_up_process(child);
		ret = 0;
		break;
	}

	case PTRACE_DETACH:
		ret = ptrace_detach(child, data);
		break;

#ifdef CONFIG_ALTIVEC
	case PTRACE_GETVRREGS:
		/* Get the child altivec register state. */
		if (child->thread.regs->msr & MSR_VEC)
			giveup_altivec(child);
		ret = get_vrregs((unsigned long *)data, child);
		break;

	case PTRACE_SETVRREGS:
		/* Set the child altivec register state. */
		/* this is to clear the MSR_VEC bit to force a reload
		 * of register state from memory */
		if (child->thread.regs->msr & MSR_VEC)
			giveup_altivec(child);
		ret = set_vrregs(child, (unsigned long *)data);
		break;
#endif

	default:
		ret = -EIO;
		break;
	}
out_tsk:
	free_task_struct(child);
out:
	unlock_kernel();
	return ret;
}
Exemple #7
0
/* tid is the actual task/thread id (née pid, stored as ->pid),
   pid/tgid is that 2.6 thread group id crap (stored as ->tgid) */
int vperfctr_attach(int tid, int creat)
{
	struct file *filp;
	struct task_struct *tsk;
	struct vperfctr *perfctr;
	int err;
	int fd;

	filp = vperfctr_get_filp();
	if (!filp)
		return -ENOMEM;
	err = fd = get_unused_fd();
	if (err < 0)
		goto err_filp;
	perfctr = NULL;
	if (creat) {
		perfctr = get_empty_vperfctr(); /* may sleep */
		if (IS_ERR(perfctr)) {
			err = PTR_ERR(perfctr);
			goto err_fd;
		}
	}
	tsk = current;
	if (tid != 0 && tid != task_pid_vnr(tsk)) { /* remote? */
		vperfctr_lock_find_task_by_vpid();
		tsk = find_task_by_vpid(tid);
		if (tsk)
			get_task_struct(tsk);
		vperfctr_unlock_find_task_by_vpid();
		err = -ESRCH;
		if (!tsk)
			goto err_perfctr;
		err = ptrace_check_attach(tsk, 0);
		if (err < 0)
			goto err_tsk;
	}
	if (creat) {
		/* check+install must be atomic to prevent remote-control races */
		vperfctr_task_lock(tsk);
		if (!tsk->thread.perfctr) {
			perfctr->owner = tsk;
			tsk->thread.perfctr = perfctr;
			err = 0;
		} else
			err = -EEXIST;
		vperfctr_task_unlock(tsk);
		if (err)
			goto err_tsk;
	} else {
		perfctr = tsk->thread.perfctr;
		/* PERFCTR_ABI and PERFCTR_INFO don't need the perfctr.
		   Hence no non-NULL check here. */
	}
	filp->private_data = perfctr;
	if (perfctr)
		atomic_inc(&perfctr->count);
	if (tsk != current)
		put_task_struct(tsk);
	fd_install(fd, filp);
	return fd;
 err_tsk:
	if (tsk != current)
		put_task_struct(tsk);
 err_perfctr:
	if (perfctr)	/* can only occur if creat != 0 */
		put_vperfctr(perfctr);
 err_fd:
	put_unused_fd(fd);
 err_filp:
	fput(filp);
	return err;
}
Exemple #8
0
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
{
	struct task_struct *child;
	unsigned long tmp;
	int ret;

	lock_kernel();
	ret = -EPERM;
	if (request == PTRACE_TRACEME) {
		/* are we already being traced? */
		if (current->ptrace & PT_PTRACED)
			goto out;
		ret = security_ptrace(current->parent, current);
		if (ret)
			goto out;
		/* set the ptrace bit in the process flags. */
		current->ptrace |= PT_PTRACED;
		ret = 0;
		goto out;
	}
	ret = -ESRCH;
	read_lock(&tasklist_lock);
	child = find_task_by_pid(pid);
	if (child)
		get_task_struct(child);
	read_unlock(&tasklist_lock);
	if (!child)
		goto out;

	ret = -EPERM;
	if (pid == 1)		/* you may not mess with init */
		goto out_tsk;

	if (request == PTRACE_ATTACH) {
		ret = ptrace_attach(child);
		goto out_tsk;
	}

	ret = ptrace_check_attach(child, request == PTRACE_KILL);
	if (ret < 0)
		goto out_tsk;

	switch (request) {
		/* when I and D space are separate, these will need to be fixed. */
	case PTRACE_PEEKTEXT: /* read word at location addr. */
	case PTRACE_PEEKDATA: {
		int copied;

		ret = -EIO;
		if (is_user_addr_valid(child, addr, sizeof(tmp)) < 0)
			break;

		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
		if (copied != sizeof(tmp))
			break;

		ret = put_user(tmp,(unsigned long *) data);
		break;
	}

		/* read the word at location addr in the USER area. */
	case PTRACE_PEEKUSR: {
		tmp = 0;
		ret = -EIO;
		if ((addr & 3) || addr < 0)
			break;

		ret = 0;
		switch (addr >> 2) {
		case 0 ... PT__END - 1:
			tmp = get_reg(child, addr >> 2);
			break;

		case PT__END + 0:
			tmp = child->mm->end_code - child->mm->start_code;
			break;

		case PT__END + 1:
			tmp = child->mm->end_data - child->mm->start_data;
			break;

		case PT__END + 2:
			tmp = child->mm->start_stack - child->mm->start_brk;
			break;

		case PT__END + 3:
			tmp = child->mm->start_code;
			break;

		case PT__END + 4:
			tmp = child->mm->start_stack;
			break;

		default:
			ret = -EIO;
			break;
		}

		if (ret == 0)
			ret = put_user(tmp, (unsigned long *) data);
		break;
	}

		/* when I and D space are separate, this will have to be fixed. */
	case PTRACE_POKETEXT: /* write the word at location addr. */
	case PTRACE_POKEDATA:
		ret = -EIO;
		if (is_user_addr_valid(child, addr, sizeof(tmp)) < 0)
			break;
		if (access_process_vm(child, addr, &data, sizeof(data), 1) != sizeof(data))
			break;
		ret = 0;
		break;

	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
		ret = -EIO;
		if ((addr & 3) || addr < 0)
			break;

		ret = 0;
		switch (addr >> 2) {
		case 0 ... PT__END-1:
			ret = put_reg(child, addr >> 2, data);
			break;

		default:
			ret = -EIO;
			break;
		}
		break;

	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
	case PTRACE_CONT: /* restart after signal. */
		ret = -EIO;
		if (!valid_signal(data))
			break;
		if (request == PTRACE_SYSCALL)
			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		else
			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		child->exit_code = data;
		ptrace_disable(child);
		wake_up_process(child);
		ret = 0;
		break;

		/* make the child exit.  Best I can do is send it a sigkill.
		 * perhaps it should be put in the status that it wants to
		 * exit.
		 */
	case PTRACE_KILL:
		ret = 0;
		if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
			break;
		child->exit_code = SIGKILL;
		clear_tsk_thread_flag(child, TIF_SINGLESTEP);
		ptrace_disable(child);
		wake_up_process(child);
		break;

	case PTRACE_SINGLESTEP:  /* set the trap flag. */
		ret = -EIO;
		if (!valid_signal(data))
			break;
		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		ptrace_enable(child);
		child->exit_code = data;
		wake_up_process(child);
		ret = 0;
		break;

	case PTRACE_DETACH:	/* detach a process that was attached. */
		ret = ptrace_detach(child, data);
		break;

	case PTRACE_GETREGS: { /* Get all integer regs from the child. */
		int i;
		for (i = 0; i < PT__GPEND; i++) {
			tmp = get_reg(child, i);
			if (put_user(tmp, (unsigned long *) data)) {
				ret = -EFAULT;
				break;
			}
			data += sizeof(long);
		}
		ret = 0;
		break;
	}

	case PTRACE_SETREGS: { /* Set all integer regs in the child. */
		int i;
		for (i = 0; i < PT__GPEND; i++) {
			if (get_user(tmp, (unsigned long *) data)) {
				ret = -EFAULT;
				break;
			}
			put_reg(child, i, tmp);
			data += sizeof(long);
		}
		ret = 0;
		break;
	}

	case PTRACE_GETFPREGS: { /* Get the child FP/Media state. */
		ret = 0;
		if (copy_to_user((void *) data,
				 &child->thread.user->f,
				 sizeof(child->thread.user->f)))
			ret = -EFAULT;
		break;
	}

	case PTRACE_SETFPREGS: { /* Set the child FP/Media state. */
		ret = 0;
		if (copy_from_user(&child->thread.user->f,
				   (void *) data,
				   sizeof(child->thread.user->f)))
			ret = -EFAULT;
		break;
	}

	case PTRACE_GETFDPIC:
		tmp = 0;
		switch (addr) {
		case PTRACE_GETFDPIC_EXEC:
			tmp = child->mm->context.exec_fdpic_loadmap;
			break;
		case PTRACE_GETFDPIC_INTERP:
			tmp = child->mm->context.interp_fdpic_loadmap;
			break;
		default:
			break;
		}

		ret = 0;
		if (put_user(tmp, (unsigned long *) data)) {
			ret = -EFAULT;
			break;
		}
		break;

	default:
		ret = -EIO;
		break;
	}
out_tsk:
	put_task_struct(child);
out:
	unlock_kernel();
	return ret;
}
Exemple #9
0
long sys_ptrace(long request, long pid, long addr, long data)
{
    struct task_struct *child;
    int i, ret;

    lock_kernel();
    ret = -EPERM;
    if (request == PTRACE_TRACEME) {
        /* are we already being traced? */
        if (current->ptrace & PT_PTRACED)
            goto out;

        ret = security_ptrace(current->parent, current);
        if (ret)
            goto out;

        /* set the ptrace bit in the process flags. */
        current->ptrace |= PT_PTRACED;
        ret = 0;
        goto out;
    }
    ret = -ESRCH;
    read_lock(&tasklist_lock);
    child = find_task_by_pid(pid);
    if (child)
        get_task_struct(child);
    read_unlock(&tasklist_lock);
    if (!child)
        goto out;

    ret = -EPERM;
    if (pid == 1)		/* you may not mess with init */
        goto out_tsk;

    if (request == PTRACE_ATTACH) {
        ret = ptrace_attach(child);
        goto out_tsk;
    }

#ifdef SUBACH_PTRACE_SPECIAL
    SUBARCH_PTRACE_SPECIAL(child,request,addr,data);
#endif

    ret = ptrace_check_attach(child, request == PTRACE_KILL);
    if (ret < 0)
        goto out_tsk;

    switch (request) {
    /* when I and D space are separate, these will need to be fixed. */
    case PTRACE_PEEKTEXT: /* read word at location addr. */
    case PTRACE_PEEKDATA: {
        unsigned long tmp;
        int copied;

        ret = -EIO;
        copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
        if (copied != sizeof(tmp))
            break;
        ret = put_user(tmp, (unsigned long __user *) data);
        break;
    }

    /* read the word at location addr in the USER area. */
    case PTRACE_PEEKUSR:
        ret = peek_user(child, addr, data);
        break;

    /* when I and D space are separate, this will have to be fixed. */
    case PTRACE_POKETEXT: /* write the word at location addr. */
    case PTRACE_POKEDATA:
        ret = -EIO;
        if (access_process_vm(child, addr, &data, sizeof(data),
                              1) != sizeof(data))
            break;
        ret = 0;
        break;

    case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
        ret = poke_user(child, addr, data);
        break;

    case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
    case PTRACE_CONT: { /* restart after signal. */
        ret = -EIO;
        if (!valid_signal(data))
            break;

        set_singlestepping(child, 0);
        if (request == PTRACE_SYSCALL) {
            set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
        }
        else {
            clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
        }
        child->exit_code = data;
        wake_up_process(child);
        ret = 0;
        break;
    }

    /*
     * make the child exit.  Best I can do is send it a sigkill.
     * perhaps it should be put in the status that it wants to
     * exit.
     */
    case PTRACE_KILL: {
        ret = 0;
        if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
            break;

        set_singlestepping(child, 0);
        child->exit_code = SIGKILL;
        wake_up_process(child);
        break;
    }

    case PTRACE_SINGLESTEP: {  /* set the trap flag. */
        ret = -EIO;
        if (!valid_signal(data))
            break;
        clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
        set_singlestepping(child, 1);
        child->exit_code = data;
        /* give it a chance to run. */
        wake_up_process(child);
        ret = 0;
        break;
    }

    case PTRACE_DETACH:
        /* detach a process that was attached. */
        ret = ptrace_detach(child, data);
        break;

#ifdef PTRACE_GETREGS
    case PTRACE_GETREGS: { /* Get all gp regs from the child. */
        if (!access_ok(VERIFY_WRITE, (unsigned long *)data,
                       MAX_REG_OFFSET)) {
            ret = -EIO;
            break;
        }
        for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
            __put_user(getreg(child, i),
                       (unsigned long __user *) data);
            data += sizeof(long);
        }
        ret = 0;
        break;
    }
#endif
#ifdef PTRACE_SETREGS
    case PTRACE_SETREGS: { /* Set all gp regs in the child. */
        unsigned long tmp = 0;
        if (!access_ok(VERIFY_READ, (unsigned *)data,
                       MAX_REG_OFFSET)) {
            ret = -EIO;
            break;
        }
        for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
            __get_user(tmp, (unsigned long __user *) data);
            putreg(child, i, tmp);
            data += sizeof(long);
        }
        ret = 0;
        break;
    }
#endif
#ifdef PTRACE_GETFPREGS
    case PTRACE_GETFPREGS: /* Get the child FPU state. */
        ret = get_fpregs(data, child);
        break;
#endif
#ifdef PTRACE_SETFPREGS
    case PTRACE_SETFPREGS: /* Set the child FPU state. */
        ret = set_fpregs(data, child);
        break;
#endif
#ifdef PTRACE_GETFPXREGS
    case PTRACE_GETFPXREGS: /* Get the child FPU state. */
        ret = get_fpxregs(data, child);
        break;
#endif
#ifdef PTRACE_SETFPXREGS
    case PTRACE_SETFPXREGS: /* Set the child FPU state. */
        ret = set_fpxregs(data, child);
        break;
#endif
    case PTRACE_FAULTINFO: {
        /* Take the info from thread->arch->faultinfo,
         * but transfer max. sizeof(struct ptrace_faultinfo).
         * On i386, ptrace_faultinfo is smaller!
         */
        ret = copy_to_user((unsigned long __user *) data,
                           &child->thread.arch.faultinfo,
                           sizeof(struct ptrace_faultinfo));
        if(ret)
            break;
        break;
    }

#ifdef PTRACE_LDT
    case PTRACE_LDT: {
        struct ptrace_ldt ldt;

        if(copy_from_user(&ldt, (unsigned long __user *) data,
                          sizeof(ldt))) {
            ret = -EIO;
            break;
        }

        /* This one is confusing, so just punt and return -EIO for
         * now
         */
        ret = -EIO;
        break;
    }
#endif
#ifdef CONFIG_PROC_MM
    case PTRACE_SWITCH_MM: {
        struct mm_struct *old = child->mm;
        struct mm_struct *new = proc_mm_get_mm(data);

        if(IS_ERR(new)) {
            ret = PTR_ERR(new);
            break;
        }

        atomic_inc(&new->mm_users);
        child->mm = new;
        child->active_mm = new;
        mmput(old);
        ret = 0;
        break;
    }
#endif
    default:
        ret = ptrace_request(child, request, addr, data);
        break;
    }
out_tsk:
    put_task_struct(child);
out:
    unlock_kernel();
    return ret;
}