int do_setsid(struct ptrace_child *child) { int err = 0; struct ptrace_child dummy; err = do_fork(child); if (err < 0) return err; debug("Forked a child: %ld", child->forked_pid); err = ptrace_finish_attach(&dummy, child->forked_pid); if (err < 0) goto out_kill; dummy.state = ptrace_after_syscall; copy_user(&dummy, child); if (ptrace_restore_regs(&dummy)) { err = dummy.error; goto out_kill; } err = do_syscall(&dummy, setpgid, 0, 0, 0, 0, 0, 0); if (err < 0) { error("Failed to setpgid: %s", strerror(-err)); goto out_kill; } move_process_group(child, child->pid, dummy.pid); err = do_syscall(child, setsid, 0, 0, 0, 0, 0, 0); if (err < 0) { error("Failed to setsid: %s", strerror(-err)); move_process_group(child, dummy.pid, child->pid); goto out_kill; } debug("Did setsid()"); out_kill: kill(dummy.pid, SIGKILL); ptrace_wait(&dummy); ptrace_detach_child(&dummy); do_syscall(child, wait4, dummy.pid, 0, WNOHANG, 0, 0, 0); return err; }
asmlinkage int sys32_ptrace(long request, long pid, long addr, s32 data) { struct task_struct *child; int ret = -EPERM; unsigned long flags; u32 tmp; int copied; ptrace_area parea; 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); read_unlock(&tasklist_lock); if (!child) goto out; ret = -EPERM; if (pid == 1) /* you may not mess with init */ goto out; if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); goto out; } ret = -ESRCH; // printk("child=%lX child->flags=%lX",child,child->flags); /* I added child!=current line so we can get the */ /* ieee_instruction_pointer from the user structure DJB */ if(child!=current) { if (!(child->ptrace & PT_PTRACED)) goto out; if (child->state != TASK_STOPPED) { if (request != PTRACE_KILL) goto out; } if (child->p_pptr != current) goto out; } switch (request) { /* If I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); ret = -EIO; if (copied != sizeof(tmp)) goto out; ret = put_user(tmp,(u32 *)(unsigned long)data); goto out; /* read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: ret=copy_user(child,addr,data,sizeof(u32),1,0); 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)) goto out; ret = -EIO; goto out; break; case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ ret=copy_user(child,addr,(addr_t)&data,sizeof(u32),0,1); 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; clear_single_step(child); wake_up_process(child); /* make sure the single step bit is not set. */ break; case PTRACE_SINGLESTEP: /* set the trap flag. */ ret = -EIO; if ((unsigned long) data >= _NSIG) break; child->ptrace &= ~PT_TRACESYS; child->exit_code = data; set_single_step(child); /* give it a chance to run. */ wake_up_process(child); ret = 0; break; case PTRACE_DETACH: /* detach a process that was attached. */ ret = -EIO; if ((unsigned long) data >= _NSIG) break; child->ptrace &= ~(PT_PTRACED|PT_TRACESYS); child->exit_code = data; write_lock_irqsave(&tasklist_lock, flags); REMOVE_LINKS(child); child->p_pptr = child->p_opptr; SET_LINKS(child); write_unlock_irqrestore(&tasklist_lock, flags); /* make sure the single step bit is not set. */ clear_single_step(child); wake_up_process(child); ret = 0; break; case PTRACE_PEEKUSR_AREA: case PTRACE_POKEUSR_AREA: { ptrace_area_emu31 * parea31 = (void *)addr; if (!access_ok(VERIFY_READ, parea31, sizeof(*parea31))) return(-EFAULT); ret = __get_user(parea.len, &parea31->len); ret |= __get_user(parea.kernel_addr, &parea31->kernel_addr); ret |= __get_user(parea.process_addr, &parea31->process_addr); if(ret==0) ret=copy_user(child,parea.kernel_addr,parea.process_addr, parea.len,1,(request==PTRACE_POKEUSR_AREA)); break; } default: ret = -EIO; break; } out: unlock_kernel(); return ret; }