X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/0a7de7458d150b5d4dffc935ba399be265ef0a1a..a991bd8d3e7fe02dbca0644054bab73c5b75324a:/bsd/kern/kern_exit.c diff --git a/bsd/kern/kern_exit.c b/bsd/kern/kern_exit.c index e958587b4..c38e6a898 100644 --- a/bsd/kern/kern_exit.c +++ b/bsd/kern/kern_exit.c @@ -129,6 +129,7 @@ #include #include +#include #include @@ -152,6 +153,9 @@ void dtrace_proc_exit(proc_t p); #include #endif /* CONFIG_MACF */ +#if CONFIG_MEMORYSTATUS +static void proc_memorystatus_remove(proc_t p); +#endif /* CONFIG_MEMORYSTATUS */ void proc_prepareexit(proc_t p, int rv, boolean_t perf_notify); void gather_populate_corpse_crashinfo(proc_t p, task_t corpse_task, mach_exception_data_type_t code, mach_exception_data_type_t subcode, @@ -174,6 +178,9 @@ extern uint64_t get_task_phys_footprint_limit(task_t); int proc_list_uptrs(void *p, uint64_t *udata_buffer, int size); extern uint64_t task_corpse_get_crashed_thread_id(task_t corpse_task); +ZONE_DECLARE(zombie_zone, "zombie", + sizeof(struct rusage_superset), ZC_NOENCRYPT); + /* * Things which should have prototypes in headers, but don't @@ -188,6 +195,12 @@ kern_return_t task_violated_guard(mach_exception_code_t, mach_exception_subcode_ void delay(int); void gather_rusage_info(proc_t p, rusage_info_current *ru, int flavor); +#if __has_feature(ptrauth_calls) +int exit_with_pac_exception(proc_t p, exception_type_t exception, mach_exception_code_t code, + mach_exception_subcode_t subcode); +#endif /* __has_feature(ptrauth_calls) */ + + /* * NOTE: Source and target may *NOT* overlap! * XXX Should share code with bsd/dev/ppc/unix_signal.c @@ -204,7 +217,7 @@ siginfo_user_to_user32(user_siginfo_t *in, user32_siginfo_t *out) out->si_addr = CAST_DOWN_EXPLICIT(user32_addr_t, in->si_addr); /* following cast works for sival_int because of padding */ out->si_value.sival_ptr = CAST_DOWN_EXPLICIT(user32_addr_t, in->si_value.sival_ptr); - out->si_band = in->si_band; /* range reduction */ + out->si_band = (user32_long_t)in->si_band; /* range reduction */ } void @@ -329,6 +342,14 @@ populate_corpse_crashinfo(proc_t p, task_t corpse_task, struct rusage_superset * uint64_t ledger_network_nonvolatile; uint64_t ledger_network_nonvolatile_compressed; uint64_t ledger_wired_mem; + uint64_t ledger_tagged_footprint; + uint64_t ledger_tagged_footprint_compressed; + uint64_t ledger_media_footprint; + uint64_t ledger_media_footprint_compressed; + uint64_t ledger_graphics_footprint; + uint64_t ledger_graphics_footprint_compressed; + uint64_t ledger_neural_footprint; + uint64_t ledger_neural_footprint_compressed; void *crash_info_ptr = task_get_corpseinfo(corpse_task); @@ -394,16 +415,13 @@ populate_corpse_crashinfo(proc_t p, task_t corpse_task, struct rusage_superset * } if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_PROC_PATH, MAXPATHLEN, &uaddr)) { - char *buf = (char *) kalloc(MAXPATHLEN); - if (buf != NULL) { - bzero(buf, MAXPATHLEN); - proc_pidpathinfo_internal(p, 0, buf, MAXPATHLEN, &retval); - kcdata_memcpy(crash_info_ptr, uaddr, buf, MAXPATHLEN); - kfree(buf, MAXPATHLEN); - } + char *buf = zalloc_flags(ZV_NAMEI, Z_WAITOK | Z_ZERO); + proc_pidpathinfo_internal(p, 0, buf, MAXPATHLEN, &retval); + kcdata_memcpy(crash_info_ptr, uaddr, buf, MAXPATHLEN); + zfree(ZV_NAMEI, buf); } - pflags = p->p_flag & (P_LP64 | P_SUGID); + pflags = p->p_flag & (P_LP64 | P_SUGID | P_TRANSLATED); if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_PROC_FLAGS, sizeof(pflags), &uaddr)) { kcdata_memcpy(crash_info_ptr, uaddr, &pflags, sizeof(pflags)); } @@ -509,6 +527,11 @@ populate_corpse_crashinfo(proc_t p, task_t corpse_task, struct rusage_superset * kcdata_memcpy(crash_info_ptr, uaddr, &p->p_responsible_pid, sizeof(p->p_responsible_pid)); } + if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_PROC_PERSONA_ID, sizeof(uid_t), &uaddr)) { + uid_t persona_id = proc_persona_id(p); + kcdata_memcpy(crash_info_ptr, uaddr, &persona_id, sizeof(persona_id)); + } + #if CONFIG_COALITIONS if (KERN_SUCCESS == kcdata_get_memory_addr_for_array(crash_info_ptr, TASK_CRASHINFO_COALITION_ID, sizeof(uint64_t), COALITION_NUM_TYPES, &uaddr)) { uint64_t coalition_ids[COALITION_NUM_TYPES]; @@ -518,12 +541,60 @@ populate_corpse_crashinfo(proc_t p, task_t corpse_task, struct rusage_superset * #endif /* CONFIG_COALITIONS */ #if CONFIG_MEMORYSTATUS - memstat_dirty_flags = memorystatus_dirty_get(p); + memstat_dirty_flags = memorystatus_dirty_get(p, FALSE); if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_DIRTY_FLAGS, sizeof(memstat_dirty_flags), &uaddr)) { kcdata_memcpy(crash_info_ptr, uaddr, &memstat_dirty_flags, sizeof(memstat_dirty_flags)); } #endif + if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_MEMORY_LIMIT_INCREASE, sizeof(p->p_memlimit_increase), &uaddr)) { + kcdata_memcpy(crash_info_ptr, uaddr, &p->p_memlimit_increase, sizeof(p->p_memlimit_increase)); + } + + if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_LEDGER_TAGGED_FOOTPRINT, sizeof(ledger_tagged_footprint), &uaddr)) { + ledger_tagged_footprint = get_task_tagged_footprint(corpse_task); + kcdata_memcpy(crash_info_ptr, uaddr, &ledger_tagged_footprint, sizeof(ledger_tagged_footprint)); + } + + if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_LEDGER_TAGGED_FOOTPRINT_COMPRESSED, sizeof(ledger_tagged_footprint_compressed), &uaddr)) { + ledger_tagged_footprint_compressed = get_task_tagged_footprint_compressed(corpse_task); + kcdata_memcpy(crash_info_ptr, uaddr, &ledger_tagged_footprint_compressed, sizeof(ledger_tagged_footprint_compressed)); + } + + if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_LEDGER_MEDIA_FOOTPRINT, sizeof(ledger_media_footprint), &uaddr)) { + ledger_media_footprint = get_task_media_footprint(corpse_task); + kcdata_memcpy(crash_info_ptr, uaddr, &ledger_media_footprint, sizeof(ledger_media_footprint)); + } + + if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_LEDGER_MEDIA_FOOTPRINT_COMPRESSED, sizeof(ledger_media_footprint_compressed), &uaddr)) { + ledger_media_footprint_compressed = get_task_media_footprint_compressed(corpse_task); + kcdata_memcpy(crash_info_ptr, uaddr, &ledger_media_footprint_compressed, sizeof(ledger_media_footprint_compressed)); + } + + if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_LEDGER_GRAPHICS_FOOTPRINT, sizeof(ledger_graphics_footprint), &uaddr)) { + ledger_graphics_footprint = get_task_graphics_footprint(corpse_task); + kcdata_memcpy(crash_info_ptr, uaddr, &ledger_graphics_footprint, sizeof(ledger_graphics_footprint)); + } + + if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_LEDGER_GRAPHICS_FOOTPRINT_COMPRESSED, sizeof(ledger_graphics_footprint_compressed), &uaddr)) { + ledger_graphics_footprint_compressed = get_task_graphics_footprint_compressed(corpse_task); + kcdata_memcpy(crash_info_ptr, uaddr, &ledger_graphics_footprint_compressed, sizeof(ledger_graphics_footprint_compressed)); + } + + if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_LEDGER_NEURAL_FOOTPRINT, sizeof(ledger_neural_footprint), &uaddr)) { + ledger_neural_footprint = get_task_neural_footprint(corpse_task); + kcdata_memcpy(crash_info_ptr, uaddr, &ledger_neural_footprint, sizeof(ledger_neural_footprint)); + } + + if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_LEDGER_NEURAL_FOOTPRINT_COMPRESSED, sizeof(ledger_neural_footprint_compressed), &uaddr)) { + ledger_neural_footprint_compressed = get_task_neural_footprint_compressed(corpse_task); + kcdata_memcpy(crash_info_ptr, uaddr, &ledger_neural_footprint_compressed, sizeof(ledger_neural_footprint_compressed)); + } + + if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_MEMORYSTATUS_EFFECTIVE_PRIORITY, sizeof(p->p_memstat_effectivepriority), &uaddr)) { + kcdata_memcpy(crash_info_ptr, uaddr, &p->p_memstat_effectivepriority, sizeof(p->p_memstat_effectivepriority)); + } + if (p->p_exit_reason != OS_REASON_NULL && reason == OS_REASON_NULL) { reason = p->p_exit_reason; } @@ -539,7 +610,7 @@ populate_corpse_crashinfo(proc_t p, task_t corpse_task, struct rusage_superset * } if (reason->osr_kcd_buf != 0) { - uint32_t reason_buf_size = kcdata_memory_get_used_bytes(&reason->osr_kcd_descriptor); + uint32_t reason_buf_size = (uint32_t)kcdata_memory_get_used_bytes(&reason->osr_kcd_descriptor); assert(reason_buf_size != 0); if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, KCDATA_TYPE_NESTED_KCDATA, reason_buf_size, &uaddr)) { @@ -596,7 +667,8 @@ launchd_exit_reason_get_string_desc(os_reason_t exit_reason) return (char *)kcdata_iter_payload(iter); } -static __attribute__((noinline)) void +__abortlike +static void launchd_crashed_panic(proc_t p, int rv) { char *launchd_exit_reason_desc = launchd_exit_reason_get_string_desc(p->p_exit_reason); @@ -765,7 +837,7 @@ void exit(proc_t p, struct exit_args *uap, int *retval) { p->p_xhighbits = ((uint32_t)(uap->rval) & 0xFF000000) >> 24; - exit1(p, W_EXITCODE(uap->rval, 0), retval); + exit1(p, W_EXITCODE((uint32_t)uap->rval, 0), retval); thread_exception_return(); /* NOTREACHED */ @@ -921,6 +993,25 @@ exit_with_reason(proc_t p, int rv, int *retval, boolean_t thread_can_terminate, return 0; } +#if CONFIG_MEMORYSTATUS +/* + * Remove this process from jetsam bands for freezing or exiting. Note this will block, if the process + * is currently being frozen. + * The proc_list_lock is held by the caller. + * NB: If the process should be ineligible for future freezing or jetsaming the caller should first set + * the p_listflag P_LIST_EXITED bit. + */ +static void +proc_memorystatus_remove(proc_t p) +{ + LCK_MTX_ASSERT(proc_list_mlock, LCK_MTX_ASSERT_OWNED); + while (memorystatus_remove(p) == EAGAIN) { + os_log(OS_LOG_DEFAULT, "memorystatus_remove: Process[%d] tried to exit while being frozen. Blocking exit until freeze completes.", p->p_pid); + msleep(&p->p_memstat_state, proc_list_mlock, PWAIT, "proc_memorystatus_remove", NULL); + } +} +#endif + void proc_prepareexit(proc_t p, int rv, boolean_t perf_notify) { @@ -1009,29 +1100,26 @@ skipcheck: * * If the zombie allocation fails, just punt the stats. */ - MALLOC_ZONE(rup, struct rusage_superset *, - sizeof(*rup), M_ZOMBIE, M_WAITOK); - if (rup != NULL) { - gather_rusage_info(p, &rup->ri, RUSAGE_INFO_CURRENT); - rup->ri.ri_phys_footprint = 0; - rup->ri.ri_proc_exit_abstime = mach_absolute_time(); + rup = zalloc(zombie_zone); + gather_rusage_info(p, &rup->ri, RUSAGE_INFO_CURRENT); + rup->ri.ri_phys_footprint = 0; + rup->ri.ri_proc_exit_abstime = mach_absolute_time(); + /* + * Make the rusage_info visible to external observers + * only after it has been completely filled in. + */ + p->p_ru = rup; - /* - * Make the rusage_info visible to external observers - * only after it has been completely filled in. - */ - p->p_ru = rup; - } if (create_corpse) { int est_knotes = 0, num_knotes = 0; uint64_t *buffer = NULL; - int buf_size = 0; + uint32_t buf_size = 0; /* Get all the udata pointers from kqueue */ est_knotes = kevent_proc_copy_uptrs(p, NULL, 0); if (est_knotes > 0) { - buf_size = (est_knotes + 32) * sizeof(uint64_t); - buffer = (uint64_t *) kalloc(buf_size); + buf_size = (uint32_t)((est_knotes + 32) * sizeof(uint64_t)); + buffer = kheap_alloc(KHEAP_TEMP, buf_size, Z_WAITOK); num_knotes = kevent_proc_copy_uptrs(p, buffer, buf_size); if (num_knotes > est_knotes + 32) { num_knotes = est_knotes + 32; @@ -1043,7 +1131,7 @@ skipcheck: populate_corpse_crashinfo(p, p->task, rup, code, subcode, buffer, num_knotes, NULL); if (buffer != NULL) { - kfree(buffer, buf_size); + kheap_free(KHEAP_TEMP, buffer, buf_size); } } /* @@ -1056,7 +1144,7 @@ skipcheck: proc_list_lock(); #if CONFIG_MEMORYSTATUS - memorystatus_remove(p, TRUE); + proc_memorystatus_remove(p); #endif LIST_REMOVE(p, p_list); @@ -1066,7 +1154,6 @@ skipcheck: proc_list_unlock(); - #ifdef PGINPROF vmsizmon(); #endif @@ -1140,8 +1227,6 @@ proc_exit(proc_t p) dtrace_proc_exit(p); #endif - nspace_proc_exit(p); - /* * need to cancel async IO requests that can be cancelled and wait for those * already active. MAY BLOCK! @@ -1179,6 +1264,14 @@ proc_exit(proc_t p) throttle_lowpri_io(0); } + if (p->p_lflag & P_LNSPACE_RESOLVER) { + /* + * The namespace resolver is exiting; there may be + * outstanding materialization requests to clean up. + */ + nspace_resolver_exited(p); + } + #if SYSV_SHM /* Close ref SYSV Shared memory*/ if (p->vm_shm) { @@ -1214,17 +1307,6 @@ proc_exit(proc_t p) if ((tp != TTY_NULL) && (tp->t_session == sessp)) { session_unlock(sessp); - /* - * We're going to SIGHUP the foreground process - * group. It can't change from this point on - * until the revoke is complete. - * The process group changes under both the tty - * lock and proc_list_lock but we need only one - */ - tty_lock(tp); - ttysetpgrphup(tp); - tty_unlock(tp); - tty_pgsignal(tp, SIGHUP, 1); session_lock(sessp); @@ -1246,7 +1328,8 @@ proc_exit(proc_t p) (void) ttywait(tp); tty_unlock(tp); } - context.vc_thread = proc_thread(p); /* XXX */ + + context.vc_thread = NULL; context.vc_ucred = kauth_cred_proc_ref(p); VNOP_REVOKE(ttyvp, REVOKEALL, &context); if (cttyflag) { @@ -1264,14 +1347,6 @@ proc_exit(proc_t p) ttyvp = NULLVP; } if (tp) { - /* - * This is cleared even if not set. This is also done in - * spec_close to ensure that the flag is cleared. - */ - tty_lock(tp); - ttyclrpgrphup(tp); - tty_unlock(tp); - ttyfree(tp); } } @@ -1285,7 +1360,13 @@ proc_exit(proc_t p) fixjobc(p, pg, 0); pg_rele(pg); - p->p_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; + /* + * Change RLIMIT_FSIZE for accounting/debugging. proc_limitsetcur_internal() will COW the current plimit + * before making changes if the current plimit is shared. The COW'ed plimit will be freed + * below by calling proc_limitdrop(). + */ + proc_limitsetcur_internal(p, RLIMIT_FSIZE, RLIM_INFINITY); + (void)acct_process(p); proc_list_lock(); @@ -1442,14 +1523,13 @@ proc_exit(proc_t p) /* * Other substructures are freed from wait(). */ - FREE_ZONE(p->p_stats, sizeof *p->p_stats, M_PSTATS); + zfree(proc_stats_zone, p->p_stats); p->p_stats = NULL; - FREE_ZONE(p->p_sigacts, sizeof *p->p_sigacts, M_SIGACTS); + zfree(proc_sigacts_zone, p->p_sigacts); p->p_sigacts = NULL; - proc_limitdrop(p, 1); - p->p_limit = NULL; + proc_limitdrop(p); /* * Finish up by terminating the task @@ -1696,7 +1776,7 @@ reap_child_locked(proc_t parent, proc_t child, int deadparent, int reparentedtoi ruadd(&parent->p_stats->p_cru, &child->p_ru->ru); update_rusage_info_child(&parent->p_stats->ri_child, &child->p_ru->ri); proc_unlock(parent); - FREE_ZONE(child->p_ru, sizeof *child->p_ru, M_ZOMBIE); + zfree(zombie_zone, child->p_ru); child->p_ru = NULL; } else { printf("Warning : lost p_ru for %s\n", child->p_comm); @@ -1721,15 +1801,6 @@ reap_child_locked(proc_t parent, proc_t child, int deadparent, int reparentedtoi os_reason_free(child->p_exit_reason); - /* - * Free up credentials. - */ - if (IS_VALID_CRED(child->p_ucred)) { - kauth_cred_unref(&child->p_ucred); - } - - /* XXXX Note NOT SAFE TO USE p_ucred from this point onwards */ - /* * Finally finished with old proc entry. * Unlink it from its process group and free it. @@ -1763,6 +1834,14 @@ reap_child_locked(proc_t parent, proc_t child, int deadparent, int reparentedtoi proc_list_unlock(); + /* + * Free up credentials. + */ + if (IS_VALID_CRED(child->p_ucred)) { + kauth_cred_t tmp_ucred = child->p_ucred; + kauth_cred_unref(&tmp_ucred); + child->p_ucred = NOCRED; + } lck_mtx_destroy(&child->p_mlock, proc_mlock_grp); lck_mtx_destroy(&child->p_ucred_mlock, proc_ucred_mlock_grp); @@ -1772,7 +1851,7 @@ reap_child_locked(proc_t parent, proc_t child, int deadparent, int reparentedtoi #endif lck_spin_destroy(&child->p_slock, proc_slock_grp); - FREE_ZONE(child, sizeof *child, M_PROC); + zfree(proc_zone, child); if ((locked == 1) && (droplock == 0)) { proc_list_lock(); } @@ -2143,14 +2222,20 @@ loop1: #endif siginfo.si_signo = SIGCHLD; siginfo.si_pid = p->p_pid; - siginfo.si_status = (WEXITSTATUS(p->p_xstat) & 0x00FFFFFF) | (((uint32_t)(p->p_xhighbits) << 24) & 0xFF000000); - p->p_xhighbits = 0; + + /* If the child terminated abnormally due to a signal, the signum + * needs to be preserved in the exit status. + */ if (WIFSIGNALED(p->p_xstat)) { siginfo.si_code = WCOREDUMP(p->p_xstat) ? CLD_DUMPED : CLD_KILLED; + siginfo.si_status = WTERMSIG(p->p_xstat); } else { siginfo.si_code = CLD_EXITED; + siginfo.si_status = WEXITSTATUS(p->p_xstat) & 0x00FFFFFF; } + siginfo.si_status |= (((uint32_t)(p->p_xhighbits) << 24) & 0xFF000000); + p->p_xhighbits = 0; if ((error = copyoutsiginfo(&siginfo, caller64, uap->infop)) != 0) { @@ -2327,7 +2412,7 @@ proc_reparentlocked(proc_t child, proc_t parent, int signallable, int locked) } #endif oldparent->p_childrencnt--; -#if __PROC_INTERNAL_DEBUG1 +#if __PROC_INTERNAL_DEBUG if (oldparent->p_childrencnt < 0) { panic("process children count -ve\n"); } @@ -2411,7 +2496,7 @@ vfork_exit_internal(proc_t p, int rv, int forceexit) proc_list_lock(); #if CONFIG_MEMORYSTATUS - memorystatus_remove(p, TRUE); + proc_memorystatus_remove(p); #endif LIST_REMOVE(p, p_list); @@ -2440,9 +2525,7 @@ vfork_exit_internal(proc_t p, int rv, int forceexit) struct session *sessp; struct rusage_superset *rup; - /* XXX Zombie allocation may fail, in which case stats get lost */ - MALLOC_ZONE(rup, struct rusage_superset *, - sizeof(*rup), M_ZOMBIE, M_WAITOK); + rup = zalloc(zombie_zone); proc_refdrain(p); @@ -2454,88 +2537,7 @@ vfork_exit_internal(proc_t p, int rv, int forceexit) sessp = proc_session(p); if (SESS_LEADER(p, sessp)) { - if (sessp->s_ttyvp != NULLVP) { - struct vnode *ttyvp; - int ttyvid; - int cttyflag = 0; - struct vfs_context context; - struct tty *tp; - - /* - * Controlling process. - * Signal foreground pgrp, - * drain controlling terminal - * and revoke access to controlling terminal. - */ - session_lock(sessp); - tp = SESSION_TP(sessp); - if ((tp != TTY_NULL) && (tp->t_session == sessp)) { - session_unlock(sessp); - - /* - * We're going to SIGHUP the foreground process - * group. It can't change from this point on - * until the revoke is complete. - * The process group changes under both the tty - * lock and proc_list_lock but we need only one - */ - tty_lock(tp); - ttysetpgrphup(tp); - tty_unlock(tp); - - tty_pgsignal(tp, SIGHUP, 1); - - session_lock(sessp); - tp = SESSION_TP(sessp); - } - cttyflag = sessp->s_flags & S_CTTYREF; - sessp->s_flags &= ~S_CTTYREF; - ttyvp = sessp->s_ttyvp; - ttyvid = sessp->s_ttyvid; - sessp->s_ttyvp = NULL; - sessp->s_ttyvid = 0; - sessp->s_ttyp = TTY_NULL; - sessp->s_ttypgrpid = NO_PID; - session_unlock(sessp); - - if ((ttyvp != NULLVP) && (vnode_getwithvid(ttyvp, ttyvid) == 0)) { - if (tp != TTY_NULL) { - tty_lock(tp); - (void) ttywait(tp); - tty_unlock(tp); - } - context.vc_thread = proc_thread(p); /* XXX */ - context.vc_ucred = kauth_cred_proc_ref(p); - VNOP_REVOKE(ttyvp, REVOKEALL, &context); - if (cttyflag) { - /* - * Release the extra usecount taken in cttyopen. - * usecount should be released after VNOP_REVOKE is called. - * This usecount was taken to ensure that - * the VNOP_REVOKE results in a close to - * the tty since cttyclose is a no-op. - */ - vnode_rele(ttyvp); - } - vnode_put(ttyvp); - kauth_cred_unref(&context.vc_ucred); - ttyvp = NULLVP; - } - if (tp) { - /* - * This is cleared even if not set. This is also done in - * spec_close to ensure that the flag is cleared. - */ - tty_lock(tp); - ttyclrpgrphup(tp); - tty_unlock(tp); - - ttyfree(tp); - } - } - session_lock(sessp); - sessp->s_leader = NULL; - session_unlock(sessp); + panic("vfork child is session leader"); } session_rele(sessp); @@ -2543,9 +2545,15 @@ vfork_exit_internal(proc_t p, int rv, int forceexit) fixjobc(p, pg, 0); pg_rele(pg); - p->p_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; + /* + * Change RLIMIT_FSIZE for accounting/debugging. proc_limitsetcur_internal() will COW the current plimit + * before making changes if the current plimit is shared. The COW'ed plimit will be freed + * below by calling proc_limitdrop(). + */ + proc_limitsetcur_internal(p, RLIMIT_FSIZE, RLIM_INFINITY); proc_list_lock(); + proc_childdrainstart(p); while ((q = p->p_children.lh_first) != NULL) { if (q->p_stat == SZOMB) { @@ -2711,14 +2719,16 @@ vfork_exit_internal(proc_t p, int rv, int forceexit) /* * Other substructures are freed from wait(). */ - FREE_ZONE(p->p_stats, sizeof *p->p_stats, M_PSTATS); + zfree(proc_stats_zone, p->p_stats); p->p_stats = NULL; - FREE_ZONE(p->p_sigacts, sizeof *p->p_sigacts, M_SIGACTS); + zfree(proc_sigacts_zone, p->p_sigacts); p->p_sigacts = NULL; - proc_limitdrop(p, 1); - p->p_limit = NULL; + FREE(p->p_subsystem_root_path, M_SBUF); + p->p_subsystem_root_path = NULL; + + proc_limitdrop(p); /* * Finish up by terminating the task @@ -2830,28 +2840,28 @@ munge_user32_rusage(struct rusage *a_rusage_p, struct user32_rusage *a_user_rusa bzero(a_user_rusage_p, sizeof(struct user32_rusage)); /* timeval changes size, so utime and stime need special handling */ - a_user_rusage_p->ru_utime.tv_sec = a_rusage_p->ru_utime.tv_sec; + a_user_rusage_p->ru_utime.tv_sec = (user32_time_t)a_rusage_p->ru_utime.tv_sec; a_user_rusage_p->ru_utime.tv_usec = a_rusage_p->ru_utime.tv_usec; - a_user_rusage_p->ru_stime.tv_sec = a_rusage_p->ru_stime.tv_sec; + a_user_rusage_p->ru_stime.tv_sec = (user32_time_t)a_rusage_p->ru_stime.tv_sec; a_user_rusage_p->ru_stime.tv_usec = a_rusage_p->ru_stime.tv_usec; /* * everything else can be a direct assign. We currently ignore * the loss of precision */ - a_user_rusage_p->ru_maxrss = a_rusage_p->ru_maxrss; - a_user_rusage_p->ru_ixrss = a_rusage_p->ru_ixrss; - a_user_rusage_p->ru_idrss = a_rusage_p->ru_idrss; - a_user_rusage_p->ru_isrss = a_rusage_p->ru_isrss; - a_user_rusage_p->ru_minflt = a_rusage_p->ru_minflt; - a_user_rusage_p->ru_majflt = a_rusage_p->ru_majflt; - a_user_rusage_p->ru_nswap = a_rusage_p->ru_nswap; - a_user_rusage_p->ru_inblock = a_rusage_p->ru_inblock; - a_user_rusage_p->ru_oublock = a_rusage_p->ru_oublock; - a_user_rusage_p->ru_msgsnd = a_rusage_p->ru_msgsnd; - a_user_rusage_p->ru_msgrcv = a_rusage_p->ru_msgrcv; - a_user_rusage_p->ru_nsignals = a_rusage_p->ru_nsignals; - a_user_rusage_p->ru_nvcsw = a_rusage_p->ru_nvcsw; - a_user_rusage_p->ru_nivcsw = a_rusage_p->ru_nivcsw; + a_user_rusage_p->ru_maxrss = (user32_long_t)a_rusage_p->ru_maxrss; + a_user_rusage_p->ru_ixrss = (user32_long_t)a_rusage_p->ru_ixrss; + a_user_rusage_p->ru_idrss = (user32_long_t)a_rusage_p->ru_idrss; + a_user_rusage_p->ru_isrss = (user32_long_t)a_rusage_p->ru_isrss; + a_user_rusage_p->ru_minflt = (user32_long_t)a_rusage_p->ru_minflt; + a_user_rusage_p->ru_majflt = (user32_long_t)a_rusage_p->ru_majflt; + a_user_rusage_p->ru_nswap = (user32_long_t)a_rusage_p->ru_nswap; + a_user_rusage_p->ru_inblock = (user32_long_t)a_rusage_p->ru_inblock; + a_user_rusage_p->ru_oublock = (user32_long_t)a_rusage_p->ru_oublock; + a_user_rusage_p->ru_msgsnd = (user32_long_t)a_rusage_p->ru_msgsnd; + a_user_rusage_p->ru_msgrcv = (user32_long_t)a_rusage_p->ru_msgrcv; + a_user_rusage_p->ru_nsignals = (user32_long_t)a_rusage_p->ru_nsignals; + a_user_rusage_p->ru_nvcsw = (user32_long_t)a_rusage_p->ru_nvcsw; + a_user_rusage_p->ru_nivcsw = (user32_long_t)a_rusage_p->ru_nivcsw; } void @@ -2869,3 +2879,23 @@ kdp_wait4_find_process(thread_t thread, __unused event64_t wait_event, thread_wa // See man wait4 for other valid wait4 arguments. waitinfo->owner = args->pid; } + +#if __has_feature(ptrauth_calls) +int +exit_with_pac_exception(proc_t p, exception_type_t exception, mach_exception_code_t code, + mach_exception_subcode_t subcode) +{ + thread_t self = current_thread(); + struct uthread *ut = get_bsdthread_info(self); + + os_reason_t exception_reason = os_reason_create(OS_REASON_PAC_EXCEPTION, (uint64_t)code); + assert(exception_reason != OS_REASON_NULL); + exception_reason->osr_flags |= OS_REASON_FLAG_GENERATE_CRASH_REPORT; + ut->uu_exception = exception; + ut->uu_code = code; + ut->uu_subcode = subcode; + + return exit_with_reason(p, W_EXITCODE(0, SIGKILL), (int *)NULL, TRUE, FALSE, + 0, exception_reason); +} +#endif /* __has_feature(ptrauth_calls) */