patch-2.1.23 linux/arch/i386/kernel/ptrace.c
Next file: linux/arch/i386/kernel/signal.c
Previous file: linux/arch/i386/kernel/process.c
Back to the patch index
Back to the overall index
- Lines: 269
- Date:
Sun Jan 26 12:07:04 1997
- Orig file:
v2.1.22/linux/arch/i386/kernel/ptrace.c
- Orig date:
Thu Jan 2 15:55:15 1997
diff -u --recursive --new-file v2.1.22/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c
@@ -6,6 +6,8 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/user.h>
@@ -362,26 +364,29 @@
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
{
struct task_struct *child;
- struct user * dummy;
- int i;
-
- dummy = NULL;
+ struct user * dummy = NULL;
+ int i, ret;
+ lock_kernel();
+ ret = -EPERM;
if (request == PTRACE_TRACEME) {
/* are we already being traced? */
if (current->flags & PF_PTRACED)
- return -EPERM;
+ goto out;
/* set the ptrace bit in the process flags. */
current->flags |= PF_PTRACED;
- return 0;
+ ret = 0;
+ goto out;
}
if (pid == 1) /* you may not mess with init */
- return -EPERM;
+ goto out;
+ ret = -ESRCH;
if (!(child = get_task(pid)))
- return -ESRCH;
+ goto out;
+ ret = -EPERM;
if (request == PTRACE_ATTACH) {
if (child == current)
- return -EPERM;
+ goto out;
if ((!child->dumpable ||
(current->uid != child->euid) ||
(current->uid != child->suid) ||
@@ -389,10 +394,10 @@
(current->gid != child->egid) ||
(current->gid != child->sgid) ||
(current->gid != child->gid)) && !suser())
- return -EPERM;
+ goto out;
/* the same process cannot be attached many times */
if (child->flags & PF_PTRACED)
- return -EPERM;
+ goto out;
child->flags |= PF_PTRACED;
if (child->p_pptr != current) {
REMOVE_LINKS(child);
@@ -400,37 +405,39 @@
SET_LINKS(child);
}
send_sig(SIGSTOP, child, 1);
- return 0;
+ ret = 0;
+ goto out;
}
+ ret = -ESRCH;
if (!(child->flags & PF_PTRACED))
- return -ESRCH;
+ goto out;
if (child->state != TASK_STOPPED) {
if (request != PTRACE_KILL)
- return -ESRCH;
+ goto out;
}
if (child->p_pptr != current)
- return -ESRCH;
+ goto out;
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 res;
- res = read_long(child, addr, &tmp);
- if (res < 0)
- return res;
- return put_user(tmp,(unsigned long *) data);
+ ret = read_long(child, addr, &tmp);
+ if (ret >= 0)
+ ret = put_user(tmp,(unsigned long *) data);
+ goto out;
}
/* read the word at location addr in the USER area. */
case PTRACE_PEEKUSR: {
unsigned long tmp;
+ ret = -EIO;
if ((addr & 3) || addr < 0 ||
addr > sizeof(struct user) - 3)
- return -EIO;
+ goto out;
tmp = 0; /* Default return condition */
if(addr < 17*sizeof(long))
@@ -441,21 +448,26 @@
addr = addr >> 2;
tmp = child->debugreg[addr];
};
- return put_user(tmp,(unsigned long *) data);
+ ret = put_user(tmp,(unsigned long *) data);
+ goto out;
}
/* 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:
- return write_long(child,addr,data);
+ ret = write_long(child,addr,data);
+ goto out;
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
+ ret = -EIO;
if ((addr & 3) || addr < 0 ||
addr > sizeof(struct user) - 3)
- return -EIO;
+ goto out;
- if (addr < 17*sizeof(long))
- return putreg(child, addr, data);
+ if (addr < 17*sizeof(long)) {
+ ret = putreg(child, addr, data);
+ goto out;
+ }
/* We need to be very careful here. We implicitly
want to modify a portion of the task_struct, and we
@@ -470,26 +482,30 @@
if(addr < (long) &dummy->u_debugreg[4] &&
((unsigned long) data) >= 0xbffffffd) return -EIO;
+ ret = -EIO;
if(addr == (long) &dummy->u_debugreg[7]) {
data &= ~DR_CONTROL_RESERVED;
for(i=0; i<4; i++)
if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
- return -EIO;
+ goto out;
};
addr -= (long) &dummy->u_debugreg;
addr = addr >> 2;
child->debugreg[addr] = data;
- return 0;
+ ret = 0;
+ goto out;
};
- return -EIO;
+ ret = -EIO;
+ goto out;
case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
case PTRACE_CONT: { /* restart after signal. */
long tmp;
+ ret = -EIO;
if ((unsigned long) data > NSIG)
- return -EIO;
+ goto out;
if (request == PTRACE_SYSCALL)
child->flags |= PF_TRACESYS;
else
@@ -499,7 +515,8 @@
/* make sure the single step bit is not set. */
tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
put_stack_long(child, EFL_OFFSET,tmp);
- return 0;
+ ret = 0;
+ goto out;
}
/*
@@ -510,35 +527,39 @@
case PTRACE_KILL: {
long tmp;
+ ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */
- return 0;
+ goto out;
wake_up_process(child);
child->exit_code = SIGKILL;
/* make sure the single step bit is not set. */
tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
put_stack_long(child, EFL_OFFSET, tmp);
- return 0;
+ goto out;
}
case PTRACE_SINGLESTEP: { /* set the trap flag. */
long tmp;
+ ret = -EIO;
if ((unsigned long) data > NSIG)
- return -EIO;
+ goto out;
child->flags &= ~PF_TRACESYS;
tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG;
put_stack_long(child, EFL_OFFSET, tmp);
wake_up_process(child);
child->exit_code = data;
/* give it a chance to run. */
- return 0;
+ ret = 0;
+ goto out;
}
case PTRACE_DETACH: { /* detach a process that was attached. */
long tmp;
+ ret = -EIO;
if ((unsigned long) data > NSIG)
- return -EIO;
+ goto out;
child->flags &= ~(PF_PTRACED|PF_TRACESYS);
wake_up_process(child);
child->exit_code = data;
@@ -548,19 +569,25 @@
/* make sure the single step bit is not set. */
tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
put_stack_long(child, EFL_OFFSET, tmp);
- return 0;
+ ret = 0;
+ goto out;
}
default:
- return -EIO;
+ ret = -EIO;
+ goto out;
}
+out:
+ unlock_kernel();
+ return ret;
}
asmlinkage void syscall_trace(void)
{
+ lock_kernel();
if ((current->flags & (PF_PTRACED|PF_TRACESYS))
!= (PF_PTRACED|PF_TRACESYS))
- return;
+ goto out;
current->exit_code = SIGTRAP;
current->state = TASK_STOPPED;
notify_parent(current);
@@ -573,4 +600,6 @@
if (current->exit_code)
current->signal |= (1 << (current->exit_code - 1));
current->exit_code = 0;
+out:
+ unlock_kernel();
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov