+#if __arm64__
+extern int legacy_footprint_entitlement_mode;
+static inline void
+proc_legacy_footprint_entitled(proc_t p, task_t task, const char *caller)
+{
+#pragma unused(p, caller)
+ boolean_t legacy_footprint_entitled;
+
+ switch (legacy_footprint_entitlement_mode) {
+ case LEGACY_FOOTPRINT_ENTITLEMENT_IGNORE:
+ /* the entitlement is ignored */
+ break;
+ case LEGACY_FOOTPRINT_ENTITLEMENT_IOS11_ACCT:
+ /* the entitlement grants iOS11 legacy accounting */
+ legacy_footprint_entitled = IOTaskHasEntitlement(task,
+ "com.apple.private.memory.legacy_footprint");
+ if (legacy_footprint_entitled) {
+ task_set_legacy_footprint(task);
+ }
+ break;
+ case LEGACY_FOOTPRINT_ENTITLEMENT_LIMIT_INCREASE:
+ /* the entitlement grants a footprint limit increase */
+ legacy_footprint_entitled = IOTaskHasEntitlement(task,
+ "com.apple.private.memory.legacy_footprint");
+ if (legacy_footprint_entitled) {
+ task_set_extra_footprint_limit(task);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static inline void
+proc_ios13extended_footprint_entitled(proc_t p, task_t task, const char *caller)
+{
+#pragma unused(p, caller)
+ boolean_t ios13extended_footprint_entitled;
+
+ /* the entitlement grants a footprint limit increase */
+ ios13extended_footprint_entitled = IOTaskHasEntitlement(task,
+ "com.apple.developer.memory.ios13extended_footprint");
+ if (ios13extended_footprint_entitled) {
+ task_set_ios13extended_footprint_limit(task);
+ }
+}
+#endif /* __arm64__ */
+
+/*
+ * Apply a modification on the proc's kauth cred until it converges.
+ *
+ * `update` consumes its argument to return a new kauth cred.
+ */
+static void
+apply_kauth_cred_update(proc_t p,
+ kauth_cred_t (^update)(kauth_cred_t orig_cred))
+{
+ kauth_cred_t my_cred, my_new_cred;
+
+ my_cred = kauth_cred_proc_ref(p);
+ for (;;) {
+ my_new_cred = update(my_cred);
+ if (my_cred == my_new_cred) {
+ kauth_cred_unref(&my_new_cred);
+ break;
+ }
+
+ /* try update cred on proc */
+ proc_ucred_lock(p);
+
+ if (p->p_ucred == my_cred) {
+ /* base pointer didn't change, donate our ref */
+ p->p_ucred = my_new_cred;
+ PROC_UPDATE_CREDS_ONPROC(p);
+ proc_ucred_unlock(p);
+
+ /* drop p->p_ucred reference */
+ kauth_cred_unref(&my_cred);
+ break;
+ }
+
+ /* base pointer changed, retry */
+ my_cred = p->p_ucred;
+ kauth_cred_ref(my_cred);
+ proc_ucred_unlock(p);
+
+ kauth_cred_unref(&my_new_cred);
+ }
+}
+
+static int
+spawn_posix_cred_adopt(proc_t p,
+ struct _posix_spawn_posix_cred_info *px_pcred_info)
+{
+ int error = 0;
+
+ if (px_pcred_info->pspci_flags & POSIX_SPAWN_POSIX_CRED_GID) {
+ struct setgid_args args = {
+ .gid = px_pcred_info->pspci_gid,
+ };
+ error = setgid(p, &args, NULL);
+ if (error) {
+ return error;
+ }
+ }
+
+ if (px_pcred_info->pspci_flags & POSIX_SPAWN_POSIX_CRED_GROUPS) {
+ error = setgroups_internal(p,
+ px_pcred_info->pspci_ngroups,
+ px_pcred_info->pspci_groups,
+ px_pcred_info->pspci_gmuid);
+ if (error) {
+ return error;
+ }
+ }
+
+ if (px_pcred_info->pspci_flags & POSIX_SPAWN_POSIX_CRED_UID) {
+ struct setuid_args args = {
+ .uid = px_pcred_info->pspci_uid,
+ };
+ error = setuid(p, &args, NULL);
+ if (error) {
+ return error;
+ }
+ }
+ return 0;
+}
+