/* ARGSUSED */ int setaudit_addr(proc_t p, struct setaudit_addr_args *uap, __unused int32_t *retval) { struct auditinfo_addr aia; kauth_cred_t scred; int error; bzero(&aia, sizeof(auditinfo_addr_t)); error = copyin(uap->auditinfo_addr, &aia, min(sizeof(aia), uap->length)); if (error) return (error); AUDIT_ARG(auditinfo_addr, &aia); if (aia.ai_termid.at_type != AU_IPv6 && aia.ai_termid.at_type != AU_IPv4) return (EINVAL); if (aia.ai_asid != AU_ASSIGN_ASID && (uint32_t)aia.ai_asid > ASSIGNED_ASID_MAX) return (EINVAL); #if CONFIG_MACF error = mac_proc_check_setaudit(p, &aia); if (error) return (error); #endif scred = kauth_cred_proc_ref(p); error = suser(scred, &p->p_acflag); if (error) { kauth_cred_unref(&scred); return (error); } WARN_IF_AINFO_ADDR_CHANGED(uap->length, sizeof(auditinfo_addr_t), "setaudit_addr(2)", "auditinfo_addr_t"); WARN_IF_BAD_ASID(aia.ai_asid, "setaudit_addr(2)"); kauth_cred_unref(&scred); AUDIT_CHECK_IF_KEVENTS_MASK(aia.ai_mask); if (aia.ai_asid == AU_DEFAUDITSID) aia.ai_asid = AU_ASSIGN_ASID; error = audit_session_setaia(p, &aia); if (error) return (error); /* * If asked to assign an ASID then let the user know what the ASID is * by copying the auditinfo_addr struct back out. */ if (aia.ai_asid == AU_ASSIGN_ASID) error = getaudit_addr_internal(p, uap->auditinfo_addr, uap->length); return (error); }
int reboot(struct proc *p, register struct reboot_args *uap, __unused int32_t *retval) { char command[64]; int error=0; size_t dummy=0; #if CONFIG_MACF kauth_cred_t my_cred; #endif AUDIT_ARG(cmd, uap->opt); command[0] = '\0'; if ((error = suser(kauth_cred_get(), &p->p_acflag))) return(error); if (uap->opt & RB_COMMAND) error = copyinstr(uap->command, (void *)command, sizeof(command), (size_t *)&dummy); #if CONFIG_MACF if (error) return (error); my_cred = kauth_cred_proc_ref(p); error = mac_system_check_reboot(my_cred, uap->opt); kauth_cred_unref(&my_cred); #endif if (!error) { OSBitOrAtomic(P_REBOOT, &p->p_flag); /* No more signals for this proc */ error = boot(RB_BOOT, uap->opt, command); } return(error); }
/* * Destroy a process structure that resulted from a call to forkproc(), but * which must be returned to the system because of a subsequent failure * preventing it from becoming active. * * Parameters: p The incomplete process from forkproc() * * Returns: (void) * * Note: This function should only be used in an error handler following * a call to forkproc(). * * Operations occur in reverse order of those in forkproc(). */ void forkproc_free(proc_t p) { /* We held signal and a transition locks; drop them */ proc_signalend(p, 0); proc_transend(p, 0); /* * If we have our own copy of the resource limits structure, we * need to free it. If it's a shared copy, we need to drop our * reference on it. */ proc_limitdrop(p, 0); p->p_limit = NULL; #if SYSV_SHM /* Need to drop references to the shared memory segment(s), if any */ if (p->vm_shm) { /* * Use shmexec(): we have no address space, so no mappings * * XXX Yes, the routine is badly named. */ shmexec(p); } #endif /* Need to undo the effects of the fdcopy(), if any */ fdfree(p); /* * Drop the reference on a text vnode pointer, if any * XXX This code is broken in forkproc(); see <rdar://4256419>; * XXX if anyone ever uses this field, we will be extremely unhappy. */ if (p->p_textvp) { vnode_rele(p->p_textvp); p->p_textvp = NULL; } /* Stop the profiling clock */ stopprofclock(p); /* Release the credential reference */ kauth_cred_unref(&p->p_ucred); proc_list_lock(); /* Decrement the count of processes in the system */ nprocs--; proc_list_unlock(); thread_call_free(p->p_rcall); /* Free allocated memory */ FREE_ZONE(p->p_sigacts, sizeof *p->p_sigacts, M_SIGACTS); FREE_ZONE(p->p_stats, sizeof *p->p_stats, M_PSTATS); proc_checkdeadrefs(p); FREE_ZONE(p, sizeof *p, M_PROC); }
void vnclear(struct vn_softc *vn, vfs_context_t ctx) { if (vn->sc_vp != NULL) { /* release long-term reference */ (void)vn_close(vn->sc_vp, vn->sc_open_flags, ctx); vn->sc_vp = NULL; } if (vn->sc_shadow_vp != NULL) { /* release long-term reference */ (void)vn_close(vn->sc_shadow_vp, FREAD | FWRITE, ctx); vn->sc_shadow_vp = NULL; } if (vn->sc_shadow_map != NULL) { shadow_map_free(vn->sc_shadow_map); vn->sc_shadow_map = NULL; } vn->sc_flags &= ~(VNF_INITED | VNF_READONLY); if (vn->sc_cred) { kauth_cred_unref(&vn->sc_cred); } vn->sc_size = 0; vn->sc_fsize = 0; if (vn->sc_cdev) { devfs_remove(vn->sc_cdev); vn->sc_cdev = NULL; } }
/* * Construct an audit record for the passed thread. */ static void audit_record_ctor(proc_t p, struct kaudit_record *ar) { kauth_cred_t cred; bzero(ar, sizeof(*ar)); ar->k_ar.ar_magic = AUDIT_RECORD_MAGIC; nanotime(&ar->k_ar.ar_starttime); if (PROC_NULL != p) { cred = kauth_cred_proc_ref(p); /* * Export the subject credential. */ cru2x(cred, &ar->k_ar.ar_subj_cred); ar->k_ar.ar_subj_ruid = kauth_cred_getruid(cred); ar->k_ar.ar_subj_rgid = kauth_cred_getrgid(cred); ar->k_ar.ar_subj_egid = kauth_cred_getgid(cred); ar->k_ar.ar_subj_pid = p->p_pid; ar->k_ar.ar_subj_auid = cred->cr_audit.as_aia_p->ai_auid; ar->k_ar.ar_subj_asid = cred->cr_audit.as_aia_p->ai_asid; bcopy(&cred->cr_audit.as_mask, &ar->k_ar.ar_subj_amask, sizeof(struct au_mask)); bcopy(&cred->cr_audit.as_aia_p->ai_termid, &ar->k_ar.ar_subj_term_addr, sizeof(struct au_tid_addr)); kauth_cred_unref(&cred); } }
/* * Routine: task_for_pid_posix_check * Purpose: * Verify that the current process should be allowed to * get the target process's task port. This is only * permitted if: * - The current process is root * OR all of the following are true: * - The target process's real, effective, and saved uids * are the same as the current proc's euid, * - The target process's group set is a subset of the * calling process's group set, and * - The target process hasn't switched credentials. * * Returns: TRUE: permitted * FALSE: denied */ static int task_for_pid_posix_check(proc_t target) { kauth_cred_t targetcred, mycred; uid_t myuid; int allowed; /* No task_for_pid on bad targets */ if (target->p_stat == SZOMB) { return FALSE; } mycred = kauth_cred_get(); myuid = kauth_cred_getuid(mycred); /* If we're running as root, the check passes */ if (kauth_cred_issuser(mycred)) return TRUE; /* We're allowed to get our own task port */ if (target == current_proc()) return TRUE; /* * Under DENY, only root can get another proc's task port, * so no more checks are needed. */ if (tfp_policy == KERN_TFP_POLICY_DENY) { return FALSE; } targetcred = kauth_cred_proc_ref(target); allowed = TRUE; /* Do target's ruid, euid, and saved uid match my euid? */ if ((kauth_cred_getuid(targetcred) != myuid) || (kauth_cred_getruid(targetcred) != myuid) || (kauth_cred_getsvuid(targetcred) != myuid)) { allowed = FALSE; goto out; } /* Are target's groups a subset of my groups? */ if (kauth_cred_gid_subset(targetcred, mycred, &allowed) || allowed == 0) { allowed = FALSE; goto out; } /* Has target switched credentials? */ if (target->p_flag & P_SUGID) { allowed = FALSE; goto out; } out: kauth_cred_unref(&targetcred); return allowed; }
/** * Device open. Called on open /dev/vboxguest and (later) /dev/vboxguestu. * * @param Dev The device number. * @param fFlags ???. * @param fDevType ???. * @param pProcess The process issuing this request. */ static int VbgdDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess) { /* * Only two minor devices numbers are allowed. */ if (minor(Dev) != 0 && minor(Dev) != 1) return EACCES; /* * Find the session created by org_virtualbox_VBoxGuestClient, fail * if no such session, and mark it as opened. We set the uid & gid * here too, since that is more straight forward at this point. */ //const bool fUnrestricted = minor(Dev) == 0; int rc = VINF_SUCCESS; PVBOXGUESTSESSION pSession = NULL; kauth_cred_t pCred = kauth_cred_proc_ref(pProcess); if (pCred) { RTPROCESS Process = RTProcSelf(); unsigned iHash = SESSION_HASH(Process); RTSpinlockAcquire(g_Spinlock); pSession = g_apSessionHashTab[iHash]; while (pSession && pSession->Process != Process) pSession = pSession->pNextHash; if (pSession) { if (!pSession->fOpened) { pSession->fOpened = true; /*pSession->fUnrestricted = fUnrestricted; - later */ } else rc = VERR_ALREADY_LOADED; } else rc = VERR_GENERAL_FAILURE; RTSpinlockRelease(g_Spinlock); #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 kauth_cred_unref(&pCred); #else /* 10.4 */ /* The 10.4u SDK headers and 10.4.11 kernel source have inconsistent definitions of kauth_cred_unref(), so use the other (now deprecated) API for releasing it. */ kauth_cred_rele(pCred); #endif /* 10.4 */ } else rc = VERR_INVALID_PARAMETER; Log(("VbgdDarwinOpen: g_DevExt=%p pSession=%p rc=%d pid=%d\n", &g_DevExt, pSession, rc, proc_pid(pProcess))); return VbgdDarwinErr2DarwinErr(rc); }
int reboot(struct proc *p, struct reboot_args *uap, __unused int32_t *retval) { char message[128]; int error=0; size_t dummy=0; #if CONFIG_MACF kauth_cred_t my_cred; #endif AUDIT_ARG(cmd, uap->opt); message[0] = '\0'; if ((error = suser(kauth_cred_get(), &p->p_acflag))) { #if (DEVELOPMENT || DEBUG) /* allow non-root user to call panic on dev/debug kernels */ if (!(uap->opt & RB_PANIC)) return error; #else return error; #endif } if (uap->opt & RB_COMMAND) return ENOSYS; if (uap->opt & RB_PANIC) { error = copyinstr(uap->command, (void *)message, sizeof(message), (size_t *)&dummy); } #if CONFIG_MACF #if (DEVELOPMENT || DEBUG) if (uap->opt & RB_PANIC) { /* on dev/debug kernels: allow anyone to call panic */ goto skip_cred_check; } #endif if (error) return (error); my_cred = kauth_cred_proc_ref(p); error = mac_system_check_reboot(my_cred, uap->opt); kauth_cred_unref(&my_cred); #if (DEVELOPMENT || DEBUG) skip_cred_check: #endif #endif if (!error) { OSBitOrAtomic(P_REBOOT, &p->p_flag); /* No more signals for this proc */ error = reboot_kernel(uap->opt, message); } return(error); }
/* This routine releases the credential stored in uthread */ void uthread_cred_free(void *uthread) { uthread_t uth = (uthread_t)uthread; /* and free the uthread itself */ if (IS_VALID_CRED(uth->uu_ucred)) { kauth_cred_t oldcred = uth->uu_ucred; uth->uu_ucred = NOCRED; kauth_cred_unref(&oldcred); } }
int mac_cred_label_externalize_audit(struct proc *p, struct mac *mac) { kauth_cred_t cr; int error; cr = kauth_cred_proc_ref(p); error = MAC_EXTERNALIZE_AUDIT(cred, cr->cr_label, mac->m_string, mac->m_buflen); kauth_cred_unref(&cr); return (error); }
/* ARGSUSED */ int setauid(proc_t p, struct setauid_args *uap, __unused int32_t *retval) { int error; au_id_t id; kauth_cred_t scred; struct auditinfo_addr aia; error = copyin(uap->auid, &id, sizeof(id)); if (error) return (error); AUDIT_ARG(auid, id); #if CONFIG_MACF error = mac_proc_check_setauid(p, id); if (error) return (error); #endif scred = kauth_cred_proc_ref(p); error = suser(scred, &p->p_acflag); if (error) { kauth_cred_unref(&scred); return (error); } bcopy(scred->cr_audit.as_aia_p, &aia, sizeof(aia)); if (aia.ai_asid == AU_DEFAUDITSID) { aia.ai_asid = AU_ASSIGN_ASID; } bcopy(&scred->cr_audit.as_mask, &aia.ai_mask, sizeof(au_mask_t)); kauth_cred_unref(&scred); aia.ai_auid = id; error = audit_session_setaia(p, &aia); return (error); }
int mac_task_check_set_host_exception_port(struct task *task, unsigned int exception) { int error; struct proc *p = mac_task_get_proc(task); if (p == NULL) return ESRCH; kauth_cred_t cred = kauth_cred_proc_ref(p); MAC_CHECK(proc_check_set_host_exception_port, cred, exception); kauth_cred_unref(&cred); proc_rele(p); return (error); }
int mac_task_check_set_host_special_port(struct task *task, int id, struct ipc_port *port) { int error; struct proc *p = mac_task_get_proc(task); if (p == NULL) return ESRCH; kauth_cred_t cred = kauth_cred_proc_ref(p); MAC_CHECK(proc_check_set_host_special_port, cred, id, port); kauth_cred_unref(&cred); proc_rele(p); return (error); }
int mac_proc_check_ledger(proc_t curp, proc_t proc, int ledger_op) { kauth_cred_t cred; int error = 0; if (!mac_proc_enforce || !mac_proc_check_enforce(curp, MAC_PROC_ENFORCE)) return (0); cred = kauth_cred_proc_ref(curp); MAC_CHECK(proc_check_ledger, cred, proc, ledger_op); kauth_cred_unref(&cred); return (error); }
int mac_proc_check_fork(proc_t curp) { kauth_cred_t cred; int error; if (!mac_proc_enforce || !mac_proc_check_enforce(curp, MAC_PROC_ENFORCE)) return (0); cred = kauth_cred_proc_ref(curp); MAC_CHECK(proc_check_fork, cred, curp); kauth_cred_unref(&cred); return (error); }
/* * The type of maxprot in proc_check_map_anon must be equivalent to vm_prot_t * (defined in <mach/vm_prot.h>). mac_policy.h does not include any header * files, so cannot use the typedef itself. */ int mac_proc_check_map_anon(proc_t proc, user_addr_t u_addr, user_size_t u_size, int prot, int flags, int *maxprot) { kauth_cred_t cred; int error; if (!mac_vm_enforce || !mac_proc_check_enforce(proc, MAC_VM_ENFORCE)) return (0); cred = kauth_cred_proc_ref(proc); MAC_CHECK(proc_check_map_anon, proc, cred, u_addr, u_size, prot, flags, maxprot); kauth_cred_unref(&cred); return (error); }
int mac_proc_check_mprotect(proc_t proc, user_addr_t addr, user_size_t size, int prot) { kauth_cred_t cred; int error; if (!mac_vm_enforce || !mac_proc_check_enforce(proc, MAC_VM_ENFORCE)) return (0); cred = kauth_cred_proc_ref(proc); MAC_CHECK(proc_check_mprotect, cred, proc, addr, size, prot); kauth_cred_unref(&cred); return (error); }
int mac_proc_check_signal(proc_t curp, struct proc *proc, int signum) { kauth_cred_t cred; int error; if (!mac_proc_enforce || !mac_proc_check_enforce(curp, MAC_PROC_ENFORCE)) return (0); cred = kauth_cred_proc_ref(curp); MAC_CHECK(proc_check_signal, cred, proc, signum); kauth_cred_unref(&cred); return (error); }
static int getaudit_addr_internal(proc_t p, user_addr_t user_addr, size_t length) { kauth_cred_t scred; auditinfo_addr_t aia; scred = kauth_cred_proc_ref(p); bcopy(scred->cr_audit.as_aia_p, &aia, sizeof (auditinfo_addr_t)); /* * Only superuser gets to see the real mask. */ if (suser(scred, &p->p_acflag)) { aia.ai_mask.am_success = ~0; aia.ai_mask.am_failure = ~0; } kauth_cred_unref(&scred); return (copyout(&aia, user_addr, min(sizeof(aia), length))); }
int cttyopen(__unused dev_t dev, int flag, __unused int mode, proc_t p) { vnode_t ttyvp = cttyvp(p); struct vfs_context context; int error; if (ttyvp == NULL) return (ENXIO); context.vc_thread = current_thread(); context.vc_ucred = kauth_cred_proc_ref(p); error = VNOP_OPEN(ttyvp, flag, &context); vnode_put(ttyvp); kauth_cred_unref(&context.vc_ucred); return (error); }
int reboot(struct proc *p, struct reboot_args *uap, __unused int32_t *retval) { char message[128]; int error=0; size_t dummy=0; #if CONFIG_MACF kauth_cred_t my_cred; #endif AUDIT_ARG(cmd, uap->opt); message[0] = '\0'; if ((error = suser(kauth_cred_get(), &p->p_acflag))) return(error); if (uap->opt & RB_COMMAND) return ENOSYS; if (uap->opt & RB_PANIC) { #if !(DEVELOPMENT || DEBUG) if (p != initproc) { return EPERM; } #endif error = copyinstr(uap->command, (void *)message, sizeof(message), (size_t *)&dummy); } #if CONFIG_MACF if (error) return (error); my_cred = kauth_cred_proc_ref(p); error = mac_system_check_reboot(my_cred, uap->opt); kauth_cred_unref(&my_cred); #endif if (!error) { OSBitOrAtomic(P_REBOOT, &p->p_flag); /* No more signals for this proc */ error = reboot_kernel(uap->opt, message); } return(error); }
int mac_task_check_set_host_exception_ports(struct task *task, unsigned int exception_mask) { int error = 0; int exception; struct proc *p = mac_task_get_proc(task); if (p == NULL) return ESRCH; kauth_cred_t cred = kauth_cred_proc_ref(p); for (exception = FIRST_EXCEPTION; exception < EXC_TYPES_COUNT; exception++) { if (exception_mask & (1 << exception)) { MAC_CHECK(proc_check_set_host_exception_port, cred, exception); if (error) break; } } kauth_cred_unref(&cred); proc_rele(p); return (error); }
/* ARGSUSED */ int getauid(proc_t p, struct getauid_args *uap, __unused int32_t *retval) { au_id_t id; int error; kauth_cred_t scred; #if CONFIG_MACF error = mac_proc_check_getauid(p); if (error) return (error); #endif scred = kauth_cred_proc_ref(p); id = scred->cr_audit.as_aia_p->ai_auid; kauth_cred_unref(&scred); error = copyout((void *)&id, uap->auid, sizeof(id)); if (error) return (error); return (0); }
/* system call implementation */ int process_policy(__unused struct proc *p, struct process_policy_args * uap, __unused int32_t *retval) { int error = 0; int scope = uap->scope; int policy = uap->policy; int action = uap->action; int policy_subtype = uap->policy_subtype; user_addr_t attrp = uap->attrp; pid_t target_pid = uap->target_pid; uint64_t target_threadid = uap->target_threadid; proc_t target_proc = PROC_NULL; #if CONFIG_MACF || !CONFIG_EMBEDDED proc_t curp = current_proc(); #endif kauth_cred_t my_cred; #if CONFIG_EMBEDDED kauth_cred_t target_cred; #endif if ((scope != PROC_POLICY_SCOPE_PROCESS) && (scope != PROC_POLICY_SCOPE_THREAD)) { return(EINVAL); } if (target_pid == 0 || target_pid == proc_selfpid()) target_proc = proc_self(); else target_proc = proc_find(target_pid); if (target_proc == PROC_NULL) return(ESRCH); my_cred = kauth_cred_get(); #if CONFIG_EMBEDDED target_cred = kauth_cred_proc_ref(target_proc); if (!kauth_cred_issuser(my_cred) && kauth_cred_getruid(my_cred) && kauth_cred_getuid(my_cred) != kauth_cred_getuid(target_cred) && kauth_cred_getruid(my_cred) != kauth_cred_getuid(target_cred)) #else /* * Resoure starvation control can be used by unpriv resource owner but priv at the time of ownership claim. This is * checked in low resource handle routine. So bypass the checks here. */ if ((policy != PROC_POLICY_RESOURCE_STARVATION) && (policy != PROC_POLICY_APPTYPE) && (!kauth_cred_issuser(my_cred) && curp != p)) #endif { error = EPERM; goto out; } #if CONFIG_MACF switch (policy) { case PROC_POLICY_BOOST: case PROC_POLICY_RESOURCE_USAGE: #if CONFIG_EMBEDDED case PROC_POLICY_APPTYPE: case PROC_POLICY_APP_LIFECYCLE: #endif /* These policies do their own appropriate mac checks */ break; default: error = mac_proc_check_sched(curp, target_proc); if (error) goto out; break; } #endif /* CONFIG_MACF */ switch(policy) { case PROC_POLICY_BACKGROUND: error = ENOTSUP; break; case PROC_POLICY_HARDWARE_ACCESS: error = ENOTSUP; break; case PROC_POLICY_RESOURCE_STARVATION: error = handle_lowresource(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid); break; case PROC_POLICY_RESOURCE_USAGE: switch(policy_subtype) { case PROC_POLICY_RUSAGE_NONE: case PROC_POLICY_RUSAGE_WIREDMEM: case PROC_POLICY_RUSAGE_VIRTMEM: case PROC_POLICY_RUSAGE_DISK: case PROC_POLICY_RUSAGE_NETWORK: case PROC_POLICY_RUSAGE_POWER: error = ENOTSUP; goto out; default: error = EINVAL; goto out; case PROC_POLICY_RUSAGE_CPU: break; } error = handle_cpuuse(action, attrp, target_proc, target_threadid); break; #if CONFIG_EMBEDDED case PROC_POLICY_APP_LIFECYCLE: error = handle_applifecycle(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid); break; #endif /* CONFIG_EMBEDDED */ case PROC_POLICY_APPTYPE: error = handle_apptype(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid); break; case PROC_POLICY_BOOST: error = handle_boost(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid); break; default: error = EINVAL; break; } out: proc_rele(target_proc); #if CONFIG_EMBEDDED kauth_cred_unref(&target_cred); #endif return(error); }
/* * XXX: this is borrowed from in6_pcbbind(). If possible, we should * share this function by all *bsd*... */ int in6_pcbsetport( __unused struct in6_addr *laddr, struct inpcb *inp, struct proc *p, int locked) { struct socket *so = inp->inp_socket; u_int16_t lport = 0, first, last, *lastport; int count, error = 0, wild = 0; struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; kauth_cred_t cred; if (!locked) { /* Make sure we don't run into a deadlock: 4052373 */ if (!lck_rw_try_lock_exclusive(pcbinfo->mtx)) { socket_unlock(inp->inp_socket, 0); lck_rw_lock_exclusive(pcbinfo->mtx); socket_lock(inp->inp_socket, 0); } } /* XXX: this is redundant when called from in6_pcbbind */ if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0) wild = INPLOOKUP_WILDCARD; inp->inp_flags |= INP_ANONPORT; if (inp->inp_flags & INP_HIGHPORT) { first = ipport_hifirstauto; /* sysctl */ last = ipport_hilastauto; lastport = &pcbinfo->lasthi; } else if (inp->inp_flags & INP_LOWPORT) { cred = kauth_cred_proc_ref(p); error = priv_check_cred(cred, PRIV_NETINET_RESERVEDPORT, 0); kauth_cred_unref(&cred); if (error != 0) { if (!locked) lck_rw_done(pcbinfo->mtx); return error; } first = ipport_lowfirstauto; /* 1023 */ last = ipport_lowlastauto; /* 600 */ lastport = &pcbinfo->lastlow; } else { first = ipport_firstauto; /* sysctl */ last = ipport_lastauto; lastport = &pcbinfo->lastport; } /* * Simple check to ensure all ports are not used up causing * a deadlock here. * * We split the two cases (up and down) so that the direction * is not being tested on each round of the loop. */ if (first > last) { /* * counting down */ count = first - last; do { if (count-- < 0) { /* completely used? */ /* * Undo any address bind that may have * occurred above. */ inp->in6p_laddr = in6addr_any; inp->in6p_last_outif = 0; if (!locked) lck_rw_done(pcbinfo->mtx); return (EAGAIN); } --*lastport; if (*lastport > first || *lastport < last) *lastport = first; lport = htons(*lastport); } while (in6_pcblookup_local(pcbinfo, &inp->in6p_laddr, lport, wild)); } else { /* * counting up */ count = last - first; do { if (count-- < 0) { /* completely used? */ /* * Undo any address bind that may have * occurred above. */ inp->in6p_laddr = in6addr_any; inp->in6p_last_outif = 0; if (!locked) lck_rw_done(pcbinfo->mtx); return (EAGAIN); } ++*lastport; if (*lastport < first || *lastport > last) *lastport = first; lport = htons(*lastport); } while (in6_pcblookup_local(pcbinfo, &inp->in6p_laddr, lport, wild)); } inp->inp_lport = lport; if (in_pcbinshash(inp, 1) != 0) { inp->in6p_laddr = in6addr_any; inp->inp_lport = 0; inp->in6p_last_outif = 0; if (!locked) lck_rw_done(pcbinfo->mtx); return (EAGAIN); } if (!locked) lck_rw_done(pcbinfo->mtx); return(0); }
static int vniocattach_file(struct vn_softc *vn, struct vn_ioctl_64 *vniop, dev_t dev, int in_kernel, proc_t p) { dev_t cdev; vfs_context_t ctx = vfs_context_current(); kauth_cred_t cred; struct nameidata nd; off_t file_size; int error, flags; flags = FREAD|FWRITE; if (in_kernel) { NDINIT(&nd, LOOKUP, OP_OPEN, FOLLOW, UIO_SYSSPACE, vniop->vn_file, ctx); } else { NDINIT(&nd, LOOKUP, OP_OPEN, FOLLOW, (IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32), vniop->vn_file, ctx); } /* vn_open gives both long- and short-term references */ error = vn_open(&nd, flags, 0); if (error) { if (error != EACCES && error != EPERM && error != EROFS) { return (error); } flags &= ~FWRITE; if (in_kernel) { NDINIT(&nd, LOOKUP, OP_OPEN, FOLLOW, UIO_SYSSPACE, vniop->vn_file, ctx); } else { NDINIT(&nd, LOOKUP, OP_OPEN, FOLLOW, (IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32), vniop->vn_file, ctx); } error = vn_open(&nd, flags, 0); if (error) { return (error); } } if (nd.ni_vp->v_type != VREG) { error = EINVAL; } else { error = vnode_size(nd.ni_vp, &file_size, ctx); } if (error != 0) { (void) vn_close(nd.ni_vp, flags, ctx); vnode_put(nd.ni_vp); return (error); } cred = kauth_cred_proc_ref(p); nd.ni_vp->v_flag |= VNOCACHE_DATA; error = setcred(nd.ni_vp, cred); if (error) { (void)vn_close(nd.ni_vp, flags, ctx); vnode_put(nd.ni_vp); kauth_cred_unref(&cred); return(error); } vn->sc_secsize = DEV_BSIZE; vn->sc_fsize = file_size; vn->sc_size = file_size / vn->sc_secsize; vn->sc_vp = nd.ni_vp; vn->sc_vid = vnode_vid(nd.ni_vp); vn->sc_open_flags = flags; vn->sc_cred = cred; cdev = makedev(vndevice_cdev_major, minor(dev)); vn->sc_cdev = devfs_make_node(cdev, DEVFS_CHAR, UID_ROOT, GID_OPERATOR, 0600, "rvn%d", minor(dev)); vn->sc_flags |= VNF_INITED; if (flags == FREAD) vn->sc_flags |= VNF_READONLY; /* lose the short-term reference */ vnode_put(nd.ni_vp); return(0); }
/** * Device open. Called on open /dev/vboxdrv * * @param Dev The device number. * @param fFlags ???. * @param fDevType ???. * @param pProcess The process issuing this request. */ static int VBoxDrvDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess) { #ifdef DEBUG_DARWIN_GIP char szName[128]; szName[0] = '\0'; proc_name(proc_pid(pProcess), szName, sizeof(szName)); Log(("VBoxDrvDarwinOpen: pid=%d '%s'\n", proc_pid(pProcess), szName)); #endif /* * Only two minor devices numbers are allowed. */ if (minor(Dev) != 0 && minor(Dev) != 1) return EACCES; /* * Find the session created by org_virtualbox_SupDrvClient, fail * if no such session, and mark it as opened. We set the uid & gid * here too, since that is more straight forward at this point. */ const bool fUnrestricted = minor(Dev) == 0; int rc = VINF_SUCCESS; PSUPDRVSESSION pSession = NULL; kauth_cred_t pCred = kauth_cred_proc_ref(pProcess); if (pCred) { #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 RTUID Uid = kauth_cred_getruid(pCred); RTGID Gid = kauth_cred_getrgid(pCred); #else RTUID Uid = pCred->cr_ruid; RTGID Gid = pCred->cr_rgid; #endif RTPROCESS Process = RTProcSelf(); unsigned iHash = SESSION_HASH(Process); RTSpinlockAcquire(g_Spinlock); pSession = g_apSessionHashTab[iHash]; while (pSession && pSession->Process != Process) pSession = pSession->pNextHash; if (pSession) { if (!pSession->fOpened) { pSession->fOpened = true; pSession->fUnrestricted = fUnrestricted; pSession->Uid = Uid; pSession->Gid = Gid; } else rc = VERR_ALREADY_LOADED; } else rc = VERR_GENERAL_FAILURE; RTSpinlockReleaseNoInts(g_Spinlock); #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 kauth_cred_unref(&pCred); #else /* 10.4 */ /* The 10.4u SDK headers and 10.4.11 kernel source have inconsistent definitions of kauth_cred_unref(), so use the other (now deprecated) API for releasing it. */ kauth_cred_rele(pCred); #endif /* 10.4 */ } else rc = VERR_INVALID_PARAMETER; #ifdef DEBUG_DARWIN_GIP OSDBGPRINT(("VBoxDrvDarwinOpen: pid=%d '%s' pSession=%p rc=%d\n", proc_pid(pProcess), szName, pSession, rc)); #else Log(("VBoxDrvDarwinOpen: g_DevExt=%p pSession=%p rc=%d pid=%d\n", &g_DevExt, pSession, rc, proc_pid(pProcess))); #endif return VBoxDrvDarwinErr2DarwinErr(rc); }
/* ARGSUSED */ int auditon(proc_t p, struct auditon_args *uap, __unused int32_t *retval) { kauth_cred_t scred; int error = 0; union auditon_udata udata; proc_t tp = PROC_NULL; struct auditinfo_addr aia; AUDIT_ARG(cmd, uap->cmd); #if CONFIG_MACF error = mac_system_check_auditon(kauth_cred_get(), uap->cmd); if (error) return (error); #endif if ((uap->length <= 0) || (uap->length > (int)sizeof(union auditon_udata))) return (EINVAL); memset((void *)&udata, 0, sizeof(udata)); /* * Some of the GET commands use the arguments too. */ switch (uap->cmd) { case A_SETPOLICY: case A_OLDSETPOLICY: case A_SETKMASK: case A_SETQCTRL: case A_OLDSETQCTRL: case A_SETSTAT: case A_SETUMASK: case A_SETSMASK: case A_SETCOND: case A_OLDSETCOND: case A_SETCLASS: case A_SETPMASK: case A_SETFSIZE: case A_SETKAUDIT: case A_GETCLASS: case A_GETPINFO: case A_GETPINFO_ADDR: case A_SENDTRIGGER: case A_GETSINFO_ADDR: case A_GETSFLAGS: case A_SETSFLAGS: error = copyin(uap->data, (void *)&udata, uap->length); if (error) return (error); AUDIT_ARG(auditon, &udata); AUDIT_ARG(len, uap->length); break; } /* Check appropriate privilege. */ switch (uap->cmd) { /* * A_GETSINFO doesn't require priviledge but only superuser * gets to see the audit masks. */ case A_GETSINFO_ADDR: if ((sizeof(udata.au_kau_info) != uap->length) || (audit_session_lookup(udata.au_kau_info.ai_asid, &udata.au_kau_info) != 0)) error = EINVAL; else if (!kauth_cred_issuser(kauth_cred_get())) { udata.au_kau_info.ai_mask.am_success = ~0; udata.au_kau_info.ai_mask.am_failure = ~0; } break; case A_GETSFLAGS: case A_SETSFLAGS: /* Getting one's own audit session flags requires no * privilege. Setting the flags is subject to access * control implemented in audit_session_setaia(). */ break; default: error = suser(kauth_cred_get(), &p->p_acflag); break; } if (error) return (error); /* * XXX Need to implement these commands by accessing the global * values associated with the commands. */ switch (uap->cmd) { case A_OLDGETPOLICY: case A_GETPOLICY: if (sizeof(udata.au_policy64) == uap->length) { mtx_lock(&audit_mtx); if (!audit_fail_stop) udata.au_policy64 |= AUDIT_CNT; if (audit_panic_on_write_fail) udata.au_policy64 |= AUDIT_AHLT; if (audit_argv) udata.au_policy64 |= AUDIT_ARGV; if (audit_arge) udata.au_policy64 |= AUDIT_ARGE; mtx_unlock(&audit_mtx); break; } if (sizeof(udata.au_policy) != uap->length) return (EINVAL); mtx_lock(&audit_mtx); if (!audit_fail_stop) udata.au_policy |= AUDIT_CNT; if (audit_panic_on_write_fail) udata.au_policy |= AUDIT_AHLT; if (audit_argv) udata.au_policy |= AUDIT_ARGV; if (audit_arge) udata.au_policy |= AUDIT_ARGE; mtx_unlock(&audit_mtx); break; case A_OLDSETPOLICY: case A_SETPOLICY: if (sizeof(udata.au_policy64) == uap->length) { if (udata.au_policy64 & ~(AUDIT_CNT|AUDIT_AHLT| AUDIT_ARGV|AUDIT_ARGE)) return (EINVAL); mtx_lock(&audit_mtx); audit_fail_stop = ((udata.au_policy64 & AUDIT_CNT) == 0); audit_panic_on_write_fail = (udata.au_policy64 & AUDIT_AHLT); audit_argv = (udata.au_policy64 & AUDIT_ARGV); audit_arge = (udata.au_policy64 & AUDIT_ARGE); mtx_unlock(&audit_mtx); break; } if ((sizeof(udata.au_policy) != uap->length) || (udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT|AUDIT_ARGV| AUDIT_ARGE))) return (EINVAL); /* * XXX - Need to wake up waiters if the policy relaxes? */ mtx_lock(&audit_mtx); audit_fail_stop = ((udata.au_policy & AUDIT_CNT) == 0); audit_panic_on_write_fail = (udata.au_policy & AUDIT_AHLT); audit_argv = (udata.au_policy & AUDIT_ARGV); audit_arge = (udata.au_policy & AUDIT_ARGE); mtx_unlock(&audit_mtx); break; case A_GETKMASK: if (sizeof(udata.au_mask) != uap->length) return (EINVAL); mtx_lock(&audit_mtx); udata.au_mask = audit_nae_mask; mtx_unlock(&audit_mtx); break; case A_SETKMASK: if (sizeof(udata.au_mask) != uap->length) return (EINVAL); mtx_lock(&audit_mtx); audit_nae_mask = udata.au_mask; AUDIT_CHECK_IF_KEVENTS_MASK(audit_nae_mask); mtx_unlock(&audit_mtx); break; case A_OLDGETQCTRL: case A_GETQCTRL: if (sizeof(udata.au_qctrl64) == uap->length) { mtx_lock(&audit_mtx); udata.au_qctrl64.aq64_hiwater = (u_int64_t)audit_qctrl.aq_hiwater; udata.au_qctrl64.aq64_lowater = (u_int64_t)audit_qctrl.aq_lowater; udata.au_qctrl64.aq64_bufsz = (u_int64_t)audit_qctrl.aq_bufsz; udata.au_qctrl64.aq64_delay = (u_int64_t)audit_qctrl.aq_delay; udata.au_qctrl64.aq64_minfree = (int64_t)audit_qctrl.aq_minfree; mtx_unlock(&audit_mtx); break; } if (sizeof(udata.au_qctrl) != uap->length) return (EINVAL); mtx_lock(&audit_mtx); udata.au_qctrl = audit_qctrl; mtx_unlock(&audit_mtx); break; case A_OLDSETQCTRL: case A_SETQCTRL: if (sizeof(udata.au_qctrl64) == uap->length) { if ((udata.au_qctrl64.aq64_hiwater > AQ_MAXHIGH) || (udata.au_qctrl64.aq64_lowater >= udata.au_qctrl64.aq64_hiwater) || (udata.au_qctrl64.aq64_bufsz > AQ_MAXBUFSZ) || (udata.au_qctrl64.aq64_minfree < 0) || (udata.au_qctrl64.aq64_minfree > 100)) return (EINVAL); mtx_lock(&audit_mtx); audit_qctrl.aq_hiwater = (int)udata.au_qctrl64.aq64_hiwater; audit_qctrl.aq_lowater = (int)udata.au_qctrl64.aq64_lowater; audit_qctrl.aq_bufsz = (int)udata.au_qctrl64.aq64_bufsz; audit_qctrl.aq_minfree = (int)udata.au_qctrl64.aq64_minfree; audit_qctrl.aq_delay = -1; /* Not used. */ mtx_unlock(&audit_mtx); break; } if ((sizeof(udata.au_qctrl) != uap->length) || (udata.au_qctrl.aq_hiwater > AQ_MAXHIGH) || (udata.au_qctrl.aq_lowater >= udata.au_qctrl.aq_hiwater) || (udata.au_qctrl.aq_bufsz > AQ_MAXBUFSZ) || (udata.au_qctrl.aq_minfree < 0) || (udata.au_qctrl.aq_minfree > 100)) return (EINVAL); mtx_lock(&audit_mtx); audit_qctrl = udata.au_qctrl; /* XXX The queue delay value isn't used with the kernel. */ audit_qctrl.aq_delay = -1; mtx_unlock(&audit_mtx); break; case A_GETCWD: return (ENOSYS); case A_GETCAR: return (ENOSYS); case A_GETSTAT: return (ENOSYS); case A_SETSTAT: return (ENOSYS); case A_SETUMASK: return (ENOSYS); case A_SETSMASK: return (ENOSYS); case A_OLDGETCOND: case A_GETCOND: if (sizeof(udata.au_cond64) == uap->length) { mtx_lock(&audit_mtx); if (audit_enabled && !audit_suspended) udata.au_cond64 = AUC_AUDITING; else udata.au_cond64 = AUC_NOAUDIT; mtx_unlock(&audit_mtx); break; } if (sizeof(udata.au_cond) != uap->length) return (EINVAL); mtx_lock(&audit_mtx); if (audit_enabled && !audit_suspended) udata.au_cond = AUC_AUDITING; else udata.au_cond = AUC_NOAUDIT; mtx_unlock(&audit_mtx); break; case A_OLDSETCOND: case A_SETCOND: if (sizeof(udata.au_cond64) == uap->length) { mtx_lock(&audit_mtx); if (udata.au_cond64 == AUC_NOAUDIT) audit_suspended = 1; if (udata.au_cond64 == AUC_AUDITING) audit_suspended = 0; if (udata.au_cond64 == AUC_DISABLED) { audit_suspended = 1; mtx_unlock(&audit_mtx); audit_shutdown(); break; } mtx_unlock(&audit_mtx); break; } if (sizeof(udata.au_cond) != uap->length) { return (EINVAL); } mtx_lock(&audit_mtx); if (udata.au_cond == AUC_NOAUDIT) audit_suspended = 1; if (udata.au_cond == AUC_AUDITING) audit_suspended = 0; if (udata.au_cond == AUC_DISABLED) { audit_suspended = 1; mtx_unlock(&audit_mtx); audit_shutdown(); break; } mtx_unlock(&audit_mtx); break; case A_GETCLASS: if (sizeof(udata.au_evclass) != uap->length) return (EINVAL); udata.au_evclass.ec_class = au_event_class( udata.au_evclass.ec_number); break; case A_SETCLASS: if (sizeof(udata.au_evclass) != uap->length) return (EINVAL); au_evclassmap_insert(udata.au_evclass.ec_number, udata.au_evclass.ec_class); break; case A_GETPINFO: if ((sizeof(udata.au_aupinfo) != uap->length) || IS_NOT_VALID_PID(udata.au_aupinfo.ap_pid)) return (EINVAL); if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL) return (ESRCH); scred = kauth_cred_proc_ref(tp); if (scred->cr_audit.as_aia_p->ai_termid.at_type == AU_IPv6) { kauth_cred_unref(&scred); proc_rele(tp); return (EINVAL); } udata.au_aupinfo.ap_auid = scred->cr_audit.as_aia_p->ai_auid; udata.au_aupinfo.ap_mask.am_success = scred->cr_audit.as_mask.am_success; udata.au_aupinfo.ap_mask.am_failure = scred->cr_audit.as_mask.am_failure; udata.au_aupinfo.ap_termid.machine = scred->cr_audit.as_aia_p->ai_termid.at_addr[0]; udata.au_aupinfo.ap_termid.port = scred->cr_audit.as_aia_p->ai_termid.at_port; udata.au_aupinfo.ap_asid = scred->cr_audit.as_aia_p->ai_asid; kauth_cred_unref(&scred); proc_rele(tp); tp = PROC_NULL; break; case A_SETPMASK: if ((sizeof(udata.au_aupinfo) != uap->length) || IS_NOT_VALID_PID(udata.au_aupinfo.ap_pid)) return (EINVAL); if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL) return (ESRCH); scred = kauth_cred_proc_ref(tp); bcopy(scred->cr_audit.as_aia_p, &aia, sizeof(aia)); kauth_cred_unref(&scred); aia.ai_mask.am_success = udata.au_aupinfo.ap_mask.am_success; aia.ai_mask.am_failure = udata.au_aupinfo.ap_mask.am_failure; AUDIT_CHECK_IF_KEVENTS_MASK(aia.ai_mask); error = audit_session_setaia(tp, &aia); proc_rele(tp); tp = PROC_NULL; if (error) return (error); break; case A_SETFSIZE: if ((sizeof(udata.au_fstat) != uap->length) || ((udata.au_fstat.af_filesz != 0) && (udata.au_fstat.af_filesz < MIN_AUDIT_FILE_SIZE))) return (EINVAL); mtx_lock(&audit_mtx); audit_fstat.af_filesz = udata.au_fstat.af_filesz; mtx_unlock(&audit_mtx); break; case A_GETFSIZE: if (sizeof(udata.au_fstat) != uap->length) return (EINVAL); mtx_lock(&audit_mtx); udata.au_fstat.af_filesz = audit_fstat.af_filesz; udata.au_fstat.af_currsz = audit_fstat.af_currsz; mtx_unlock(&audit_mtx); break; case A_GETPINFO_ADDR: if ((sizeof(udata.au_aupinfo_addr) != uap->length) || IS_NOT_VALID_PID(udata.au_aupinfo_addr.ap_pid)) return (EINVAL); if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL) return (ESRCH); WARN_IF_AINFO_ADDR_CHANGED(uap->length, sizeof(auditpinfo_addr_t), "auditon(A_GETPINFO_ADDR,...)", "auditpinfo_addr_t"); scred = kauth_cred_proc_ref(tp); udata.au_aupinfo_addr.ap_auid = scred->cr_audit.as_aia_p->ai_auid; udata.au_aupinfo_addr.ap_asid = scred->cr_audit.as_aia_p->ai_asid; udata.au_aupinfo_addr.ap_mask.am_success = scred->cr_audit.as_mask.am_success; udata.au_aupinfo_addr.ap_mask.am_failure = scred->cr_audit.as_mask.am_failure; bcopy(&scred->cr_audit.as_aia_p->ai_termid, &udata.au_aupinfo_addr.ap_termid, sizeof(au_tid_addr_t)); udata.au_aupinfo_addr.ap_flags = scred->cr_audit.as_aia_p->ai_flags; kauth_cred_unref(&scred); proc_rele(tp); tp = PROC_NULL; break; case A_GETKAUDIT: if (sizeof(udata.au_kau_info) != uap->length) return (EINVAL); audit_get_kinfo(&udata.au_kau_info); break; case A_SETKAUDIT: if ((sizeof(udata.au_kau_info) != uap->length) || (udata.au_kau_info.ai_termid.at_type != AU_IPv4 && udata.au_kau_info.ai_termid.at_type != AU_IPv6)) return (EINVAL); audit_set_kinfo(&udata.au_kau_info); break; case A_SENDTRIGGER: if ((sizeof(udata.au_trigger) != uap->length) || (udata.au_trigger < AUDIT_TRIGGER_MIN) || (udata.au_trigger > AUDIT_TRIGGER_MAX)) return (EINVAL); return (audit_send_trigger(udata.au_trigger)); case A_GETSINFO_ADDR: /* Handled above before switch(). */ break; case A_GETSFLAGS: if (sizeof(udata.au_flags) != uap->length) return (EINVAL); bcopy(&(kauth_cred_get()->cr_audit.as_aia_p->ai_flags), &udata.au_flags, sizeof(udata.au_flags)); break; case A_SETSFLAGS: if (sizeof(udata.au_flags) != uap->length) return (EINVAL); bcopy(kauth_cred_get()->cr_audit.as_aia_p, &aia, sizeof(aia)); aia.ai_flags = udata.au_flags; error = audit_session_setaia(p, &aia); if (error) return (error); break; default: return (EINVAL); } /* * Copy data back to userspace for the GET comands. */ switch (uap->cmd) { case A_GETPOLICY: case A_OLDGETPOLICY: case A_GETKMASK: case A_GETQCTRL: case A_OLDGETQCTRL: case A_GETCWD: case A_GETCAR: case A_GETSTAT: case A_GETCOND: case A_OLDGETCOND: case A_GETCLASS: case A_GETPINFO: case A_GETFSIZE: case A_GETPINFO_ADDR: case A_GETKAUDIT: case A_GETSINFO_ADDR: case A_GETSFLAGS: error = copyout((void *)&udata, uap->data, uap->length); if (error) return (ENOSYS); break; } return (0); }
kern_return_t task_name_for_pid( struct task_name_for_pid_args *args) { mach_port_name_t target_tport = args->target_tport; int pid = args->pid; user_addr_t task_addr = args->t; proc_t p = PROC_NULL; task_t t1; mach_port_name_t tret; void * sright; int error = 0, refheld = 0; kauth_cred_t target_cred; AUDIT_MACH_SYSCALL_ENTER(AUE_TASKNAMEFORPID); AUDIT_ARG(pid, pid); AUDIT_ARG(mach_port1, target_tport); t1 = port_name_to_task(target_tport); if (t1 == TASK_NULL) { (void) copyout((char *)&t1, task_addr, sizeof(mach_port_name_t)); AUDIT_MACH_SYSCALL_EXIT(KERN_FAILURE); return(KERN_FAILURE); } p = proc_find(pid); if (p != PROC_NULL) { AUDIT_ARG(process, p); target_cred = kauth_cred_proc_ref(p); refheld = 1; if ((p->p_stat != SZOMB) && ((current_proc() == p) || kauth_cred_issuser(kauth_cred_get()) || ((kauth_cred_getuid(target_cred) == kauth_cred_getuid(kauth_cred_get())) && ((kauth_cred_getruid(target_cred) == kauth_getruid()))))) { if (p->task != TASK_NULL) { task_reference(p->task); #if CONFIG_MACF error = mac_proc_check_get_task_name(kauth_cred_get(), p); if (error) { task_deallocate(p->task); goto noperm; } #endif sright = (void *)convert_task_name_to_port(p->task); tret = ipc_port_copyout_send(sright, get_task_ipcspace(current_task())); } else tret = MACH_PORT_NULL; AUDIT_ARG(mach_port2, tret); (void) copyout((char *)&tret, task_addr, sizeof(mach_port_name_t)); task_deallocate(t1); error = KERN_SUCCESS; goto tnfpout; } } #if CONFIG_MACF noperm: #endif task_deallocate(t1); tret = MACH_PORT_NULL; (void) copyout((char *) &tret, task_addr, sizeof(mach_port_name_t)); error = KERN_FAILURE; tnfpout: if (refheld != 0) kauth_cred_unref(&target_cred); if (p != PROC_NULL) proc_rele(p); AUDIT_MACH_SYSCALL_EXIT(error); return(error); }
int cttyopen(dev_t dev, int flag, __unused int mode, proc_t p) { vnode_t ttyvp = cttyvp(p); struct vfs_context context; int error = 0; int cttyflag, doclose = 0; struct session *sessp; if (ttyvp == NULL) return (ENXIO); context.vc_thread = current_thread(); context.vc_ucred = kauth_cred_proc_ref(p); sessp = proc_session(p); session_lock(sessp); cttyflag = sessp->s_flags & S_CTTYREF; session_unlock(sessp); /* * A little hack--this device, used by many processes, * happens to do an open on another device, which can * cause unhappiness if the second-level open blocks indefinitely * (as could be the case if the master side has hung up). Since * we know that this driver doesn't care about the serializing * opens and closes, we can drop the lock. To avoid opencount leak, * open the vnode only for the first time. */ if (cttyflag == 0) { devsw_unlock(dev, S_IFCHR); error = VNOP_OPEN(ttyvp, flag, &context); devsw_lock(dev, S_IFCHR); if (error) goto out; /* * If S_CTTYREF is set, some other thread did an open * and was able to set the flag, now perform a close, else * set the flag. */ session_lock(sessp); if (cttyflag == (sessp->s_flags & S_CTTYREF)) sessp->s_flags |= S_CTTYREF; else doclose = 1; session_unlock(sessp); /* * We have to take a reference here to make sure a close * gets called during revoke. Note that once a controlling * tty gets opened by this driver, the only way close will * get called is when the session leader , whose controlling * tty is ttyvp, exits and vnode is revoked. We cannot * redirect close from this driver because underlying controlling * terminal might change and close may get redirected to a * wrong vnode causing panic. */ if (doclose) { devsw_unlock(dev, S_IFCHR); VNOP_CLOSE(ttyvp, flag, &context); devsw_lock(dev, S_IFCHR); } else { error = vnode_ref(ttyvp); } } out: session_rele(sessp); vnode_put(ttyvp); kauth_cred_unref(&context.vc_ucred); return (error); }