X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/0b4e3aa066abc0728aacb4bbeb86f53f9737156e..6601e61aa18bf4f09af135ff61fc7f4771d23b06:/bsd/kern/mach_process.c diff --git a/bsd/kern/mach_process.c b/bsd/kern/mach_process.c index db317e75a..caa043027 100644 --- a/bsd/kern/mach_process.c +++ b/bsd/kern/mach_process.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -59,19 +59,14 @@ * * from: @(#)sys_process.c 8.1 (Berkeley) 6/10/93 */ -/* - * HISTORY - * - * 10-Jun-97 Umesh Vaishampayan (umeshv@apple.com) - * Ported to PPC. Cleaned up the architecture specific code. - */ #include #include #include #include -#include +#include +#include #include #include #include @@ -79,27 +74,33 @@ #include #include -#include +#include +#include + +#include #include #include #include + /* Macros to clear/set/test flags. */ #define SET(t, f) (t) |= (f) #define CLR(t, f) (t) &= ~(f) #define ISSET(t, f) ((t) & (f)) -void psignal_lock __P((struct proc *, int, int, int)); +extern thread_t port_name_to_thread(mach_port_name_t port_name); +extern kern_return_t thread_getstatus(thread_t thread, int flavor, thread_state_t tstate, mach_msg_type_number_t *count); +extern thread_t get_firstthread(task_t); + +#if defined (ppc) +extern kern_return_t thread_setstatus(thread_t thread, int flavor, thread_state_t tstate, mach_msg_type_number_t count); +#endif + /* * sys-trace system call. */ -struct ptrace_args { - int req; - pid_t pid; - caddr_t addr; - int data; -}; + int ptrace(p, uap, retval) struct proc *p; @@ -107,39 +108,46 @@ ptrace(p, uap, retval) register_t *retval; { struct proc *t = current_proc(); /* target process */ - vm_offset_t start_addr, end_addr, - kern_addr, offset; - vm_size_t size; - boolean_t change_protection; task_t task; - thread_t thread; - thread_act_t th_act; + thread_t th_act; struct uthread *ut; int *locr0; - int error = 0; #if defined(ppc) - struct ppc_saved_state statep; + struct ppc_thread_state64 statep; #elif defined(i386) struct i386_saved_state statep; #else #error architecture not supported #endif unsigned long state_count; - - - if (uap->req == PT_DENY_ATTACH) { - if (ISSET(p->p_flag, P_TRACED)) { - exit1(p, W_EXITCODE(ENOTSUP, 0), retval); - /* drop funnel befewo we return */ - thread_funnel_set(kernel_flock, FALSE); - thread_exception_return(); - /* NOTREACHED */ - } + int tr_sigexc = 0; + + AUDIT_ARG(cmd, uap->req); + AUDIT_ARG(pid, uap->pid); + AUDIT_ARG(addr, uap->addr); + AUDIT_ARG(value, uap->data); + + if (uap->req == PT_DENY_ATTACH) { + if (ISSET(p->p_flag, P_TRACED)) { + exit1(p, W_EXITCODE(ENOTSUP, 0), retval); + /* drop funnel before we return */ + thread_funnel_set(kernel_flock, FALSE); + thread_exception_return(); + /* NOTREACHED */ + } SET(p->p_flag, P_NOATTACH); return(0); } + if (uap->req == PT_FORCEQUOTA) { + if (is_suser()) { + SET(t->p_flag, P_FORCEQUOTA); + return (0); + } else + return (EPERM); + } + /* * Intercept and deal with "please trace me" request. */ @@ -149,6 +157,13 @@ ptrace(p, uap, retval) t->p_oppid = t->p_pptr->p_pid; return(0); } + if (uap->req == PT_SIGEXC) { + if (ISSET(p->p_flag, P_TRACED)) { + SET(p->p_flag, P_SIGEXC); + return(0); + } else + return(EINVAL); + } /* * Locate victim, and make sure it is traceable. @@ -156,6 +171,7 @@ ptrace(p, uap, retval) if ((t = pfind(uap->pid)) == NULL) return (ESRCH); + AUDIT_ARG(process, t); /* We do not want ptrace to do anything with kernel, init * and mach_init @@ -164,47 +180,40 @@ ptrace(p, uap, retval) return (EPERM); task = t->task; + if (uap->req == PT_ATTACHEXC) { + uap->req = PT_ATTACH; + tr_sigexc = 1; + } if (uap->req == PT_ATTACH) { - - /* - * You can't attach to a process if: - * (1) it's the process that's doing the attaching, - */ - if (t->p_pid == p->p_pid) - return (EINVAL); - - /* - * (2) it's already being traced, or - */ - if (ISSET(t->p_flag, P_TRACED)) - return (EBUSY); - - /* - * (3) it's not owned by you, or is set-id on exec - * (unless you're root). - */ - if ((t->p_cred->p_ruid != p->p_cred->p_ruid || - ISSET(t->p_flag, P_SUGID)) && - (error = suser(p->p_ucred, &p->p_acflag)) != 0) - return (error); - - if (ISSET(t->p_flag, P_NOATTACH)) { - psignal(p, SIGSEGV); - return (EBUSY); + int err; + + if ( kauth_authorize_process(proc_ucred(p), KAUTH_PROCESS_CANTRACE, + t, (uintptr_t)&err, 0, 0) == 0 ) { + /* it's OK to attach */ + SET(t->p_flag, P_TRACED); + if (tr_sigexc) + SET(t->p_flag, P_SIGEXC); + + t->p_oppid = t->p_pptr->p_pid; + if (t->p_pptr != p) + proc_reparent(t, p); + + if (get_task_userstop(task) == 0 ) { + t->p_xstat = 0; + psignal(t, SIGSTOP); + } else { + t->p_xstat = SIGSTOP; + task_resume(task); + } + return(0); } - SET(t->p_flag, P_TRACED); - t->p_oppid = t->p_pptr->p_pid; - if (t->p_pptr != p) - proc_reparent(t, p); - - if (get_task_userstop(task) == 0 ) { - t->p_xstat = 0; - psignal(t, SIGSTOP); - } else { - t->p_xstat = SIGSTOP; - task_resume(task); + else { + /* not allowed to attach, proper error code returned by kauth_authorize_process */ + if (ISSET(t->p_flag, P_NOATTACH)) { + psignal(p, SIGSEGV); + } + return (err); } - return(0); } /* @@ -242,6 +251,7 @@ ptrace(p, uap, retval) t->p_oppid = 0; CLR(t->p_flag, P_TRACED); + CLR(t->p_flag, P_SIGEXC); goto resume; case PT_KILL: @@ -249,30 +259,30 @@ ptrace(p, uap, retval) * Tell child process to kill itself after it * is resumed by adding NSIG to p_cursig. [see issig] */ - psignal_lock(t, SIGKILL, 0, 0); + psignal_lock(t, SIGKILL, 0); goto resume; case PT_STEP: /* single step the child */ case PT_CONTINUE: /* continue the child */ - th_act = (thread_act_t)get_firstthread(task); + th_act = (thread_t)get_firstthread(task); if (th_act == THREAD_NULL) goto errorLabel; ut = (uthread_t)get_bsdthread_info(th_act); locr0 = ut->uu_ar0; #if defined(i386) state_count = i386_NEW_THREAD_STATE_COUNT; - if (act_machine_get_state(th_act, i386_NEW_THREAD_STATE, &statep, &state_count) != KERN_SUCCESS) { + if (thread_getstatus(th_act, i386_NEW_THREAD_STATE, &statep, &state_count) != KERN_SUCCESS) { goto errorLabel; } #elif defined(ppc) - state_count = PPC_THREAD_STATE_COUNT; - if (act_machine_get_state(th_act, PPC_THREAD_STATE, &statep, &state_count) != KERN_SUCCESS) { + state_count = PPC_THREAD_STATE64_COUNT; + if (thread_getstatus(th_act, PPC_THREAD_STATE64, (thread_state_t)&statep, (mach_msg_type_number_t *)&state_count) != KERN_SUCCESS) { goto errorLabel; } #else #error architecture not supported #endif - if ((int)uap->addr != 1) { + if (uap->addr != (user_addr_t)1) { #if defined(i386) locr0[PC] = (int)uap->addr; #elif defined(ppc) @@ -280,26 +290,26 @@ ptrace(p, uap, retval) if (!ALIGNED((int)uap->addr, sizeof(int))) return (ERESTART); - statep.srr0 = (int)uap->addr; - state_count = PPC_THREAD_STATE_COUNT; - if (act_machine_set_state(th_act, PPC_THREAD_STATE, &statep, &state_count) != KERN_SUCCESS) { + statep.srr0 = uap->addr; + state_count = PPC_THREAD_STATE64_COUNT; + if (thread_setstatus(th_act, PPC_THREAD_STATE64, (thread_state_t)&statep, state_count) != KERN_SUCCESS) { goto errorLabel; } #undef ALIGNED #else #error architecture not implemented! #endif - } /* (int)uap->addr != 1 */ + } /* uap->addr != (user_addr_t)1 */ - if ((unsigned)uap->data < 0 || (unsigned)uap->data >= NSIG) + if ((unsigned)uap->data >= NSIG) goto errorLabel; if (uap->data != 0) { - psignal_lock(t, uap->data, 0, 1); + psignal_lock(t, uap->data, 0); } #if defined(ppc) - state_count = PPC_THREAD_STATE_COUNT; - if (act_machine_get_state(th_act, PPC_THREAD_STATE, &statep, &state_count) != KERN_SUCCESS) { + state_count = PPC_THREAD_STATE64_COUNT; + if (thread_getstatus(th_act, PPC_THREAD_STATE64, (thread_state_t)&statep, (mach_msg_type_number_t *)&state_count) != KERN_SUCCESS) { goto errorLabel; } #endif @@ -323,8 +333,8 @@ ptrace(p, uap, retval) #endif } #if defined (ppc) - state_count = PPC_THREAD_STATE_COUNT; - if (act_machine_set_state(th_act, PPC_THREAD_STATE, &statep, &state_count) != KERN_SUCCESS) { + state_count = PPC_THREAD_STATE64_COUNT; + if (thread_setstatus(th_act, PPC_THREAD_STATE64, (thread_state_t)&statep, state_count) != KERN_SUCCESS) { goto errorLabel; } #endif @@ -333,14 +343,79 @@ ptrace(p, uap, retval) t->p_stat = SRUN; if (t->sigwait) { wakeup((caddr_t)&(t->sigwait)); - task_release(task); + if ((t->p_flag & P_SIGEXC) == 0) + task_release(task); } break; + case PT_THUPDATE: { + if ((unsigned)uap->data >= NSIG) + goto errorLabel; + th_act = port_name_to_thread(CAST_DOWN(mach_port_name_t, uap->addr)); + if (th_act == THREAD_NULL) + return (ESRCH); + ut = (uthread_t)get_bsdthread_info(th_act); + if (uap->data) + ut->uu_siglist |= sigmask(uap->data); + t->p_xstat = uap->data; + t->p_stat = SRUN; + thread_deallocate(th_act); + return(0); + } + break; +errorLabel: default: - errorLabel: return(EINVAL); } + return(0); } + +/* + * determine if one process (cur_procp) can trace another process (traced_procp). + */ + +int +cantrace(proc_t cur_procp, kauth_cred_t creds, proc_t traced_procp, int *errp) +{ + int my_err; + /* + * You can't trace a process if: + * (1) it's the process that's doing the tracing, + */ + if (traced_procp->p_pid == cur_procp->p_pid) { + *errp = EINVAL; + return (0); + } + + /* + * (2) it's already being traced, or + */ + if (ISSET(traced_procp->p_flag, P_TRACED)) { + *errp = EBUSY; + return (0); + } + + /* + * (3) it's not owned by you, or is set-id on exec + * (unless you're root). + */ + if ((creds->cr_ruid != proc_ucred(traced_procp)->cr_ruid || + ISSET(traced_procp->p_flag, P_SUGID)) && + (my_err = suser(creds, &cur_procp->p_acflag)) != 0) { + *errp = my_err; + return (0); + } + + if ((cur_procp->p_flag & P_TRACED) && isinferior(cur_procp, traced_procp)) { + *errp = EPERM; + return (0); + } + + if (ISSET(traced_procp->p_flag, P_NOATTACH)) { + *errp = EBUSY; + return (0); + } + return(1); +}