]> git.saurik.com Git - apple/xnu.git/commitdiff
xnu-6153.61.1.tar.gz macos-10152 v6153.61.1
authorApple <opensource@apple.com>
Tue, 28 Apr 2020 21:24:20 +0000 (21:24 +0000)
committerApple <opensource@apple.com>
Tue, 28 Apr 2020 21:24:20 +0000 (21:24 +0000)
89 files changed:
EXTERNAL_HEADERS/img4/api.h
EXTERNAL_HEADERS/img4/environment.h
EXTERNAL_HEADERS/img4/img4.h
bsd/dev/dtrace/dtrace.c
bsd/kern/kern_control.c
bsd/kern/kern_exec.c
bsd/kern/kern_proc.c
bsd/kern/kern_sysctl.c
bsd/kern/subr_prf.c
bsd/kern/uipc_mbuf.c
bsd/kern/uipc_socket.c
bsd/kern/uipc_syscalls.c
bsd/libkern/libkern.h
bsd/miscfs/devfs/devfs_fdesc_support.c
bsd/net/dlil.c
bsd/net/if_ipsec.c
bsd/net/if_utun.c
bsd/net/necp.c
bsd/net/necp.h
bsd/net/pktsched/pktsched_netem.c
bsd/net/route.c
bsd/net/rtsock.c
bsd/netinet/flow_divert.c
bsd/netinet/ip_fw2.c
bsd/netinet/mptcp.c
bsd/netinet/mptcp_subr.c
bsd/netinet/tcp_input.c
bsd/netinet/tcp_timer.c
bsd/netinet6/ip6_fw.c
bsd/nfs/nfs_socket.c
bsd/pthread/pthread_workqueue.c
bsd/pthread/workqueue_internal.h
bsd/sys/codesign.h
bsd/sys/dtrace_impl.h
bsd/sys/persona.h
bsd/tests/bsd_tests.c
bsd/tests/ctrr_test_sysctl.c [new file with mode: 0644]
bsd/vfs/kpi_vfs.c
bsd/vfs/vfs_lookup.c
bsd/vfs/vfs_syscalls.c
bsd/vfs/vfs_xattr.c
config/IOKit.arm.exports
config/IOKit.arm64.exports
config/IOKit.x86_64.exports
config/Libkern.exports
config/MasterVersion
iokit/IOKit/IOBufferMemoryDescriptor.h
iokit/Kernel/IOBufferMemoryDescriptor.cpp
iokit/Kernel/IOPMrootDomain.cpp
iokit/Kernel/IOUserClient.cpp
libkern/OSKextVersion.c
libkern/libkern/img4/interface.h
libkern/net/inet_ntop.c
libkern/os/log.c
osfmk/arm/model_dep.c
osfmk/arm/pmap.c
osfmk/arm/pmap.h
osfmk/console/serial_console.c
osfmk/device/device.defs
osfmk/device/device_types.h
osfmk/i386/AT386/model_dep.c
osfmk/i386/i386_init.c
osfmk/kdp/kdp_core.c
osfmk/kdp/kdp_core.h
osfmk/kern/cs_blobs.h
osfmk/kern/ipc_tt.c
osfmk/kern/kern_stackshot.c
osfmk/kern/misc_protos.h
osfmk/kern/startup.c
osfmk/kern/task.c
osfmk/kern/task.h
osfmk/kern/test_lock.c
osfmk/mach/arm/thread_status.h
osfmk/vm/vm_kern.c
osfmk/vm/vm_kern.h
osfmk/vm/vm_map.c
osfmk/vm/vm_map_store_rb.c
osfmk/vm/vm_page.h
san/kasan.c
san/ubsan.c
tests/Makefile
tests/route_output_stack_oflow_56033075.c [new file with mode: 0644]
tests/stackshot_accuracy.m [new file with mode: 0644]
tests/sysctl_get_owned_vmobjects.c
tests/sysctl_wire_limits.c [new file with mode: 0644]
tests/tcp_input_outputopts_uaf_56155583.c [new file with mode: 0644]
tools/lldbmacros/ioreg.py
tools/lldbmacros/xnu.py
tools/lldbmacros/xnutriage.py

index 9cd1d4e4b6055d70b553848fa4bba9c26c8a80cf..861f4e38e61ce855271ee398e9f33c4e01c05392 100644 (file)
@@ -40,7 +40,7 @@
  * individual preprocessor macros in this header that declare new behavior as
  * required.
  */
-#define IMG4_API_VERSION (20190125u)
+#define IMG4_API_VERSION (20191001u)
 
 #if !defined(KERNEL) && !IMG4_PROJECT_BUILD
 #define IMG4_API_AVAILABLE_20180112 \
                API_AVAILABLE(ios(12.2), tvos(12.2), watchos(5.2))
 #define IMG4_API_AVAILABLE_20190125 \
                API_AVAILABLE(macos(10.15), ios(13.0), tvos(13.0), watchos(6.0))
+#define IMG4_API_AVAILABLE_20191001 \
+               API_AVAILABLE(macos(10.15.2), ios(13.3), tvos(13.3), watchos(6.1.1))
 #else
 #define IMG4_API_AVAILABLE_20180112
 #define IMG4_API_AVAILABLE_20181004
 #define IMG4_API_AVAILABLE_20181106
 #define IMG4_API_AVAILABLE_20190125
+#define IMG4_API_AVAILABLE_20191001
 #endif // !defined(KERNEL) && !IMG4_PROJECT_BUILD
 
 #if !defined(OS_CLOSED_ENUM)
index 6942de840528b08af3a6d83de0e570dd48bd9778..98d202444a7fe6cc5e2e78b54b35882c7d94042e 100644 (file)
 #include "tapi.h"
 #endif
 
+/*!
+ * @const IMG4_IDENTITY_VERSION
+ * The version of the {@link img4_identity_t} supported by the implementation.
+ */
+#define IMG4_IDENTITY_VERSION (0u)
+
+/*!
+ * @const IMG4_ENVIRONMENT_LENGTH
+ * The minimum length for an allocation which can accommodate an
+ * img4_environment_t structure. This is the minimum length which must be given
+ * to {@link img4_environment_init_identity}.
+ */
+#define IMG4_ENVIRONMENT_LENGTH (160ul)
+
+/*!
+ * @const IMG4_IDENTITY_CRYPTO_SHA1
+ * The device-tree string indicating that the identity requires SHA1.
+ */
+#define IMG4_IDENTITY_CRYPTO_SHA1 "sha1"
+
+/*!
+ * @const IMG4_IDENTITY_CRYPTO_SHA2_384
+ * The device-tree string indicating that the identity requires SHA2-384.
+ */
+#define IMG4_IDENTITY_CRYPTO_SHA2_384 "sha2-384"
+
 /*!
  * @typedef img4_environment_t
  * An opaque type describing an Image4 environment.
  */
 typedef struct _img4_environment img4_environment_t;
 
+/*!
+ * @typedef img4_identity_t
+ * A structure describing a specific Image4 identity comprised of user-supplied
+ * identifiers.
+ *
+ * @field i4id_version
+ * The version of the identity structure; initialize to
+ * {@link IMG4_IDENTITY_VERSION}
+ *
+ * @field i4id_algo
+ * A string identifying the chosen crypto algorithm as represented in the device
+ * tree. Currently valid values are:
+ *
+ *     - {@link IMG4_IDENTITY_CRYPTO_SHA1}
+ *     - {@link IMG4_IDENTITY_CRYPTO_SHA2_384}
+ *
+ * @field i4id_cepo
+ * The minimum certificate epoch required,
+ *
+ * @field i4id_bord
+ * The board identifier.
+ *
+ * @field i4id_chip
+ * The chip identifier.
+ *
+ * @field i4id_ecid
+ * The unique chip identifier.
+ *
+ * @field i4id_sdom
+ * The security domain.
+ *
+ * @field i4id_cpro
+ * The certificate production status.
+ *
+ * @field i4id_csec
+ * The certificate security mode.
+ *
+ * @field i4id_epro
+ * The effective production status.
+ *
+ * @field i4id_esec
+ * The effective security mode.
+ */
+IMG4_API_AVAILABLE_20191001
+typedef struct _img4_identity {
+       img4_struct_version_t i4id_version;
+       char i4id_algo[12];
+       uint32_t i4id_cepo;
+       uint32_t i4id_bord;
+       uint32_t i4id_chip;
+       uint64_t i4id_ecid;
+       uint32_t i4id_sdom;
+       bool i4id_cpro;
+       bool i4id_csec;
+       bool i4id_epro;
+       bool i4id_esec;
+} img4_identity_t;
+
 /*!
  * @const IMG4_ENVIRONMENT_PLATFORM
  * The environment for the host that uses the default platform implementation to
@@ -50,4 +134,47 @@ const struct _img4_environment _img4_environment_trust_cache;
 #define IMG4_ENVIRONMENT_TRUST_CACHE (img4if->i4if_environment_trust_cache)
 #endif
 
+/*!
+ * @function img4_environment_init_identity
+ * Initializes a caller-supplied environment with custom identity information.
+ * This may be used for performing test evaluations or evaluations against
+ * environments not yet supported by the implementation.
+ *
+ * @param i4e
+ * A pointer to the storage which will hold the custom environment.
+ *
+ * @param len
+ * The length of the storage referenced by {@link i4e}. This must be at least
+ * {@link IMG4_ENVIRONMENT_LENGTH} bytes.
+ *
+ * @param i4id
+ * The identity with which to initialize the environment. The resulting
+ * environment object will provide these identitifers to the evaluator.
+ *
+ * @result
+ * Upon success, zero is returned. The implementation may also return one of the
+ * following error codes directly:
+ *
+ *     [EOVERFLOW]    The length provided is insufficient to initialize an
+ *                    environment structure
+ *
+ * @discussion
+ * When the resulting environment is given to {@link img4_get_trusted_payload}
+ * or {@link img4_get_trusted_external_payload}, the trust evaluation proceeds
+ * as though it were creating a new chain of trust and therefore acts as though
+ * {@link I4F_FIRST_STAGE} was given to {@link img4_init}. No prior stage of
+ * secure boot will be consulted for evaluation, and mix-n-match will be
+ * presumed to be permitted.
+ */
+#if !XNU_KERNEL_PRIVATE
+IMG4_API_AVAILABLE_20191001
+OS_EXPORT OS_WARN_RESULT OS_NONNULL1 OS_NONNULL3
+errno_t
+img4_environment_init_identity(img4_environment_t *i4e, size_t len,
+               const img4_identity_t *i4id);
+#else
+#define img4_environment_init_identity(...) \
+               (img4if->i4if_v4.environment_init_identity(__VA_ARGS__))
+#endif
+
 #endif // __IMG4_ENVIRONMENT_H
index cb68c4645e41c364f826df071a5941944d6d2f81..3d995b10f3f4812f4aef762678b2edfe28e86982 100644 (file)
@@ -453,9 +453,6 @@ img4_set_nonce_domain(img4_t *i4, const img4_nonce_domain_t *nd);
  *                  in the manifest
  *     [EIO]        The payload could not be fetched
  *
- * Additionally, errors from the routines specified in the
- * {@link img4_environment_t} may be returned.
- *
  * @discussion
  * This routine will perform the following validation:
  *
@@ -543,7 +540,7 @@ img4_get_trusted_payload(img4_t *i4, img4_tag_t tag,
  *
  * @discussion
  * This routine performs the same validation steps as
- * {@link img4_get_trusted_payload}.
+ * {@link img4_get_trusted_payload} and has the same caveats.
  */
 #if !XNU_KERNEL_PRIVATE
 IMG4_API_AVAILABLE_20180112
index 9cc3b6094762fd468df658ceb333d3aba4bc458f..a48f1e6f78d14bf43ab05bbbd8196b44a380ff6d 100644 (file)
@@ -10634,18 +10634,35 @@ dtrace_difo_release(dtrace_difo_t *dp, dtrace_vstate_t *vstate)
 /*
  * DTrace Format Functions
  */
+
+static dtrace_format_t*
+dtrace_format_new(char *str)
+{
+       dtrace_format_t *fmt = NULL;
+       size_t bufsize = strlen(str) + 1;
+
+       fmt = kmem_zalloc(sizeof(*fmt) + bufsize, KM_SLEEP);
+
+       fmt->dtf_refcount = 1;
+       (void) strlcpy(fmt->dtf_str, str, bufsize);
+
+       return fmt;
+}
+
 static uint16_t
 dtrace_format_add(dtrace_state_t *state, char *str)
 {
-       char *fmt, **new;
-       uint16_t ndx, len = strlen(str) + 1;
-
-       fmt = kmem_zalloc(len, KM_SLEEP);
-       bcopy(str, fmt, len);
+       dtrace_format_t **new;
+       uint16_t ndx;
 
        for (ndx = 0; ndx < state->dts_nformats; ndx++) {
                if (state->dts_formats[ndx] == NULL) {
-                       state->dts_formats[ndx] = fmt;
+                       state->dts_formats[ndx] = dtrace_format_new(str);
+                       return (ndx + 1);
+               }
+               else if (strcmp(state->dts_formats[ndx]->dtf_str, str) == 0) {
+                       VERIFY(state->dts_formats[ndx]->dtf_refcount < UINT64_MAX);
+                       state->dts_formats[ndx]->dtf_refcount++;
                        return (ndx + 1);
                }
        }
@@ -10655,7 +10672,6 @@ dtrace_format_add(dtrace_state_t *state, char *str)
                 * This is only likely if a denial-of-service attack is being
                 * attempted.  As such, it's okay to fail silently here.
                 */
-               kmem_free(fmt, len);
                return (0);
        }
 
@@ -10664,16 +10680,16 @@ dtrace_format_add(dtrace_state_t *state, char *str)
         * number of formats.
         */
        ndx = state->dts_nformats++;
-       new = kmem_alloc((ndx + 1) * sizeof (char *), KM_SLEEP);
+       new = kmem_alloc((ndx + 1) * sizeof (*state->dts_formats), KM_SLEEP);
 
        if (state->dts_formats != NULL) {
                ASSERT(ndx != 0);
-               bcopy(state->dts_formats, new, ndx * sizeof (char *));
-               kmem_free(state->dts_formats, ndx * sizeof (char *));
+               bcopy(state->dts_formats, new, ndx * sizeof (*state->dts_formats));
+               kmem_free(state->dts_formats, ndx * sizeof (*state->dts_formats));
        }
 
        state->dts_formats = new;
-       state->dts_formats[ndx] = fmt;
+       state->dts_formats[ndx] = dtrace_format_new(str);
 
        return (ndx + 1);
 }
@@ -10681,15 +10697,22 @@ dtrace_format_add(dtrace_state_t *state, char *str)
 static void
 dtrace_format_remove(dtrace_state_t *state, uint16_t format)
 {
-       char *fmt;
+       dtrace_format_t *fmt;
 
        ASSERT(state->dts_formats != NULL);
        ASSERT(format <= state->dts_nformats);
-       ASSERT(state->dts_formats[format - 1] != NULL);
 
        fmt = state->dts_formats[format - 1];
-       kmem_free(fmt, strlen(fmt) + 1);
-       state->dts_formats[format - 1] = NULL;
+
+       ASSERT(fmt != NULL);
+       VERIFY(fmt->dtf_refcount > 0);
+
+       fmt->dtf_refcount--;
+
+       if (fmt->dtf_refcount == 0) {
+               kmem_free(fmt, DTRACE_FORMAT_SIZE(fmt));
+               state->dts_formats[format - 1] = NULL;
+       }
 }
 
 static void
@@ -10705,15 +10728,15 @@ dtrace_format_destroy(dtrace_state_t *state)
        ASSERT(state->dts_formats != NULL);
 
        for (i = 0; i < state->dts_nformats; i++) {
-               char *fmt = state->dts_formats[i];
+               dtrace_format_t *fmt = state->dts_formats[i];
 
                if (fmt == NULL)
                        continue;
 
-               kmem_free(fmt, strlen(fmt) + 1);
+               kmem_free(fmt, DTRACE_FORMAT_SIZE(fmt));
        }
 
-       kmem_free(state->dts_formats, state->dts_nformats * sizeof (char *));
+       kmem_free(state->dts_formats, state->dts_nformats * sizeof (*state->dts_formats));
        state->dts_nformats = 0;
        state->dts_formats = NULL;
 }
@@ -18428,7 +18451,7 @@ dtrace_ioctl(dev_t dev, u_long cmd, user_addr_t arg, int md, cred_t *cr, int *rv
                 * and that the format for the specified index is non-NULL.
                 */
                ASSERT(state->dts_formats != NULL);
-               str = state->dts_formats[fmt.dtfd_format - 1];
+               str = state->dts_formats[fmt.dtfd_format - 1]->dtf_str;
                ASSERT(str != NULL);
 
                len = strlen(str) + 1;
index e41d1f103d8528c6e6fe6a870a0bb5bde632ca56..3142cbda603f922529ca5a65300297c702978228 100644 (file)
@@ -85,6 +85,14 @@ struct kctl {
        u_int32_t               lastunit;
 };
 
+#if DEVELOPMENT || DEBUG
+enum ctl_status {
+       KCTL_DISCONNECTED = 0,
+       KCTL_CONNECTING = 1,
+       KCTL_CONNECTED = 2
+};
+#endif /* DEVELOPMENT || DEBUG */
+
 struct ctl_cb {
        TAILQ_ENTRY(ctl_cb)     next;           /* controller chain */
        lck_mtx_t               *mtx;
@@ -94,6 +102,9 @@ struct ctl_cb {
        struct sockaddr_ctl     sac;
        u_int32_t               usecount;
        u_int32_t               kcb_usecount;
+#if DEVELOPMENT || DEBUG
+       enum ctl_status         status;
+#endif /* DEVELOPMENT || DEBUG */
 };
 
 #ifndef ROUNDUP64
@@ -225,6 +236,12 @@ u_int32_t ctl_debug = 0;
 SYSCTL_INT(_net_systm_kctl, OID_AUTO, debug,
     CTLFLAG_RW | CTLFLAG_LOCKED, &ctl_debug, 0, "");
 
+#if DEVELOPMENT || DEBUG
+u_int32_t ctl_panic_debug = 0;
+SYSCTL_INT(_net_systm_kctl, OID_AUTO, panicdebug,
+    CTLFLAG_RW | CTLFLAG_LOCKED, &ctl_panic_debug, 0, "");
+#endif /* DEVELOPMENT || DEBUG */
+
 #define KCTL_TBL_INC 16
 
 static uintptr_t kctl_tbl_size = 0;
@@ -398,6 +415,9 @@ ctl_detach(struct socket *so)
        }
 
        soisdisconnected(so);
+#if DEVELOPMENT || DEBUG
+       kcb->status = KCTL_DISCONNECTED;
+#endif /* DEVELOPMENT || DEBUG */
        so->so_flags |= SOF_PCBCLEARING;
        clt_kcb_decrement_use_count(kcb);
        return 0;
@@ -526,6 +546,9 @@ ctl_setup_kctl(struct socket *so, struct sockaddr *nam, struct proc *p)
 done:
        if (error) {
                soisdisconnected(so);
+#if DEVELOPMENT || DEBUG
+               kcb->status = KCTL_DISCONNECTED;
+#endif /* DEVELOPMENT || DEBUG */
                lck_mtx_lock(ctl_mtx);
                TAILQ_REMOVE(&kctl->kcb_head, kcb, next);
                kcb->kctl = NULL;
@@ -587,6 +610,13 @@ ctl_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
        lck_mtx_t *mtx_held = socket_getlock(so, PR_F_WILLUNLOCK);
        ctl_kcb_increment_use_count(kcb, mtx_held);
 
+#if DEVELOPMENT || DEBUG
+       if (kcb->status != KCTL_DISCONNECTED && ctl_panic_debug) {
+               panic("kctl already connecting/connected");
+       }
+       kcb->status = KCTL_CONNECTING;
+#endif /* DEVELOPMENT || DEBUG */
+
        error = ctl_setup_kctl(so, nam, p);
        if (error) {
                goto out;
@@ -604,6 +634,9 @@ ctl_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
                goto end;
        }
        soisconnected(so);
+#if DEVELOPMENT || DEBUG
+       kcb->status = KCTL_CONNECTED;
+#endif /* DEVELOPMENT || DEBUG */
 
 end:
        if (error && kcb->kctl->disconnect) {
@@ -622,6 +655,9 @@ end:
        }
        if (error) {
                soisdisconnected(so);
+#if DEVELOPMENT || DEBUG
+               kcb->status = KCTL_DISCONNECTED;
+#endif /* DEVELOPMENT || DEBUG */
                lck_mtx_lock(ctl_mtx);
                TAILQ_REMOVE(&kcb->kctl->kcb_head, kcb, next);
                kcb->kctl = NULL;
@@ -654,6 +690,9 @@ ctl_disconnect(struct socket *so)
                }
 
                soisdisconnected(so);
+#if DEVELOPMENT || DEBUG
+               kcb->status = KCTL_DISCONNECTED;
+#endif /* DEVELOPMENT || DEBUG */
 
                socket_unlock(so, 0);
                lck_mtx_lock(ctl_mtx);
index eb333d4b1a33df93d2b5515180b3f1e60f7155db..e4ec2a210cfd21515ac62a02a6df46116f19108c 100644 (file)
@@ -5016,11 +5016,11 @@ exec_add_entropy_key(struct image_params *imgp,
                entropy[0] &= ~(0xffull << 8);
        }
 
-       int len = snprintf(str, sizeof(str), "%s0x%llx", key, entropy[0]);
+       int len = scnprintf(str, sizeof(str), "%s0x%llx", key, entropy[0]);
        int remaining = sizeof(str) - len;
        for (int i = 1; i < values && remaining > 0; ++i) {
                int start = sizeof(str) - remaining;
-               len = snprintf(&str[start], remaining, ",0x%llx", entropy[i]);
+               len = scnprintf(&str[start], remaining, ",0x%llx", entropy[i]);
                remaining -= len;
        }
 
index 1efcb56746637f90d5a32204f2bab4d5d471ed4f..c074ae1c628536b1b37ca478f1d26ce8ff275c56 100644 (file)
 #include <sys/persona.h>
 #include <sys/sysent.h>
 #include <sys/reason.h>
+#include <IOKit/IOBSD.h>        /* IOTaskHasEntitlement() */
 
 #ifdef CONFIG_32BIT_TELEMETRY
 #include <sys/kasl.h>
@@ -2193,6 +2194,7 @@ csops_internal(pid_t pid, int ops, user_addr_t uaddr, user_size_t usersize, user
        case CS_OPS_IDENTITY:
        case CS_OPS_BLOB:
        case CS_OPS_TEAMID:
+       case CS_OPS_CLEAR_LV:
                break;          /* not restricted to root */
        default:
                if (forself == 0 && kauth_cred_issuser(kauth_cred_get()) != TRUE) {
@@ -2229,6 +2231,7 @@ csops_internal(pid_t pid, int ops, user_addr_t uaddr, user_size_t usersize, user
        case CS_OPS_SET_STATUS:
        case CS_OPS_CLEARINSTALLER:
        case CS_OPS_CLEARPLATFORM:
+       case CS_OPS_CLEAR_LV:
                if ((error = mac_proc_check_set_cs_info(current_proc(), pt, ops))) {
                        goto out;
                }
@@ -2396,6 +2399,45 @@ csops_internal(pid_t pid, int ops, user_addr_t uaddr, user_size_t usersize, user
 
                break;
        }
+       case CS_OPS_CLEAR_LV: {
+               /*
+                * This option is used to remove library validation from
+                * a running process. This is used in plugin architectures
+                * when a program needs to load untrusted libraries. This
+                * allows the process to maintain library validation as
+                * long as possible, then drop it only when required.
+                * Once a process has loaded the untrusted library,
+                * relying on library validation in the future will
+                * not be effective. An alternative is to re-exec
+                * your application without library validation, or
+                * fork an untrusted child.
+                */
+#ifdef CONFIG_EMBEDDED
+               // On embedded platforms, we don't support dropping LV
+               error = ENOTSUP;
+#else
+               /*
+                * if we have the flag set, and the caller wants
+                * to remove it, and they're entitled to, then
+                * we remove it from the csflags
+                *
+                * NOTE: We are fine to poke into the task because
+                * we get a ref to pt when we do the proc_find
+                * at the beginning of this function.
+                *
+                * We also only allow altering ourselves.
+                */
+               if (forself == 1 && IOTaskHasEntitlement(pt->task, CLEAR_LV_ENTITLEMENT)) {
+                       proc_lock(pt);
+                       pt->p_csflags &= (~(CS_REQUIRE_LV & CS_FORCED_LV));
+                       proc_unlock(pt);
+                       error = 0;
+               } else {
+                       error = EPERM;
+               }
+#endif
+               break;
+       }
        case CS_OPS_BLOB: {
                void *start;
                size_t length;
@@ -3768,7 +3810,7 @@ proc_log_32bit_telemetry(proc_t p)
         * Get proc name and parent proc name; if the parent execs, we'll get a
         * garbled name.
         */
-       bytes_printed = snprintf(signature_cur_end,
+       bytes_printed = scnprintf(signature_cur_end,
            signature_buf_end - signature_cur_end,
            "%s,%s,", p->p_name,
            (p->p_pptr ? p->p_pptr->p_name : ""));
@@ -3799,7 +3841,7 @@ proc_log_32bit_telemetry(proc_t p)
                identity = "";
        }
 
-       bytes_printed = snprintf(signature_cur_end,
+       bytes_printed = scnprintf(signature_cur_end,
            signature_buf_end - signature_cur_end,
            "%s,%s", teamid, identity);
 
index ff66292387a163cfa2db31e3ca822ed7f3438624..0c10a3ac48f9d25b87769f37e4e0a989abe177db 100644 (file)
@@ -3443,7 +3443,7 @@ SYSCTL_PROC(_kern, OID_AUTO, slide,
  *
  * vm_global_user_wire_limit - system wide limit on wired memory from all processes combined.
  *
- * vm_user_wire_limit - per address space limit on wired memory.  This puts a cap on the process's rlimit value.
+ * vm_per_task_user_wire_limit - per address space limit on wired memory.  This puts a cap on the process's rlimit value.
  *
  * These values are initialized to reasonable defaults at boot time based on the available physical memory in
  * kmem_init().
@@ -3451,23 +3451,57 @@ SYSCTL_PROC(_kern, OID_AUTO, slide,
  * All values are in bytes.
  */
 
-vm_map_size_t   vm_global_no_user_wire_amount;
 vm_map_size_t   vm_global_user_wire_limit;
-vm_map_size_t   vm_user_wire_limit;
+vm_map_size_t   vm_per_task_user_wire_limit;
+extern uint64_t max_mem;
 
+/*
+ * We used to have a global in the kernel called vm_global_no_user_wire_limit which was the inverse
+ * of vm_global_user_wire_limit. But maintaining both of those is silly, and vm_global_user_wire_limit is the
+ * real limit.
+ * This function is for backwards compatibility with userspace
+ * since we exposed the old global via a sysctl.
+ */
+STATIC int
+sysctl_global_no_user_wire_amount(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
+{
+       vm_map_size_t old_value;
+       vm_map_size_t new_value;
+       int changed;
+       int error;
+
+       old_value = max_mem - vm_global_user_wire_limit;
+       error = sysctl_io_number(req, old_value, sizeof(vm_map_size_t), &new_value, &changed);
+       if (changed) {
+               if ((uint64_t)new_value > max_mem) {
+                       error = EINVAL;
+               } else {
+                       vm_global_user_wire_limit = max_mem - new_value;
+               }
+       }
+       return error;
+}
 /*
  * There needs to be a more automatic/elegant way to do this
  */
 #if defined(__ARM__)
-SYSCTL_INT(_vm, OID_AUTO, global_no_user_wire_amount, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_global_no_user_wire_amount, 0, "");
 SYSCTL_INT(_vm, OID_AUTO, global_user_wire_limit, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_global_user_wire_limit, 0, "");
-SYSCTL_INT(_vm, OID_AUTO, user_wire_limit, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_user_wire_limit, 0, "");
+SYSCTL_INT(_vm, OID_AUTO, user_wire_limit, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_per_task_user_wire_limit, 0, "");
+SYSCTL_PROC(_vm, OID_AUTO, global_no_user_wire_amount, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, 0, 0, &sysctl_global_no_user_wire_amount, "I", "");
 #else
-SYSCTL_QUAD(_vm, OID_AUTO, global_no_user_wire_amount, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_global_no_user_wire_amount, "");
 SYSCTL_QUAD(_vm, OID_AUTO, global_user_wire_limit, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_global_user_wire_limit, "");
-SYSCTL_QUAD(_vm, OID_AUTO, user_wire_limit, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_user_wire_limit, "");
+SYSCTL_QUAD(_vm, OID_AUTO, user_wire_limit, CTLFLAG_RW | CTLFLAG_LOCKED, &vm_per_task_user_wire_limit, "");
+SYSCTL_PROC(_vm, OID_AUTO, global_no_user_wire_amount, CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_LOCKED, 0, 0, &sysctl_global_no_user_wire_amount, "Q", "");
 #endif
 
+#if DEVELOPMENT || DEBUG
+/* These sysyctls are used to test the wired limit. */
+extern unsigned int    vm_page_wire_count;
+extern uint32_t        vm_lopage_free_count;
+SYSCTL_INT(_vm, OID_AUTO, page_wire_count, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_page_wire_count, 0, "");
+SYSCTL_INT(_vm, OID_AUTO, lopage_free_count, CTLFLAG_RD | CTLFLAG_LOCKED, &vm_lopage_free_count, 0, "");
+#endif /* DEVELOPMENT */
+
 extern int vm_map_copy_overwrite_aligned_src_not_internal;
 extern int vm_map_copy_overwrite_aligned_src_not_symmetric;
 extern int vm_map_copy_overwrite_aligned_src_large;
@@ -4433,6 +4467,22 @@ wedge_thread SYSCTL_HANDLER_ARGS
 
 SYSCTL_PROC(_kern, OID_AUTO, wedge_thread, CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED, 0, 0, wedge_thread, "I", "wedge this thread so it cannot be cleaned up");
 
+extern unsigned long
+total_corpses_count(void);
+
+static int
+sysctl_total_corpses_count SYSCTL_HANDLER_ARGS;
+
+static int
+sysctl_total_corpses_count SYSCTL_HANDLER_ARGS
+{
+#pragma unused(oidp, arg1, arg2)
+       int corpse_count = total_corpses_count();
+       return sysctl_io_opaque(req, &corpse_count, sizeof(int), NULL);
+}
+
+SYSCTL_PROC(_kern, OID_AUTO, total_corpses_count, CTLFLAG_RD | CTLFLAG_ANYBODY | CTLFLAG_LOCKED, 0, 0, sysctl_total_corpses_count, "I", "total corpses on the system");
+
 static int
 sysctl_turnstile_test_prim_lock SYSCTL_HANDLER_ARGS;
 static int
@@ -4616,10 +4666,10 @@ sysctl_test_mtx_uncontended SYSCTL_HANDLER_ARGS
 
        printf("%s starting uncontended mutex test with %d iterations\n", __func__, iter);
 
-       offset = snprintf(buffer, buffer_size, "STATS INNER LOOP");
+       offset = scnprintf(buffer, buffer_size, "STATS INNER LOOP");
        offset += lck_mtx_test_mtx_uncontended(iter, &buffer[offset], buffer_size - offset);
 
-       offset += snprintf(&buffer[offset], buffer_size - offset, "\nSTATS OUTER LOOP");
+       offset += scnprintf(&buffer[offset], buffer_size - offset, "\nSTATS OUTER LOOP");
        offset += lck_mtx_test_mtx_uncontended_loop_time(iter, &buffer[offset], buffer_size - offset);
 
        error = SYSCTL_OUT(req, buffer, offset);
@@ -4680,22 +4730,22 @@ sysctl_test_mtx_contended SYSCTL_HANDLER_ARGS
 
        printf("%s starting contended mutex test with %d iterations FULL_CONTENDED\n", __func__, iter);
 
-       offset = snprintf(buffer, buffer_size, "STATS INNER LOOP");
+       offset = scnprintf(buffer, buffer_size, "STATS INNER LOOP");
        offset += lck_mtx_test_mtx_contended(iter, &buffer[offset], buffer_size - offset, FULL_CONTENDED);
 
        printf("%s starting contended mutex loop test with %d iterations FULL_CONTENDED\n", __func__, iter);
 
-       offset += snprintf(&buffer[offset], buffer_size - offset, "\nSTATS OUTER LOOP");
+       offset += scnprintf(&buffer[offset], buffer_size - offset, "\nSTATS OUTER LOOP");
        offset += lck_mtx_test_mtx_contended_loop_time(iter, &buffer[offset], buffer_size - offset, FULL_CONTENDED);
 
        printf("%s starting contended mutex test with %d iterations HALF_CONTENDED\n", __func__, iter);
 
-       offset += snprintf(&buffer[offset], buffer_size - offset, "STATS INNER LOOP");
+       offset += scnprintf(&buffer[offset], buffer_size - offset, "STATS INNER LOOP");
        offset += lck_mtx_test_mtx_contended(iter, &buffer[offset], buffer_size - offset, HALF_CONTENDED);
 
        printf("%s starting contended mutex loop test with %d iterations HALF_CONTENDED\n", __func__, iter);
 
-       offset += snprintf(&buffer[offset], buffer_size - offset, "\nSTATS OUTER LOOP");
+       offset += scnprintf(&buffer[offset], buffer_size - offset, "\nSTATS OUTER LOOP");
        offset += lck_mtx_test_mtx_contended_loop_time(iter, &buffer[offset], buffer_size - offset, HALF_CONTENDED);
 
        error = SYSCTL_OUT(req, buffer, offset);
index a7f73781a9afadf3f0332f4603e6af5dac56edc2..ddf8e5db4aed91e230804f171bef57984f4d68ef 100644 (file)
@@ -465,6 +465,30 @@ vsnprintf(char *str, size_t size, const char *format, va_list ap)
        return retval;
 }
 
+int
+vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
+{
+       ssize_t ssize = size;
+       int i;
+
+       i = vsnprintf(buf, size, fmt, args);
+
+       return (i >= ssize) ? (ssize - 1) : i;
+}
+
+int
+scnprintf(char *buf, size_t size, const char *fmt, ...)
+{
+       va_list args;
+       int i;
+
+       va_start(args, fmt);
+       i = vscnprintf(buf, size, fmt, args);
+       va_end(args);
+
+       return i;
+}
+
 static void
 snprintf_func(int ch, void *arg)
 {
index db7acd2ed8d6fcae37b21130b76a69da67dc987c..947f38ad623e4558ef8c185e0d7e760bdd6ba04f 100644 (file)
@@ -7848,14 +7848,14 @@ mbuf_dump(void)
        if (totmbufs > m_mbufs) {
                totmbufs = m_mbufs;
        }
-       k = snprintf(c, clen, "%lu/%u mbufs in use:\n", totmbufs, m_mbufs);
+       k = scnprintf(c, clen, "%lu/%u mbufs in use:\n", totmbufs, m_mbufs);
        MBUF_DUMP_BUF_CHK();
 
        bzero(&seen, sizeof(seen));
        for (mp = mbtypes; mp->mt_name != NULL; mp++) {
                if (mbstat.m_mtypes[mp->mt_type] != 0) {
                        seen[mp->mt_type] = 1;
-                       k = snprintf(c, clen, "\t%u mbufs allocated to %s\n",
+                       k = scnprintf(c, clen, "\t%u mbufs allocated to %s\n",
                            mbstat.m_mtypes[mp->mt_type], mp->mt_name);
                        MBUF_DUMP_BUF_CHK();
                }
@@ -7863,17 +7863,17 @@ mbuf_dump(void)
        seen[MT_FREE] = 1;
        for (i = 0; i < nmbtypes; i++) {
                if (!seen[i] && mbstat.m_mtypes[i] != 0) {
-                       k = snprintf(c, clen, "\t%u mbufs allocated to "
+                       k = scnprintf(c, clen, "\t%u mbufs allocated to "
                            "<mbuf type %d>\n", mbstat.m_mtypes[i], i);
                        MBUF_DUMP_BUF_CHK();
                }
        }
        if ((m_mbufs - totmbufs) > 0) {
-               k = snprintf(c, clen, "\t%lu mbufs allocated to caches\n",
+               k = scnprintf(c, clen, "\t%lu mbufs allocated to caches\n",
                    m_mbufs - totmbufs);
                MBUF_DUMP_BUF_CHK();
        }
-       k = snprintf(c, clen, "%u/%u mbuf 2KB clusters in use\n"
+       k = scnprintf(c, clen, "%u/%u mbuf 2KB clusters in use\n"
            "%u/%u mbuf 4KB clusters in use\n",
            (unsigned int)(mbstat.m_clusters - m_clfree),
            (unsigned int)mbstat.m_clusters,
@@ -7882,7 +7882,7 @@ mbuf_dump(void)
        MBUF_DUMP_BUF_CHK();
 
        if (njcl > 0) {
-               k = snprintf(c, clen, "%u/%u mbuf %uKB clusters in use\n",
+               k = scnprintf(c, clen, "%u/%u mbuf %uKB clusters in use\n",
                    m_16kclusters - m_16kclfree, m_16kclusters,
                    njclbytes / 1024);
                MBUF_DUMP_BUF_CHK();
@@ -7897,21 +7897,21 @@ mbuf_dump(void)
                u_long totused1 = totused / 100;
                totpct = (totused1 * 100) / totmem1;
        }
-       k = snprintf(c, clen, "%lu KB allocated to network (approx. %lu%% "
+       k = scnprintf(c, clen, "%lu KB allocated to network (approx. %lu%% "
            "in use)\n", totmem / 1024, totpct);
        MBUF_DUMP_BUF_CHK();
-       k = snprintf(c, clen, "%lu KB returned to the system\n",
+       k = scnprintf(c, clen, "%lu KB returned to the system\n",
            totreturned / 1024);
        MBUF_DUMP_BUF_CHK();
 
        net_update_uptime();
-       k = snprintf(c, clen,
+       k = scnprintf(c, clen,
            "VM allocation failures: contiguous %u, normal %u, one page %u\n",
            mb_kmem_contig_failed, mb_kmem_failed, mb_kmem_one_failed);
        MBUF_DUMP_BUF_CHK();
        if (mb_kmem_contig_failed_ts || mb_kmem_failed_ts ||
            mb_kmem_one_failed_ts) {
-               k = snprintf(c, clen,
+               k = scnprintf(c, clen,
                    "VM allocation failure timestamps: contiguous %llu "
                    "(size %llu), normal %llu (size %llu), one page %llu "
                    "(now %llu)\n",
@@ -7919,20 +7919,20 @@ mbuf_dump(void)
                    mb_kmem_failed_ts, mb_kmem_failed_size,
                    mb_kmem_one_failed_ts, net_uptime());
                MBUF_DUMP_BUF_CHK();
-               k = snprintf(c, clen,
+               k = scnprintf(c, clen,
                    "VM return codes: ");
                MBUF_DUMP_BUF_CHK();
                for (i = 0;
                    i < sizeof(mb_kmem_stats) / sizeof(mb_kmem_stats[0]);
                    i++) {
-                       k = snprintf(c, clen, "%s: %u ", mb_kmem_stats_labels[i],
+                       k = scnprintf(c, clen, "%s: %u ", mb_kmem_stats_labels[i],
                            mb_kmem_stats[i]);
                        MBUF_DUMP_BUF_CHK();
                }
-               k = snprintf(c, clen, "\n");
+               k = scnprintf(c, clen, "\n");
                MBUF_DUMP_BUF_CHK();
        }
-       k = snprintf(c, clen,
+       k = scnprintf(c, clen,
            "worker thread runs: %u, expansions: %llu, cl %llu/%llu, "
            "bigcl %llu/%llu, 16k %llu/%llu\n", mbuf_worker_run_cnt,
            mb_expand_cnt, mb_expand_cl_cnt, mb_expand_cl_total,
@@ -7940,14 +7940,14 @@ mbuf_dump(void)
            mb_expand_16kcl_total);
        MBUF_DUMP_BUF_CHK();
        if (mbuf_worker_last_runtime != 0) {
-               k = snprintf(c, clen, "worker thread last run time: "
+               k = scnprintf(c, clen, "worker thread last run time: "
                    "%llu (%llu seconds ago)\n",
                    mbuf_worker_last_runtime,
                    net_uptime() - mbuf_worker_last_runtime);
                MBUF_DUMP_BUF_CHK();
        }
        if (mbuf_drain_last_runtime != 0) {
-               k = snprintf(c, clen, "drain routine last run time: "
+               k = scnprintf(c, clen, "drain routine last run time: "
                    "%llu (%llu seconds ago)\n",
                    mbuf_drain_last_runtime,
                    net_uptime() - mbuf_drain_last_runtime);
@@ -7955,7 +7955,7 @@ mbuf_dump(void)
        }
 
 #if DEBUG || DEVELOPMENT
-       k = snprintf(c, clen, "\nworker thread log:\n%s\n", mbwdog_logging);
+       k = scnprintf(c, clen, "\nworker thread log:\n%s\n", mbwdog_logging);
        MBUF_DUMP_BUF_CHK();
 #endif
 
@@ -7965,61 +7965,61 @@ mbuf_dump(void)
                        continue;
                }
                if (printed_banner == false) {
-                       k = snprintf(c, clen,
+                       k = scnprintf(c, clen,
                            "\nlargest allocation failure backtraces:\n");
                        MBUF_DUMP_BUF_CHK();
                        printed_banner = true;
                }
-               k = snprintf(c, clen, "size %llu: < ", trace->size);
+               k = scnprintf(c, clen, "size %llu: < ", trace->size);
                MBUF_DUMP_BUF_CHK();
                for (i = 0; i < trace->depth; i++) {
                        if (mleak_stat->ml_isaddr64) {
-                               k = snprintf(c, clen, "0x%0llx ",
+                               k = scnprintf(c, clen, "0x%0llx ",
                                    (uint64_t)VM_KERNEL_UNSLIDE(
                                            trace->addr[i]));
                        } else {
-                               k = snprintf(c, clen,
+                               k = scnprintf(c, clen,
                                    "0x%08x ",
                                    (uint32_t)VM_KERNEL_UNSLIDE(
                                            trace->addr[i]));
                        }
                        MBUF_DUMP_BUF_CHK();
                }
-               k = snprintf(c, clen, ">\n");
+               k = scnprintf(c, clen, ">\n");
                MBUF_DUMP_BUF_CHK();
        }
 
        /* mbuf leak detection statistics */
        mleak_update_stats();
 
-       k = snprintf(c, clen, "\nmbuf leak detection table:\n");
+       k = scnprintf(c, clen, "\nmbuf leak detection table:\n");
        MBUF_DUMP_BUF_CHK();
-       k = snprintf(c, clen, "\ttotal captured: %u (one per %u)\n",
+       k = scnprintf(c, clen, "\ttotal captured: %u (one per %u)\n",
            mleak_table.mleak_capture / mleak_table.mleak_sample_factor,
            mleak_table.mleak_sample_factor);
        MBUF_DUMP_BUF_CHK();
-       k = snprintf(c, clen, "\ttotal allocs outstanding: %llu\n",
+       k = scnprintf(c, clen, "\ttotal allocs outstanding: %llu\n",
            mleak_table.outstanding_allocs);
        MBUF_DUMP_BUF_CHK();
-       k = snprintf(c, clen, "\tnew hash recorded: %llu allocs, %llu traces\n",
+       k = scnprintf(c, clen, "\tnew hash recorded: %llu allocs, %llu traces\n",
            mleak_table.alloc_recorded, mleak_table.trace_recorded);
        MBUF_DUMP_BUF_CHK();
-       k = snprintf(c, clen, "\thash collisions: %llu allocs, %llu traces\n",
+       k = scnprintf(c, clen, "\thash collisions: %llu allocs, %llu traces\n",
            mleak_table.alloc_collisions, mleak_table.trace_collisions);
        MBUF_DUMP_BUF_CHK();
-       k = snprintf(c, clen, "\toverwrites: %llu allocs, %llu traces\n",
+       k = scnprintf(c, clen, "\toverwrites: %llu allocs, %llu traces\n",
            mleak_table.alloc_overwrites, mleak_table.trace_overwrites);
        MBUF_DUMP_BUF_CHK();
-       k = snprintf(c, clen, "\tlock conflicts: %llu\n\n",
+       k = scnprintf(c, clen, "\tlock conflicts: %llu\n\n",
            mleak_table.total_conflicts);
        MBUF_DUMP_BUF_CHK();
 
-       k = snprintf(c, clen, "top %d outstanding traces:\n",
+       k = scnprintf(c, clen, "top %d outstanding traces:\n",
            mleak_stat->ml_cnt);
        MBUF_DUMP_BUF_CHK();
        for (i = 0; i < mleak_stat->ml_cnt; i++) {
                mltr = &mleak_stat->ml_trace[i];
-               k = snprintf(c, clen, "[%d] %llu outstanding alloc(s), "
+               k = scnprintf(c, clen, "[%d] %llu outstanding alloc(s), "
                    "%llu hit(s), %llu collision(s)\n", (i + 1),
                    mltr->mltr_allocs, mltr->mltr_hitcount,
                    mltr->mltr_collisions);
@@ -8027,40 +8027,40 @@ mbuf_dump(void)
        }
 
        if (mleak_stat->ml_isaddr64) {
-               k = snprintf(c, clen, MB_LEAK_HDR_64);
+               k = scnprintf(c, clen, MB_LEAK_HDR_64);
        } else {
-               k = snprintf(c, clen, MB_LEAK_HDR_32);
+               k = scnprintf(c, clen, MB_LEAK_HDR_32);
        }
        MBUF_DUMP_BUF_CHK();
 
        for (i = 0; i < MLEAK_STACK_DEPTH; i++) {
-               k = snprintf(c, clen, "%2d: ", (i + 1));
+               k = scnprintf(c, clen, "%2d: ", (i + 1));
                MBUF_DUMP_BUF_CHK();
                for (j = 0; j < mleak_stat->ml_cnt; j++) {
                        mltr = &mleak_stat->ml_trace[j];
                        if (i < mltr->mltr_depth) {
                                if (mleak_stat->ml_isaddr64) {
-                                       k = snprintf(c, clen, "0x%0llx  ",
+                                       k = scnprintf(c, clen, "0x%0llx  ",
                                            (uint64_t)VM_KERNEL_UNSLIDE(
                                                    mltr->mltr_addr[i]));
                                } else {
-                                       k = snprintf(c, clen,
+                                       k = scnprintf(c, clen,
                                            "0x%08x  ",
                                            (uint32_t)VM_KERNEL_UNSLIDE(
                                                    mltr->mltr_addr[i]));
                                }
                        } else {
                                if (mleak_stat->ml_isaddr64) {
-                                       k = snprintf(c, clen,
+                                       k = scnprintf(c, clen,
                                            MB_LEAK_SPACING_64);
                                } else {
-                                       k = snprintf(c, clen,
+                                       k = scnprintf(c, clen,
                                            MB_LEAK_SPACING_32);
                                }
                        }
                        MBUF_DUMP_BUF_CHK();
                }
-               k = snprintf(c, clen, "\n");
+               k = scnprintf(c, clen, "\n");
                MBUF_DUMP_BUF_CHK();
        }
 done:
@@ -8692,7 +8692,7 @@ _mbwdog_logger(const char *func, const int line, const char *fmt, ...)
        vsnprintf(p, sizeof(p), fmt, ap);
        va_end(ap);
        microuptime(&now);
-       len = snprintf(str, sizeof(str),
+       len = scnprintf(str, sizeof(str),
            "\n%ld.%d (%d/%llx) %s:%d %s",
            now.tv_sec, now.tv_usec,
            current_proc()->p_pid,
index aa07cc477c0d2913981c1a2ab496d0fb71235dca..4ab504c31dfe11db61b4d880da0dddaa86ae705b 100644 (file)
@@ -1727,6 +1727,9 @@ soconnectlock(struct socket *so, struct sockaddr *nam, int dolock)
                } else {
                        error = (*so->so_proto->pr_usrreqs->pru_connect)
                            (so, nam, p);
+                       if (error != 0) {
+                               so->so_state &= ~SS_ISCONNECTING;
+                       }
                }
        }
        if (dolock) {
@@ -1826,6 +1829,9 @@ soconnectxlocked(struct socket *so, struct sockaddr *src,
                        error = (*so->so_proto->pr_usrreqs->pru_connectx)
                            (so, src, dst, p, ifscope, aid, pcid,
                            flags, arg, arglen, auio, bytes_written);
+                       if (error != 0) {
+                               so->so_state &= ~SS_ISCONNECTING;
+                       }
                }
        }
 
@@ -7083,7 +7089,7 @@ solockhistory_nr(struct socket *so)
 
        bzero(lock_history_str, sizeof(lock_history_str));
        for (i = SO_LCKDBG_MAX - 1; i >= 0; i--) {
-               n += snprintf(lock_history_str + n,
+               n += scnprintf(lock_history_str + n,
                    SO_LOCK_HISTORY_STR_LEN - n, "%p:%p ",
                    so->lock_lr[(so->next_lock_lr + i) % SO_LCKDBG_MAX],
                    so->unlock_lr[(so->next_unlock_lr + i) % SO_LCKDBG_MAX]);
index ca5e7dd6e8e17768124c2da4c6d986ff2819c48e..5c929755a2e91c72814828323fda1cea9a0a862d 100644 (file)
@@ -965,7 +965,6 @@ connectit(struct socket *so, struct sockaddr *sa)
        }
        error = soconnectlock(so, sa, 0);
        if (error != 0) {
-               so->so_state &= ~SS_ISCONNECTING;
                goto out;
        }
        if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
@@ -1064,7 +1063,6 @@ connectitx(struct socket *so, struct sockaddr *src,
        error = soconnectxlocked(so, src, dst, p, ifscope,
            aid, pcid, 0, NULL, 0, auio, bytes_written);
        if (error != 0) {
-               so->so_state &= ~SS_ISCONNECTING;
                goto out;
        }
        /*
index ab4dfd3ee583a86dfc1406e99fa6d763796088c1..b95c70e3cb8ece4d151089470342375ca32dd274 100644 (file)
@@ -159,7 +159,13 @@ extern char     *strsep(char **, const char *);
 extern void     *memchr(const void *, int, size_t);
 extern void     url_decode(char *str);
 
+/*
+ * NOTE: snprintf() returns the full length of the formatted string even if it
+ * couldn't fit in the supplied buffer.
+ * Use scnprintf() if you need the actual number of bytes (minus the \0)
+ */
 int     snprintf(char *, size_t, const char *, ...) __printflike(3, 4);
+int     scnprintf(char *, size_t, const char *, ...) __printflike(3, 4);
 
 /* sprintf() is being deprecated. Please use snprintf() instead. */
 int     sprintf(char *bufp, const char *, ...) __deprecated __printflike(2, 3);
@@ -209,6 +215,7 @@ int vsscanf(const char *, char const *, va_list);
 
 extern int      vprintf(const char *, va_list) __printflike(1, 0);
 extern int      vsnprintf(char *, size_t, const char *, va_list) __printflike(3, 0);
+extern int      vscnprintf(char *, size_t, const char *, va_list) __printflike(3, 0);
 
 #if XNU_KERNEL_PRIVATE
 extern int      vprintf_log_locked(const char *, va_list, bool addcr) __printflike(1, 0);
index b83108b525a10387828dd345a92969d705a43aba..95a5be5f2b7a0ccfe5d0c5b95efbee335f66234a 100644 (file)
@@ -597,7 +597,7 @@ devfs_devfd_readdir(struct vnop_readdir_args *ap)
 
                        bzero((caddr_t) dp, UIO_MX);
 
-                       dp->d_namlen = snprintf(dp->d_name, sizeof(dp->d_name),
+                       dp->d_namlen = scnprintf(dp->d_name, sizeof(dp->d_name),
                            "%d", i);
                        dp->d_reclen = UIO_MX;
                        dp->d_type = DT_UNKNOWN;
index 7a119911e9bcc3a5141e571de094da6c2d716caa..8acee164d7e49b5a07134f78bba886e32cbafe7c 100644 (file)
@@ -7291,7 +7291,7 @@ dlil_alloc_lladdr(struct ifnet *ifp, const struct sockaddr_dl *ll_addr)
        ifnet_lock_assert(ifp, IFNET_LCK_ASSERT_EXCLUSIVE);
        VERIFY(ll_addr == NULL || ll_addr->sdl_alen == ifp->if_addrlen);
 
-       namelen = snprintf(workbuf, sizeof(workbuf), "%s",
+       namelen = scnprintf(workbuf, sizeof(workbuf), "%s",
            if_name(ifp));
        masklen = offsetof(struct sockaddr_dl, sdl_data[0])
            + ((namelen > 0) ? namelen : 0);
index 407f3243e9fa7dcce7e9ddbd6c04bb1da28b249a..756272a891aa0a18898a32d7673b3caf634d072b 100644 (file)
@@ -3404,7 +3404,7 @@ ipsec_ctl_getopt(__unused kern_ctl_ref kctlref,
                                result = EINVAL;
                                break;
                        }
-                       *len = snprintf(data, *len, "%s", pcb->ipsec_if_xname) + 1;
+                       *len = scnprintf(data, *len, "%s", pcb->ipsec_if_xname) + 1;
                }
                break;
        }
index d29785b8b71c3838c558906276aaa3de8cafe9ce..dd076948f2a18f3be45e9f2f535b71d5ebe87057 100644 (file)
@@ -2304,7 +2304,7 @@ utun_ctl_getopt(__unused kern_ctl_ref kctlref,
                                result = EINVAL;
                                break;
                        }
-                       *len = snprintf(data, *len, "%s", pcb->utun_if_xname) + 1;
+                       *len = scnprintf(data, *len, "%s", pcb->utun_if_xname) + 1;
                }
                break;
 
index 3e251d7b13110eb55e2654c2b906a9ca148907f8..2133f31f3601376d03be95e0c2f2eedc550860c0 100644 (file)
@@ -75,7 +75,7 @@
  * NECP - Network Extension Control Policy database
  * ------------------------------------------------
  * The goal of this module is to allow clients connecting via a
- * kernel control socket to create high-level policy sessions, which
+ * policy file descriptor to create high-level policy sessions, which
  * are ingested into low-level kernel policies that control and tag
  * traffic at the application, socket, and IP layers.
  *
@@ -91,7 +91,7 @@
  * can specify the sub-order for each policy it creates which will be
  * used to further sort the kernel policies.
  *
- *  Kernel Control Socket --> 1 necp_session --> list of necp_session_policy structs
+ *  Policy fd --> 1 necp_session --> list of necp_session_policy structs
  *
  * ------------------------------------------------
  * Kernel Policies
@@ -289,9 +289,6 @@ struct necp_socket_info {
        unsigned __pad_bits : 6;
 };
 
-static kern_ctl_ref     necp_kctlref;
-static u_int32_t        necp_family;
-static OSMallocTag      necp_malloc_tag;
 static  lck_grp_attr_t  *necp_kernel_policy_grp_attr    = NULL;
 static  lck_attr_t              *necp_kernel_policy_mtx_attr    = NULL;
 static  lck_grp_t               *necp_kernel_policy_mtx_grp             = NULL;
@@ -366,19 +363,9 @@ static struct necp_kernel_socket_policy pass_policy =
 static struct necp_session *necp_create_session(void);
 static void necp_delete_session(struct necp_session *session);
 
-static necp_policy_id necp_handle_policy_add(struct necp_session *session, u_int32_t message_id, mbuf_t packet,
+static necp_policy_id necp_handle_policy_add(struct necp_session *session,
     u_int8_t *tlv_buffer, size_t tlv_buffer_length, int offset, int *error);
-static void necp_handle_policy_get(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset);
-static void necp_handle_policy_delete(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset);
-static void necp_handle_policy_apply_all(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset);
-static void necp_handle_policy_list_all(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset);
-static void necp_handle_policy_delete_all(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset);
-static int necp_handle_policy_dump_all(struct necp_session *session, u_int32_t message_id, mbuf_t packet,
-    user_addr_t out_buffer, size_t out_buffer_length, int offset);
-static void necp_handle_set_session_priority(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset);
-static void necp_handle_lock_session_to_proc(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset);
-static void necp_handle_register_service(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset);
-static void necp_handle_unregister_service(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset);
+static int necp_handle_policy_dump_all(user_addr_t out_buffer, size_t out_buffer_length);
 
 #define MAX_RESULT_STRING_LEN 64
 static inline const char * necp_get_result_description(char *result_string, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter);
@@ -741,7 +728,7 @@ necp_session_add_policy(struct necp_session *session, struct necp_session_action
                goto done;
        }
 
-       necp_policy_id new_policy_id = necp_handle_policy_add(session, 0, NULL, tlv_buffer, uap->in_buffer_length, 0, &error);
+       necp_policy_id new_policy_id = necp_handle_policy_add(session, tlv_buffer, uap->in_buffer_length, 0, &error);
        if (error != 0) {
                NECPLOG(LOG_ERR, "necp_session_add_policy failed to add policy (%d)", error);
                goto done;
@@ -1084,6 +1071,7 @@ done:
 static int
 necp_session_dump_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
 {
+#pragma unused(session)
        int error = 0;
 
        if (uap->out_buffer_length == 0 || uap->out_buffer == 0) {
@@ -1092,7 +1080,7 @@ necp_session_dump_all(struct necp_session *session, struct necp_session_action_a
                goto done;
        }
 
-       error = necp_handle_policy_dump_all(session, 0, NULL, uap->out_buffer, uap->out_buffer_length, 0);
+       error = necp_handle_policy_dump_all(uap->out_buffer, uap->out_buffer_length);
 done:
        *retval = error;
        return error;
@@ -1187,17 +1175,6 @@ done:
        return return_value;
 }
 
-// Kernel Control functions
-static errno_t necp_register_control(void);
-static errno_t necp_ctl_connect(kern_ctl_ref kctlref, struct sockaddr_ctl *sac, void **unitinfo);
-static errno_t necp_ctl_disconnect(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo);
-static errno_t necp_ctl_send(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, mbuf_t m, int flags);
-static void necp_ctl_rcvd(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int flags);
-static errno_t necp_ctl_getopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int opt, void *data, size_t *len);
-static errno_t necp_ctl_setopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int opt, void *data, size_t len);
-
-static bool necp_send_ctl_data(struct necp_session *session, u_int8_t *buffer, size_t buffer_size);
-
 struct necp_resolver_key_state {
        const struct ccdigest_info *digest_info;
        uint8_t key[CCSHA256_OUTPUT_SIZE];
@@ -1314,11 +1291,6 @@ necp_init(void)
 {
        errno_t result = 0;
 
-       result = necp_register_control();
-       if (result != 0) {
-               goto done;
-       }
-
        necp_kernel_policy_grp_attr = lck_grp_attr_alloc_init();
        if (necp_kernel_policy_grp_attr == NULL) {
                NECPLOG0(LOG_ERR, "lck_grp_attr_alloc_init failed");
@@ -1432,52 +1404,10 @@ done:
                        lck_grp_attr_free(necp_route_rule_grp_attr);
                        necp_route_rule_grp_attr = NULL;
                }
-               if (necp_kctlref != NULL) {
-                       ctl_deregister(necp_kctlref);
-                       necp_kctlref = NULL;
-               }
        }
        return result;
 }
 
-static errno_t
-necp_register_control(void)
-{
-       struct kern_ctl_reg     kern_ctl;
-       errno_t                         result = 0;
-
-       // Create a tag to allocate memory
-       necp_malloc_tag = OSMalloc_Tagalloc(NECP_CONTROL_NAME, OSMT_DEFAULT);
-
-       // Find a unique value for our interface family
-       result = mbuf_tag_id_find(NECP_CONTROL_NAME, &necp_family);
-       if (result != 0) {
-               NECPLOG(LOG_ERR, "mbuf_tag_id_find_internal failed: %d", result);
-               return result;
-       }
-
-       bzero(&kern_ctl, sizeof(kern_ctl));
-       strlcpy(kern_ctl.ctl_name, NECP_CONTROL_NAME, sizeof(kern_ctl.ctl_name));
-       kern_ctl.ctl_name[sizeof(kern_ctl.ctl_name) - 1] = 0;
-       kern_ctl.ctl_flags = CTL_FLAG_PRIVILEGED; // Require root
-       kern_ctl.ctl_sendsize = 64 * 1024;
-       kern_ctl.ctl_recvsize = 64 * 1024;
-       kern_ctl.ctl_connect = necp_ctl_connect;
-       kern_ctl.ctl_disconnect = necp_ctl_disconnect;
-       kern_ctl.ctl_send = necp_ctl_send;
-       kern_ctl.ctl_rcvd = necp_ctl_rcvd;
-       kern_ctl.ctl_setopt = necp_ctl_setopt;
-       kern_ctl.ctl_getopt = necp_ctl_getopt;
-
-       result = ctl_register(&kern_ctl, &necp_kctlref);
-       if (result != 0) {
-               NECPLOG(LOG_ERR, "ctl_register failed: %d", result);
-               return result;
-       }
-
-       return 0;
-}
-
 static void
 necp_post_change_event(struct kev_necp_policies_changed_data *necp_event_data)
 {
@@ -1496,117 +1426,6 @@ necp_post_change_event(struct kev_necp_policies_changed_data *necp_event_data)
        kev_post_msg(&ev_msg);
 }
 
-static errno_t
-necp_ctl_connect(kern_ctl_ref kctlref, struct sockaddr_ctl *sac, void **unitinfo)
-{
-#pragma unused(kctlref, sac)
-       *unitinfo = necp_create_session();
-       if (*unitinfo == NULL) {
-               // Could not allocate session
-               return ENOBUFS;
-       }
-
-       return 0;
-}
-
-static errno_t
-necp_ctl_disconnect(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo)
-{
-#pragma unused(kctlref, unit)
-       struct necp_session *session = (struct necp_session *)unitinfo;
-       if (session != NULL) {
-               necp_policy_mark_all_for_deletion(session);
-               necp_policy_apply_all(session);
-               necp_delete_session((struct necp_session *)unitinfo);
-       }
-
-       return 0;
-}
-
-
-// Message handling
-static int
-necp_packet_find_tlv(mbuf_t packet, int offset, u_int8_t type, int *err, int next)
-{
-       size_t  cursor                  = offset;
-       int             error                   = 0;
-       u_int32_t       curr_length;
-       u_int8_t        curr_type;
-
-       *err = 0;
-
-       do {
-               if (!next) {
-                       error = mbuf_copydata(packet, cursor, sizeof(curr_type), &curr_type);
-                       if (error) {
-                               *err = ENOENT;
-                               return -1;
-                       }
-               } else {
-                       next = 0;
-                       curr_type = NECP_TLV_NIL;
-               }
-
-               if (curr_type != type) {
-                       cursor += sizeof(curr_type);
-                       error = mbuf_copydata(packet, cursor, sizeof(curr_length), &curr_length);
-                       if (error) {
-                               *err = error;
-                               return -1;
-                       }
-                       cursor += (sizeof(curr_length) + curr_length);
-               }
-       } while (curr_type != type);
-
-       return cursor;
-}
-
-static int
-necp_packet_get_tlv_at_offset(mbuf_t packet, int tlv_offset, u_int32_t buff_len, void *buff, u_int32_t *value_size)
-{
-       int                     error   = 0;
-       u_int32_t       length;
-
-       if (tlv_offset < 0) {
-               return EINVAL;
-       }
-
-       error = mbuf_copydata(packet, tlv_offset + sizeof(u_int8_t), sizeof(length), &length);
-       if (error) {
-               return error;
-       }
-
-       u_int32_t total_len = m_length2(packet, NULL);
-       if (total_len < (tlv_offset + sizeof(u_int8_t) + sizeof(length) + length)) {
-               NECPLOG(LOG_ERR, "Got a bad TLV, length (%u) + offset (%d) < total length (%u)",
-                   length, (tlv_offset + sizeof(u_int8_t) + sizeof(length)), total_len);
-               return EINVAL;
-       }
-
-       if (value_size != NULL) {
-               *value_size = length;
-       }
-
-       if (buff != NULL && buff_len > 0) {
-               u_int32_t to_copy = (length < buff_len) ? length : buff_len;
-               error = mbuf_copydata(packet, tlv_offset + sizeof(u_int8_t) + sizeof(length), to_copy, buff);
-               if (error) {
-                       return error;
-               }
-       }
-
-       return 0;
-}
-
-static u_int8_t *
-necp_buffer_write_packet_header(u_int8_t *buffer, u_int8_t packet_type, u_int8_t flags, u_int32_t message_id)
-{
-       ((struct necp_packet_header *)(void *)buffer)->packet_type = packet_type;
-       ((struct necp_packet_header *)(void *)buffer)->flags = flags;
-       ((struct necp_packet_header *)(void *)buffer)->message_id = message_id;
-       return buffer + sizeof(struct necp_packet_header);
-}
-
 static inline bool
 necp_buffer_write_tlv_validate(u_int8_t *cursor, u_int8_t type, u_int32_t length,
     u_int8_t *buffer, u_int32_t buffer_length)
@@ -1762,26 +1581,19 @@ necp_buffer_find_tlv(u_int8_t *buffer, u_int32_t buffer_length, int offset, u_in
 }
 
 static int
-necp_find_tlv(mbuf_t packet, u_int8_t *buffer, u_int32_t buffer_length, int offset, u_int8_t type, int *err, int next)
+necp_find_tlv(u_int8_t *buffer, u_int32_t buffer_length, int offset, u_int8_t type, int *err, int next)
 {
        int cursor = -1;
-       if (packet != NULL) {
-               cursor = necp_packet_find_tlv(packet, offset, type, err, next);
-       } else if (buffer != NULL) {
+       if (buffer != NULL) {
                cursor = necp_buffer_find_tlv(buffer, buffer_length, offset, type, err, next);
        }
        return cursor;
 }
 
 static int
-necp_get_tlv_at_offset(mbuf_t packet, u_int8_t *buffer, u_int32_t buffer_length,
+necp_get_tlv_at_offset(u_int8_t *buffer, u_int32_t buffer_length,
     int tlv_offset, u_int32_t out_buffer_length, void *out_buffer, u_int32_t *value_size)
 {
-       if (packet != NULL) {
-               // Handle mbuf parsing
-               return necp_packet_get_tlv_at_offset(packet, tlv_offset, out_buffer_length, out_buffer, value_size);
-       }
-
        if (buffer == NULL) {
                NECPLOG0(LOG_ERR, "necp_get_tlv_at_offset buffer is NULL");
                return EINVAL;
@@ -1832,219 +1644,17 @@ necp_get_tlv_at_offset(mbuf_t packet, u_int8_t *buffer, u_int32_t buffer_length,
 }
 
 static int
-necp_get_tlv(mbuf_t packet, u_int8_t *buffer, u_int32_t buffer_length,
+necp_get_tlv(u_int8_t *buffer, u_int32_t buffer_length,
     int offset, u_int8_t type, u_int32_t buff_len, void *buff, u_int32_t *value_size)
 {
        int error = 0;
 
-       int tlv_offset = necp_find_tlv(packet, buffer, buffer_length, offset, type, &error, 0);
+       int tlv_offset = necp_find_tlv(buffer, buffer_length, offset, type, &error, 0);
        if (tlv_offset < 0) {
                return error;
        }
 
-       return necp_get_tlv_at_offset(packet, buffer, buffer_length, tlv_offset, buff_len, buff, value_size);
-}
-
-static bool
-necp_send_ctl_data(struct necp_session *session, u_int8_t *buffer, size_t buffer_size)
-{
-       int             error;
-
-       if (necp_kctlref == NULL || session == NULL || buffer == NULL || buffer_size == 0) {
-               return FALSE;
-       }
-
-       error = ctl_enqueuedata(necp_kctlref, session->control_unit, buffer, buffer_size, CTL_DATA_EOR);
-
-       return error == 0;
-}
-
-static bool
-necp_send_success_response(struct necp_session *session, u_int8_t packet_type, u_int32_t message_id)
-{
-       bool success = TRUE;
-       u_int8_t *response = NULL;
-       u_int8_t *cursor = NULL;
-       size_t response_size = sizeof(struct necp_packet_header) + sizeof(u_int8_t) + sizeof(u_int32_t);
-       MALLOC(response, u_int8_t *, response_size, M_NECP, M_WAITOK);
-       if (response == NULL) {
-               return FALSE;
-       }
-       cursor = response;
-       cursor = necp_buffer_write_packet_header(cursor, packet_type, NECP_PACKET_FLAGS_RESPONSE, message_id);
-       cursor = necp_buffer_write_tlv(cursor, NECP_TLV_NIL, 0, NULL, response, response_size);
-
-       if (!(success = necp_send_ctl_data(session, (u_int8_t *)response, response_size))) {
-               NECPLOG0(LOG_ERR, "Failed to send response");
-       }
-
-       FREE(response, M_NECP);
-       return success;
-}
-
-static bool
-necp_send_error_response(struct necp_session *session, u_int8_t packet_type, u_int32_t message_id, u_int32_t error)
-{
-       bool success = TRUE;
-       u_int8_t *response = NULL;
-       u_int8_t *cursor = NULL;
-       size_t response_size = sizeof(struct necp_packet_header) + sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(u_int32_t);
-       MALLOC(response, u_int8_t *, response_size, M_NECP, M_WAITOK);
-       if (response == NULL) {
-               return FALSE;
-       }
-       cursor = response;
-       cursor = necp_buffer_write_packet_header(cursor, packet_type, NECP_PACKET_FLAGS_RESPONSE, message_id);
-       cursor = necp_buffer_write_tlv(cursor, NECP_TLV_ERROR, sizeof(error), &error, response, response_size);
-
-       if (!(success = necp_send_ctl_data(session, (u_int8_t *)response, response_size))) {
-               NECPLOG0(LOG_ERR, "Failed to send response");
-       }
-
-       FREE(response, M_NECP);
-       return success;
-}
-
-static bool
-necp_send_policy_id_response(struct necp_session *session, u_int8_t packet_type, u_int32_t message_id, necp_policy_id policy_id)
-{
-       bool success = TRUE;
-       u_int8_t *response = NULL;
-       u_int8_t *cursor = NULL;
-       size_t response_size = sizeof(struct necp_packet_header) + sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(u_int32_t);
-       MALLOC(response, u_int8_t *, response_size, M_NECP, M_WAITOK);
-       if (response == NULL) {
-               return FALSE;
-       }
-       cursor = response;
-       cursor = necp_buffer_write_packet_header(cursor, packet_type, NECP_PACKET_FLAGS_RESPONSE, message_id);
-       cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, sizeof(policy_id), &policy_id, response, response_size);
-
-       if (!(success = necp_send_ctl_data(session, (u_int8_t *)response, response_size))) {
-               NECPLOG0(LOG_ERR, "Failed to send response");
-       }
-
-       FREE(response, M_NECP);
-       return success;
-}
-
-static errno_t
-necp_ctl_send(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, mbuf_t packet, int flags)
-{
-#pragma unused(kctlref, unit, flags)
-       struct necp_session *session = (struct necp_session *)unitinfo;
-       struct necp_packet_header header;
-       int error = 0;
-
-       if (session == NULL) {
-               NECPLOG0(LOG_ERR, "Got a NULL session");
-               error = EINVAL;
-               goto done;
-       }
-
-       if (mbuf_pkthdr_len(packet) < sizeof(header)) {
-               NECPLOG(LOG_ERR, "Got a bad packet, length (%lu) < sizeof header (%lu)", mbuf_pkthdr_len(packet), sizeof(header));
-               error = EINVAL;
-               goto done;
-       }
-
-       error = mbuf_copydata(packet, 0, sizeof(header), &header);
-       if (error) {
-               NECPLOG(LOG_ERR, "mbuf_copydata failed for the header: %d", error);
-               error = ENOBUFS;
-               goto done;
-       }
-
-       if (session->proc_locked) {
-               // Verify that the calling process is allowed to send messages
-               uuid_t proc_uuid;
-               proc_getexecutableuuid(current_proc(), proc_uuid, sizeof(proc_uuid));
-               if (uuid_compare(proc_uuid, session->proc_uuid) != 0) {
-                       necp_send_error_response(session, header.packet_type, header.message_id, NECP_ERROR_INVALID_PROCESS);
-                       goto done;
-               }
-       } else {
-               // If not locked, update the proc_uuid and proc_pid of the session
-               proc_getexecutableuuid(current_proc(), session->proc_uuid, sizeof(session->proc_uuid));
-               session->proc_pid = proc_pid(current_proc());
-       }
-
-       switch (header.packet_type) {
-       case NECP_PACKET_TYPE_POLICY_ADD: {
-               necp_handle_policy_add(session, header.message_id, packet, NULL, 0, sizeof(header), NULL);
-               break;
-       }
-       case NECP_PACKET_TYPE_POLICY_GET: {
-               necp_handle_policy_get(session, header.message_id, packet, sizeof(header));
-               break;
-       }
-       case NECP_PACKET_TYPE_POLICY_DELETE: {
-               necp_handle_policy_delete(session, header.message_id, packet, sizeof(header));
-               break;
-       }
-       case NECP_PACKET_TYPE_POLICY_APPLY_ALL: {
-               necp_handle_policy_apply_all(session, header.message_id, packet, sizeof(header));
-               break;
-       }
-       case NECP_PACKET_TYPE_POLICY_LIST_ALL: {
-               necp_handle_policy_list_all(session, header.message_id, packet, sizeof(header));
-               break;
-       }
-       case NECP_PACKET_TYPE_POLICY_DELETE_ALL: {
-               necp_handle_policy_delete_all(session, header.message_id, packet, sizeof(header));
-               break;
-       }
-       case NECP_PACKET_TYPE_POLICY_DUMP_ALL: {
-               necp_handle_policy_dump_all(session, header.message_id, packet, 0, 0, sizeof(header));
-               break;
-       }
-       case NECP_PACKET_TYPE_SET_SESSION_PRIORITY: {
-               necp_handle_set_session_priority(session, header.message_id, packet, sizeof(header));
-               break;
-       }
-       case NECP_PACKET_TYPE_LOCK_SESSION_TO_PROC: {
-               necp_handle_lock_session_to_proc(session, header.message_id, packet, sizeof(header));
-               break;
-       }
-       case NECP_PACKET_TYPE_REGISTER_SERVICE: {
-               necp_handle_register_service(session, header.message_id, packet, sizeof(header));
-               break;
-       }
-       case NECP_PACKET_TYPE_UNREGISTER_SERVICE: {
-               necp_handle_unregister_service(session, header.message_id, packet, sizeof(header));
-               break;
-       }
-       default: {
-               NECPLOG(LOG_ERR, "Received unknown message type %d", header.packet_type);
-               necp_send_error_response(session, header.packet_type, header.message_id, NECP_ERROR_UNKNOWN_PACKET_TYPE);
-               break;
-       }
-       }
-
-done:
-       mbuf_freem(packet);
-       return error;
-}
-
-static void
-necp_ctl_rcvd(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int flags)
-{
-#pragma unused(kctlref, unit, unitinfo, flags)
-       return;
-}
-
-static errno_t
-necp_ctl_getopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int opt, void *data, size_t *len)
-{
-#pragma unused(kctlref, unit, unitinfo, opt, data, len)
-       return 0;
-}
-
-static errno_t
-necp_ctl_setopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int opt, void *data, size_t len)
-{
-#pragma unused(kctlref, unit, unitinfo, opt, data, len)
-       return 0;
+       return necp_get_tlv_at_offset(buffer, buffer_length, tlv_offset, buff_len, buff, value_size);
 }
 
 // Session Management
@@ -2501,164 +2111,8 @@ necp_get_posix_error_for_necp_error(int response_error)
        }
 }
 
-static void
-necp_handle_set_session_priority(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset)
-{
-       int error;
-       struct necp_session_policy *policy = NULL;
-       struct necp_session_policy *temp_policy = NULL;
-       u_int32_t response_error = NECP_ERROR_INTERNAL;
-       u_int32_t requested_session_priority = NECP_SESSION_PRIORITY_UNKNOWN;
-
-       // Read policy id
-       error = necp_get_tlv(packet, NULL, 0, offset, NECP_TLV_SESSION_PRIORITY, sizeof(requested_session_priority), &requested_session_priority, NULL);
-       if (error) {
-               NECPLOG(LOG_ERR, "Failed to get session priority: %d", error);
-               response_error = NECP_ERROR_INVALID_TLV;
-               goto fail;
-       }
-
-       if (session == NULL) {
-               NECPLOG0(LOG_ERR, "Failed to find session");
-               response_error = NECP_ERROR_INTERNAL;
-               goto fail;
-       }
-
-       // Enforce special session priorities with entitlements
-       if (requested_session_priority == NECP_SESSION_PRIORITY_CONTROL ||
-           requested_session_priority == NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL) {
-               errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
-               if (cred_result != 0) {
-                       NECPLOG(LOG_ERR, "Session does not hold necessary entitlement to claim priority level %d", requested_session_priority);
-                       goto fail;
-               }
-       }
-
-       if (session->session_priority != requested_session_priority) {
-               session->session_priority = requested_session_priority;
-               session->session_order = necp_allocate_new_session_order(session->session_priority, session->control_unit);
-               session->dirty = TRUE;
-
-               // Mark all policies as needing updates
-               LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
-                       policy->pending_update = TRUE;
-               }
-       }
-
-       necp_send_success_response(session, NECP_PACKET_TYPE_SET_SESSION_PRIORITY, message_id);
-       return;
-
-fail:
-       necp_send_error_response(session, NECP_PACKET_TYPE_SET_SESSION_PRIORITY, message_id, response_error);
-}
-
-static void
-necp_handle_lock_session_to_proc(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset)
-{
-#pragma unused(packet, offset)
-       // proc_uuid already filled out
-       session->proc_locked = TRUE;
-       necp_send_success_response(session, NECP_PACKET_TYPE_LOCK_SESSION_TO_PROC, message_id);
-}
-
-static void
-necp_handle_register_service(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset)
-{
-       int error;
-       struct necp_service_registration *new_service = NULL;
-       u_int32_t response_error = NECP_ERROR_INTERNAL;
-       uuid_t service_uuid;
-       uuid_clear(service_uuid);
-
-       if (session == NULL) {
-               NECPLOG0(LOG_ERR, "Failed to find session");
-               response_error = NECP_ERROR_INTERNAL;
-               goto fail;
-       }
-
-       // Enforce entitlements
-       errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
-       if (cred_result != 0) {
-               NECPLOG0(LOG_ERR, "Session does not hold necessary entitlement to register service");
-               goto fail;
-       }
-
-       // Read service uuid
-       error = necp_get_tlv(packet, NULL, 0, offset, NECP_TLV_SERVICE_UUID, sizeof(uuid_t), service_uuid, NULL);
-       if (error) {
-               NECPLOG(LOG_ERR, "Failed to get service UUID: %d", error);
-               response_error = NECP_ERROR_INVALID_TLV;
-               goto fail;
-       }
-
-       MALLOC(new_service, struct necp_service_registration *, sizeof(*new_service), M_NECP, M_WAITOK);
-       if (new_service == NULL) {
-               NECPLOG0(LOG_ERR, "Failed to allocate service registration");
-               response_error = NECP_ERROR_INTERNAL;
-               goto fail;
-       }
-
-       lck_rw_lock_exclusive(&necp_kernel_policy_lock);
-       memset(new_service, 0, sizeof(*new_service));
-       new_service->service_id = necp_create_uuid_service_id_mapping(service_uuid);
-       LIST_INSERT_HEAD(&session->services, new_service, session_chain);
-       LIST_INSERT_HEAD(&necp_registered_service_list, new_service, kernel_chain);
-       lck_rw_done(&necp_kernel_policy_lock);
-
-       necp_send_success_response(session, NECP_PACKET_TYPE_REGISTER_SERVICE, message_id);
-       return;
-fail:
-       necp_send_error_response(session, NECP_PACKET_TYPE_REGISTER_SERVICE, message_id, response_error);
-}
-
-static void
-necp_handle_unregister_service(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset)
-{
-       int error;
-       struct necp_service_registration *service = NULL;
-       struct necp_service_registration *temp_service = NULL;
-       u_int32_t response_error = NECP_ERROR_INTERNAL;
-       struct necp_uuid_id_mapping *mapping = NULL;
-       uuid_t service_uuid;
-       uuid_clear(service_uuid);
-
-       if (session == NULL) {
-               NECPLOG0(LOG_ERR, "Failed to find session");
-               response_error = NECP_ERROR_INTERNAL;
-               goto fail;
-       }
-
-       // Read service uuid
-       error = necp_get_tlv(packet, NULL, 0, offset, NECP_TLV_SERVICE_UUID, sizeof(uuid_t), service_uuid, NULL);
-       if (error) {
-               NECPLOG(LOG_ERR, "Failed to get service UUID: %d", error);
-               response_error = NECP_ERROR_INVALID_TLV;
-               goto fail;
-       }
-
-       // Mark remove all matching services for this session
-       lck_rw_lock_exclusive(&necp_kernel_policy_lock);
-       mapping = necp_uuid_lookup_service_id_locked(service_uuid);
-       if (mapping != NULL) {
-               LIST_FOREACH_SAFE(service, &session->services, session_chain, temp_service) {
-                       if (service->service_id == mapping->id) {
-                               LIST_REMOVE(service, session_chain);
-                               LIST_REMOVE(service, kernel_chain);
-                               FREE(service, M_NECP);
-                       }
-               }
-               necp_remove_uuid_service_id_mapping(service_uuid);
-       }
-       lck_rw_done(&necp_kernel_policy_lock);
-
-       necp_send_success_response(session, NECP_PACKET_TYPE_UNREGISTER_SERVICE, message_id);
-       return;
-fail:
-       necp_send_error_response(session, NECP_PACKET_TYPE_UNREGISTER_SERVICE, message_id, response_error);
-}
-
 static necp_policy_id
-necp_handle_policy_add(struct necp_session *session, u_int32_t message_id, mbuf_t packet,
+necp_handle_policy_add(struct necp_session *session,
     u_int8_t *tlv_buffer, size_t tlv_buffer_length, int offset, int *return_error)
 {
        bool has_default_condition = FALSE;
@@ -2686,7 +2140,7 @@ necp_handle_policy_add(struct necp_session *session, u_int32_t message_id, mbuf_
        u_int32_t policy_result_size = 0;
 
        // Read policy order
-       error = necp_get_tlv(packet, tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_ORDER, sizeof(order), &order, NULL);
+       error = necp_get_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_ORDER, sizeof(order), &order, NULL);
        if (error) {
                NECPLOG(LOG_ERR, "Failed to get policy order: %d", error);
                response_error = NECP_ERROR_INVALID_TLV;
@@ -2694,13 +2148,13 @@ necp_handle_policy_add(struct necp_session *session, u_int32_t message_id, mbuf_
        }
 
        // Read policy result
-       cursor = necp_find_tlv(packet, tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_RESULT, &error, 0);
+       cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_RESULT, &error, 0);
        if (error || cursor < 0) {
                NECPLOG(LOG_ERR, "Failed to find policy result TLV: %d", error);
                response_error = NECP_ERROR_INVALID_TLV;
                goto fail;
        }
-       error = necp_get_tlv_at_offset(packet, tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &policy_result_size);
+       error = necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &policy_result_size);
        if (error || policy_result_size == 0) {
                NECPLOG(LOG_ERR, "Failed to get policy result length: %d", error);
                response_error = NECP_ERROR_INVALID_TLV;
@@ -2717,7 +2171,7 @@ necp_handle_policy_add(struct necp_session *session, u_int32_t message_id, mbuf_
                response_error = NECP_ERROR_INTERNAL;
                goto fail;
        }
-       error = necp_get_tlv_at_offset(packet, tlv_buffer, tlv_buffer_length, cursor, policy_result_size, policy_result, NULL);
+       error = necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, policy_result_size, policy_result, NULL);
        if (error) {
                NECPLOG(LOG_ERR, "Failed to get policy result: %d", error);
                response_error = NECP_ERROR_POLICY_RESULT_INVALID;
@@ -2731,11 +2185,11 @@ necp_handle_policy_add(struct necp_session *session, u_int32_t message_id, mbuf_
 
        if (necp_policy_result_requires_route_rules(policy_result, policy_result_size)) {
                // Read route rules conditions
-               for (cursor = necp_find_tlv(packet, tlv_buffer, tlv_buffer_length, offset, NECP_TLV_ROUTE_RULE, &error, 0);
+               for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_ROUTE_RULE, &error, 0);
                    cursor >= 0;
-                   cursor = necp_find_tlv(packet, tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_ROUTE_RULE, &error, 1)) {
+                   cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_ROUTE_RULE, &error, 1)) {
                        u_int32_t route_rule_size = 0;
-                       necp_get_tlv_at_offset(packet, tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &route_rule_size);
+                       necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &route_rule_size);
                        if (os_add_overflow(route_rules_array_size,
                            (sizeof(u_int8_t) + sizeof(u_int32_t) + route_rule_size),
                            &route_rules_array_size)) {
@@ -2763,12 +2217,12 @@ necp_handle_policy_add(struct necp_session *session, u_int32_t message_id, mbuf_
                }
 
                route_rules_array_cursor = 0;
-               for (cursor = necp_find_tlv(packet, tlv_buffer, tlv_buffer_length, offset, NECP_TLV_ROUTE_RULE, &error, 0);
+               for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_ROUTE_RULE, &error, 0);
                    cursor >= 0;
-                   cursor = necp_find_tlv(packet, tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_ROUTE_RULE, &error, 1)) {
+                   cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_ROUTE_RULE, &error, 1)) {
                        u_int8_t route_rule_type = NECP_TLV_ROUTE_RULE;
                        u_int32_t route_rule_size = 0;
-                       necp_get_tlv_at_offset(packet, tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &route_rule_size);
+                       necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &route_rule_size);
                        if (route_rule_size > 0 &&
                            (sizeof(route_rule_type) + sizeof(route_rule_size) + route_rule_size) <= (route_rules_array_size - route_rules_array_cursor)) {
                                // Add type
@@ -2780,7 +2234,7 @@ necp_handle_policy_add(struct necp_session *session, u_int32_t message_id, mbuf_
                                route_rules_array_cursor += sizeof(route_rule_size);
 
                                // Add value
-                               necp_get_tlv_at_offset(packet, tlv_buffer, tlv_buffer_length, cursor, route_rule_size, (route_rules_array + route_rules_array_cursor), NULL);
+                               necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, route_rule_size, (route_rules_array + route_rules_array_cursor), NULL);
 
                                if (!necp_policy_route_rule_is_valid((route_rules_array + route_rules_array_cursor), route_rule_size)) {
                                        NECPLOG0(LOG_ERR, "Failed to validate policy route rule");
@@ -2803,11 +2257,11 @@ necp_handle_policy_add(struct necp_session *session, u_int32_t message_id, mbuf_
        }
 
        // Read policy conditions
-       for (cursor = necp_find_tlv(packet, tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
+       for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
            cursor >= 0;
-           cursor = necp_find_tlv(packet, tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
+           cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
                u_int32_t condition_size = 0;
-               necp_get_tlv_at_offset(packet, tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &condition_size);
+               necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &condition_size);
 
                if (condition_size > 0) {
                        if (os_add_overflow(conditions_array_size,
@@ -2838,12 +2292,12 @@ necp_handle_policy_add(struct necp_session *session, u_int32_t message_id, mbuf_
        }
 
        conditions_array_cursor = 0;
-       for (cursor = necp_find_tlv(packet, tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
+       for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
            cursor >= 0;
-           cursor = necp_find_tlv(packet, tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
+           cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
                u_int8_t condition_type = NECP_TLV_POLICY_CONDITION;
                u_int32_t condition_size = 0;
-               necp_get_tlv_at_offset(packet, tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &condition_size);
+               necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &condition_size);
                if (condition_size > 0 &&
                    (sizeof(condition_type) + sizeof(condition_size) + condition_size) <= (conditions_array_size - conditions_array_cursor)) {
                        // Add type
@@ -2855,7 +2309,7 @@ necp_handle_policy_add(struct necp_session *session, u_int32_t message_id, mbuf_
                        conditions_array_cursor += sizeof(condition_size);
 
                        // Add value
-                       necp_get_tlv_at_offset(packet, tlv_buffer, tlv_buffer_length, cursor, condition_size, (conditions_array + conditions_array_cursor), NULL);
+                       necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, condition_size, (conditions_array + conditions_array_cursor), NULL);
                        if (!necp_policy_condition_is_valid((conditions_array + conditions_array_cursor), condition_size, necp_policy_result_get_type_from_buffer(policy_result, policy_result_size))) {
                                NECPLOG0(LOG_ERR, "Failed to validate policy condition");
                                response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
@@ -2910,9 +2364,6 @@ necp_handle_policy_add(struct necp_session *session, u_int32_t message_id, mbuf_
                goto fail;
        }
 
-       if (packet != NULL) {
-               necp_send_policy_id_response(session, NECP_PACKET_TYPE_POLICY_ADD, message_id, policy->local_id);
-       }
        return policy->local_id;
 
 fail:
@@ -2926,168 +2377,12 @@ fail:
                FREE(route_rules_array, M_NECP);
        }
 
-       if (packet != NULL) {
-               necp_send_error_response(session, NECP_PACKET_TYPE_POLICY_ADD, message_id, response_error);
-       }
        if (return_error != NULL) {
                *return_error = necp_get_posix_error_for_necp_error(response_error);
        }
        return 0;
 }
 
-static void
-necp_handle_policy_get(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset)
-{
-#pragma unused(offset)
-       int error;
-       u_int8_t *response = NULL;
-       u_int8_t *cursor = NULL;
-       u_int32_t response_error = NECP_ERROR_INTERNAL;
-       necp_policy_id policy_id = 0;
-       u_int32_t order_tlv_size = 0;
-       u_int32_t result_tlv_size = 0;
-       u_int32_t response_size = 0;
-
-       struct necp_session_policy *policy = NULL;
-
-       // Read policy id
-       error = necp_get_tlv(packet, NULL, 0, offset, NECP_TLV_POLICY_ID, sizeof(policy_id), &policy_id, NULL);
-       if (error) {
-               NECPLOG(LOG_ERR, "Failed to get policy id: %d", error);
-               response_error = NECP_ERROR_INVALID_TLV;
-               goto fail;
-       }
-
-       policy = necp_policy_find(session, policy_id);
-       if (policy == NULL || policy->pending_deletion) {
-               NECPLOG(LOG_ERR, "Failed to find policy with id %d", policy_id);
-               response_error = NECP_ERROR_POLICY_ID_NOT_FOUND;
-               goto fail;
-       }
-
-       order_tlv_size = sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(necp_policy_order);
-       result_tlv_size = (policy->result_size ? (sizeof(u_int8_t) + sizeof(u_int32_t) + policy->result_size) : 0);
-       response_size = sizeof(struct necp_packet_header) + order_tlv_size + result_tlv_size + policy->conditions_size;
-       MALLOC(response, u_int8_t *, response_size, M_NECP, M_WAITOK);
-       if (response == NULL) {
-               necp_send_error_response(session, NECP_PACKET_TYPE_POLICY_GET, message_id, NECP_ERROR_INTERNAL);
-               return;
-       }
-
-       cursor = response;
-       cursor = necp_buffer_write_packet_header(cursor, NECP_PACKET_TYPE_POLICY_GET, NECP_PACKET_FLAGS_RESPONSE, message_id);
-       cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ORDER, sizeof(necp_policy_order), &policy->order, response, response_size);
-
-       if (result_tlv_size) {
-               cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_RESULT, policy->result_size, &policy->result, response, response_size);
-       }
-       if (policy->conditions_size) {
-               memcpy(((u_int8_t *)(void *)(cursor)), policy->conditions, policy->conditions_size);
-       }
-
-       if (!necp_send_ctl_data(session, (u_int8_t *)response, response_size)) {
-               NECPLOG0(LOG_ERR, "Failed to send response");
-       }
-
-       FREE(response, M_NECP);
-       return;
-
-fail:
-       necp_send_error_response(session, NECP_PACKET_TYPE_POLICY_GET, message_id, response_error);
-}
-
-static void
-necp_handle_policy_delete(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset)
-{
-       int error;
-       u_int32_t response_error = NECP_ERROR_INTERNAL;
-       necp_policy_id policy_id = 0;
-
-       struct necp_session_policy *policy = NULL;
-
-       // Read policy id
-       error = necp_get_tlv(packet, NULL, 0, offset, NECP_TLV_POLICY_ID, sizeof(policy_id), &policy_id, NULL);
-       if (error) {
-               NECPLOG(LOG_ERR, "Failed to get policy id: %d", error);
-               response_error = NECP_ERROR_INVALID_TLV;
-               goto fail;
-       }
-
-       policy = necp_policy_find(session, policy_id);
-       if (policy == NULL || policy->pending_deletion) {
-               NECPLOG(LOG_ERR, "Failed to find policy with id %d", policy_id);
-               response_error = NECP_ERROR_POLICY_ID_NOT_FOUND;
-               goto fail;
-       }
-
-       necp_policy_mark_for_deletion(session, policy);
-
-       necp_send_success_response(session, NECP_PACKET_TYPE_POLICY_DELETE, message_id);
-       return;
-
-fail:
-       necp_send_error_response(session, NECP_PACKET_TYPE_POLICY_DELETE, message_id, response_error);
-}
-
-static void
-necp_handle_policy_apply_all(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset)
-{
-#pragma unused(packet, offset)
-       necp_policy_apply_all(session);
-       necp_send_success_response(session, NECP_PACKET_TYPE_POLICY_APPLY_ALL, message_id);
-}
-
-static void
-necp_handle_policy_list_all(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset)
-{
-#pragma unused(packet, offset)
-       u_int32_t tlv_size = (sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(u_int32_t));
-       u_int32_t response_size = 0;
-       u_int8_t *response = NULL;
-       u_int8_t *cursor = NULL;
-       int num_policies = 0;
-       int cur_policy_index = 0;
-       struct necp_session_policy *policy;
-
-       LIST_FOREACH(policy, &session->policies, chain) {
-               if (!policy->pending_deletion) {
-                       num_policies++;
-               }
-       }
-
-       // Create a response with one Policy ID TLV for each policy
-       response_size = sizeof(struct necp_packet_header) + num_policies * tlv_size;
-       MALLOC(response, u_int8_t *, response_size, M_NECP, M_WAITOK);
-       if (response == NULL) {
-               necp_send_error_response(session, NECP_PACKET_TYPE_POLICY_LIST_ALL, message_id, NECP_ERROR_INTERNAL);
-               return;
-       }
-
-       cursor = response;
-       cursor = necp_buffer_write_packet_header(cursor, NECP_PACKET_TYPE_POLICY_LIST_ALL, NECP_PACKET_FLAGS_RESPONSE, message_id);
-
-       LIST_FOREACH(policy, &session->policies, chain) {
-               if (!policy->pending_deletion && cur_policy_index < num_policies) {
-                       cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, sizeof(u_int32_t), &policy->local_id, response, response_size);
-                       cur_policy_index++;
-               }
-       }
-
-       if (!necp_send_ctl_data(session, (u_int8_t *)response, response_size)) {
-               NECPLOG0(LOG_ERR, "Failed to send response");
-       }
-
-       FREE(response, M_NECP);
-}
-
-static void
-necp_handle_policy_delete_all(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset)
-{
-#pragma unused(packet, offset)
-       necp_policy_mark_all_for_deletion(session);
-       necp_send_success_response(session, NECP_PACKET_TYPE_POLICY_DELETE_ALL, message_id);
-}
-
 static necp_policy_id
 necp_policy_get_new_id(struct necp_session *session)
 {
@@ -3203,10 +2498,8 @@ necp_policy_get_new_id(struct necp_session *session)
  *     ...
  */
 static int
-necp_handle_policy_dump_all(struct necp_session *session, u_int32_t message_id, mbuf_t packet,
-    user_addr_t out_buffer, size_t out_buffer_length, int offset)
+necp_handle_policy_dump_all(user_addr_t out_buffer, size_t out_buffer_length)
 {
-#pragma unused(offset)
        struct necp_kernel_socket_policy *policy = NULL;
        int policy_i;
        int policy_count = 0;
@@ -3547,33 +2840,6 @@ necp_handle_policy_dump_all(struct necp_session *session, u_int32_t message_id,
        // UNLOCK
        lck_rw_done(&necp_kernel_policy_lock);
 
-       // Send packet
-       if (packet != NULL) {
-               u_int32_t total_result_length = sizeof(struct necp_packet_header) + total_tlv_len;
-
-               // Allow malloc to wait, since the total buffer may be large and we are not holding any locks
-               MALLOC(result_buf, u_int8_t *, total_result_length, M_NECP, M_WAITOK | M_ZERO);
-               if (result_buf == NULL) {
-                       NECPLOG(LOG_DEBUG, "Failed to allocate result_buffer (%u bytes)", total_result_length);
-                       REPORT_ERROR(NECP_ERROR_INTERNAL);
-               }
-
-               result_buf_cursor = result_buf;
-               result_buf_cursor = necp_buffer_write_packet_header(result_buf_cursor, NECP_PACKET_TYPE_POLICY_DUMP_ALL, NECP_PACKET_FLAGS_RESPONSE, message_id);
-
-               for (int i = 0; i < policy_count; i++) {
-                       if (tlv_buffer_pointers[i] != NULL) {
-                               result_buf_cursor = necp_buffer_write_tlv(result_buf_cursor, NECP_TLV_POLICY_DUMP, tlv_buffer_lengths[i], tlv_buffer_pointers[i], result_buf, total_result_length);
-                       }
-               }
-
-               if (!necp_send_ctl_data(session, result_buf, result_buf_cursor - result_buf)) {
-                       NECPLOG(LOG_ERR, "Failed to send response (%u bytes)", result_buf_cursor - result_buf);
-               } else {
-                       NECPLOG(LOG_ERR, "Sent data worth %u bytes. Total result buffer length was %u bytes", result_buf_cursor - result_buf, total_result_length);
-               }
-       }
-
        // Copy out
        if (out_buffer != 0) {
                if (out_buffer_length < total_tlv_len + sizeof(u_int32_t)) {
@@ -3610,13 +2876,6 @@ necp_handle_policy_dump_all(struct necp_session *session, u_int32_t message_id,
 done:
 
        if (error_occured) {
-               if (packet != NULL) {
-                       if (!necp_send_error_response(session, NECP_PACKET_TYPE_POLICY_DUMP_ALL, message_id, response_error)) {
-                               NECPLOG0(LOG_ERR, "Failed to send error response");
-                       } else {
-                               NECPLOG0(LOG_ERR, "Sent error response");
-                       }
-               }
                error_code = necp_get_posix_error_for_necp_error(response_error);
        }
 
index b6f9db0afe9862dbd55007845eb184b34b8a6498..5bf7a9de16d7d41e23dcaff800e1b13d839b2080 100644 (file)
@@ -38,7 +38,7 @@
 #include <net/if.h>
 
 /*
- * Name registered by the ipsec kernel control
+ * Name registered by the NECP
  */
 #define NECP_CONTROL_NAME "com.apple.net.necp_control"
 
index 5344b01a024c69312f4af8d0fa8371bced5a63b7..0cbc0fc37bfd9fa1d3ed7e5189f409124bc18cc6 100644 (file)
 #include <net/pktsched/pktsched.h>
 #include <net/pktsched/pktsched_netem.h>
 
+/* <rdar://problem/55953523> M8 Perf: Remove norm_dist_table on armv7k (16K wired win) */
+/* compile out netem on platforms where skywalk is not enabled by default */
+#if __LP64__
+#define CONFIG_NETEM 1
+#else
+#define CONFIG_NETEM 0
+#endif
+
+#if CONFIG_NETEM
+
 enum {
        NETEM_LOG_ERROR = 0,
        NETEM_LOG_INFO = 1,
@@ -1521,3 +1531,55 @@ done:
        netem_log(NETEM_LOG_INFO, "netem config ret %d", ret);
        return ret;
 }
+
+#else /* !CONFIG_NETEM */
+
+int
+netem_init(void)
+{
+       return 0;
+}
+
+int
+netem_config(struct netem **ne, const char *name,
+    const struct if_netem_params *p, void *output_handle,
+    int (*output_func)(void *handle, pktsched_pkt_t *pkts, uint32_t n_pkts),
+    uint32_t output_max_batch_size)
+{
+#pragma unused(ne, name, p, output_handle, output_func, output_max_batch_size)
+       printf("%s error %d: unavailable on this platform\n", __func__, ENOTSUP);
+       return ENOTSUP;
+}
+
+void
+__attribute__((noreturn))
+netem_get_params(struct netem *ne, struct if_netem_params *p)
+{
+#pragma unused(ne, p)
+       panic("unexpected netem call");
+}
+
+void
+__attribute__((noreturn))
+netem_destroy(struct netem *ne)
+{
+#pragma unused(ne)
+       panic("unexpected netem call");
+}
+
+int
+netem_enqueue(struct netem *ne, classq_pkt_t *p, boolean_t *pdrop)
+{
+#pragma unused(ne, p, pdrop)
+       panic("unexpected netem call");
+       return 0;
+}
+
+int
+netem_dequeue(struct netem *ne, pktsched_pkt_t *p, boolean_t *ppending)
+{
+#pragma unused(ne, p, ppending)
+       panic("unexpected netem call");
+       return 0;
+}
+#endif /* !CONFIG_NETEM */
index b63ba0183744560e61d098c382ac4dca1c38f96f..156c375b64448c54cacccfc533917be8f8da7b95 100644 (file)
@@ -603,10 +603,12 @@ sa_copy(struct sockaddr *src, struct sockaddr_storage *dst,
 
        if (af == AF_INET) {
                bcopy(src, dst, sizeof (struct sockaddr_in));
+               dst->ss_len = sizeof(struct sockaddr_in);
                if (pifscope == NULL || ifscope != IFSCOPE_NONE)
                        sin_set_ifscope(SA(dst), ifscope);
        } else {
                bcopy(src, dst, sizeof (struct sockaddr_in6));
+               dst->ss_len = sizeof(struct sockaddr_in6);
                if (pifscope != NULL &&
                    IN6_IS_SCOPE_EMBED(&SIN6(dst)->sin6_addr)) {
                        unsigned int eifscope;
index a8b2601593c7397ac9d3339cecad3917be078234..9633e6b4b3e6070b332ea912d6b238a9e5954057 100644 (file)
@@ -1084,6 +1084,9 @@ rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo)
                if ((cp + sa->sa_len) > cplim) {
                        return EINVAL;
                }
+               if (sa->sa_len > sizeof(struct sockaddr_storage)) {
+                       return EINVAL;
+               }
                /*
                 * there are no more.. quit now
                 * If there are more bits, they are in error.
index ebd14a5b1e5e9ea9a08be57c970c3e98682cbc8e..84f3f4f483e4b76050665e4f5feed971ef7a0722 100644 (file)
@@ -2348,11 +2348,15 @@ flow_divert_handle_app_map_create(struct flow_divert_group *group, mbuf_t packet
        FDLOG(LOG_INFO, &nil_pcb, "Nodes count = %lu, child maps count = %lu, bytes_count = %lu",
            new_trie.nodes_count, new_trie.child_maps_count, new_trie.bytes_count);
 
-       nodes_mem_size = (sizeof(*new_trie.nodes) * new_trie.nodes_count);
-       child_maps_mem_size = (sizeof(*new_trie.child_maps) * CHILD_MAP_SIZE * new_trie.child_maps_count);
-       bytes_mem_size = (sizeof(*new_trie.bytes) * new_trie.bytes_count);
+       if (os_mul_overflow(sizeof(*new_trie.nodes), new_trie.nodes_count, &nodes_mem_size) ||
+           os_mul3_overflow(sizeof(*new_trie.child_maps), CHILD_MAP_SIZE, new_trie.child_maps_count, &child_maps_mem_size) ||
+           os_mul_overflow(sizeof(*new_trie.bytes), new_trie.bytes_count, &bytes_mem_size) ||
+           os_add3_overflow(nodes_mem_size, child_maps_mem_size, bytes_mem_size, &trie_memory_size)) {
+               FDLOG0(LOG_ERR, &nil_pcb, "Overflow while computing trie memory sizes");
+               lck_rw_done(&group->lck);
+               return;
+       }
 
-       trie_memory_size = nodes_mem_size + child_maps_mem_size + bytes_mem_size;
        if (trie_memory_size > FLOW_DIVERT_MAX_TRIE_MEMORY) {
                FDLOG(LOG_ERR, &nil_pcb, "Trie memory size (%lu) is too big (maximum is %u)", trie_memory_size, FLOW_DIVERT_MAX_TRIE_MEMORY);
                lck_rw_done(&group->lck);
index f6f9baf01ca3a8332de18c9c4d4c1306591cd7e9..0ec625ec64a4149be0503213d9992091845b01be 100644 (file)
@@ -368,7 +368,7 @@ ipfwsyslog( int level, const char *format, ...)
        bzero(msgBuf, msgsize);
        bzero(&ev_msg, sizeof(struct kev_msg));
        va_start( ap, format );
-       loglen = vsnprintf(msgBuf, msgsize, format, ap);
+       loglen = vscnprintf(msgBuf, msgsize, format, ap);
        va_end( ap );
 
        ev_msg.vendor_code    = KEV_VENDOR_APPLE;
@@ -1251,7 +1251,7 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ether_header *eh,
                        if (f->reserved_1 == IPFW_RULE_INACTIVE) {
                                break;
                        }
-                       len = snprintf(SNPARGS(action2, 0), "Forward to %s",
+                       len = scnprintf(SNPARGS(action2, 0), "Forward to %s",
                            inet_ntop(AF_INET, &sa->sa.sin_addr, ipv4str, sizeof(ipv4str)));
                        if (sa->sa.sin_port) {
                                snprintf(SNPARGS(action2, len), ":%d",
@@ -1288,7 +1288,7 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ether_header *eh,
                offset = ip_off & IP_OFFMASK;
                switch (ip->ip_p) {
                case IPPROTO_TCP:
-                       len = snprintf(SNPARGS(proto, 0), "TCP %s",
+                       len = scnprintf(SNPARGS(proto, 0), "TCP %s",
                            inet_ntop(AF_INET, &ip->ip_src, ipv4str, sizeof(ipv4str)));
                        if (offset == 0) {
                                snprintf(SNPARGS(proto, len), ":%d %s:%d",
@@ -1302,7 +1302,7 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ether_header *eh,
                        break;
 
                case IPPROTO_UDP:
-                       len = snprintf(SNPARGS(proto, 0), "UDP %s",
+                       len = scnprintf(SNPARGS(proto, 0), "UDP %s",
                            inet_ntop(AF_INET, &ip->ip_src, ipv4str, sizeof(ipv4str)));
                        if (offset == 0) {
                                snprintf(SNPARGS(proto, len), ":%d %s:%d",
@@ -1317,20 +1317,20 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ether_header *eh,
 
                case IPPROTO_ICMP:
                        if (offset == 0) {
-                               len = snprintf(SNPARGS(proto, 0),
+                               len = scnprintf(SNPARGS(proto, 0),
                                    "ICMP:%u.%u ",
                                    icmp->icmp_type, icmp->icmp_code);
                        } else {
-                               len = snprintf(SNPARGS(proto, 0), "ICMP ");
+                               len = scnprintf(SNPARGS(proto, 0), "ICMP ");
                        }
-                       len += snprintf(SNPARGS(proto, len), "%s",
+                       len += scnprintf(SNPARGS(proto, len), "%s",
                            inet_ntop(AF_INET, &ip->ip_src, ipv4str, sizeof(ipv4str)));
                        snprintf(SNPARGS(proto, len), " %s",
                            inet_ntop(AF_INET, &ip->ip_dst, ipv4str, sizeof(ipv4str)));
                        break;
 
                default:
-                       len = snprintf(SNPARGS(proto, 0), "P:%d %s", ip->ip_p,
+                       len = scnprintf(SNPARGS(proto, 0), "P:%d %s", ip->ip_p,
                            inet_ntop(AF_INET, &ip->ip_src, ipv4str, sizeof(ipv4str)));
                        snprintf(SNPARGS(proto, len), " %s",
                            inet_ntop(AF_INET, &ip->ip_dst, ipv4str, sizeof(ipv4str)));
index 25a51db92a2ce203d139a8800fe813977a1b244e..3b3d83765e9adfd39355c5b3a83cd1ac18e2fa82 100644 (file)
@@ -646,9 +646,14 @@ mptcp_output(struct mptses *mpte)
        int error = 0;
 
        mp_so = mptetoso(mpte);
-       socket_lock_assert_owned(mp_so);
        mp_tp = mpte->mpte_mptcb;
 
+       socket_lock_assert_owned(mp_so);
+
+       if (mp_so->so_flags & SOF_DEFUNCT) {
+               return 0;
+       }
+
        VERIFY(!(mpte->mpte_mppcb->mpp_flags & MPP_WUPCALL));
        mpte->mpte_mppcb->mpp_flags |= MPP_WUPCALL;
 
index da19de2095fbf3579c1c813bfa33dde35af08b94..9e8637a928dffa7e5f7a0255ec6639d40457db4d 100644 (file)
@@ -5414,6 +5414,14 @@ mptcp_output_getm_dsnmap64(struct socket *so, int off, uint64_t *dsn,
 
        VERIFY(off >= 0);
 
+       if (m == NULL && (so->so_flags & SOF_DEFUNCT)) {
+               *dsn = 0;
+               *relseq = 0;
+               *data_len = 0;
+               *dss_csum = 0;
+               return;
+       }
+
        /*
         * In the subflow socket, the DSN sequencing can be discontiguous,
         * but the subflow sequence mapping is contiguous. Use the subflow
@@ -5433,7 +5441,6 @@ mptcp_output_getm_dsnmap64(struct socket *so, int off, uint64_t *dsn,
                }
        }
 
-       VERIFY(m);
        VERIFY(off >= 0);
        VERIFY(m->m_pkthdr.mp_rlen <= UINT16_MAX);
 
@@ -5567,6 +5574,10 @@ mptcp_adj_sendlen(struct socket *so, int32_t off)
        uint16_t mdss_data_len;
        uint16_t dss_csum;
 
+       if (so->so_snd.sb_mb == NULL && (so->so_flags & SOF_DEFUNCT)) {
+               return 0;
+       }
+
        mptcp_output_getm_dsnmap64(so, off, &mdss_dsn, &mdss_subflow_seq,
            &mdss_data_len, &dss_csum);
 
@@ -5584,15 +5595,8 @@ mptcp_adj_sendlen(struct socket *so, int32_t off)
                mdss_subflow_off--;
        }
 
-       if (off < mdss_subflow_off) {
-               printf("%s off %d mdss_subflow_off %d mdss_subflow_seq %u iss %u suna %u\n", __func__,
-                   off, mdss_subflow_off, mdss_subflow_seq, mpts->mpts_iss, tp->snd_una);
-       }
        VERIFY(off >= mdss_subflow_off);
 
-       mptcplog((LOG_DEBUG, "%s dlen %u off %d sub_off %d sub_seq %u iss %u suna %u\n",
-           __func__, mdss_data_len, off, mdss_subflow_off, mdss_subflow_seq,
-           mpts->mpts_iss, tp->snd_una), MPTCP_SENDER_DBG, MPTCP_LOGLVL_VERBOSE);
        return mdss_data_len - (off - mdss_subflow_off);
 }
 
index d7d04516aa2ea1c0d8d5e6dbd0456a103ed4cef0..b8fbb62d4acb1e57dcf043b4e93794d263dce447 100644 (file)
@@ -2794,6 +2794,7 @@ findpcb:
                                TCP_LOG_DROP_PCB(TCP_LOG_HDR, th, tp, false, " in_pcbinshash failed");
                                goto drop;
                        }
+                       socket_lock(oso, 0);
 #if INET6
                        if (isipv6) {
                                /*
@@ -2822,7 +2823,6 @@ findpcb:
                                inp->inp_options = ip_srcroute();
                                inp->inp_ip_tos = oinp->inp_ip_tos;
                        }
-                       socket_lock(oso, 0);
 #if IPSEC
                        /* copy old policy into new socket's */
                        if (sotoinpcb(oso)->inp_sp) {
@@ -3207,8 +3207,6 @@ findpcb:
                                        tp->t_rexmtthresh = tcprexmtthresh;
                                }
 
-                               m_freem(m);
-
                                /*
                                 * If all outstanding data are acked, stop
                                 * retransmit timer, otherwise restart timer
@@ -3248,6 +3246,8 @@ findpcb:
 
                                tcp_tfo_rcv_ack(tp, th);
 
+                               m_freem(m);
+
                                tcp_check_timer_state(tp);
 
                                tcp_handle_wakeup(so, read_wakeup, write_wakeup);
index ee69afd6fd91f2191c0cd72718265f8f3844ed61..c19dc1706959300eba3b285aabc8066844266cd9 100644 (file)
@@ -128,25 +128,27 @@ static int
 sysctl_msec_to_ticks SYSCTL_HANDLER_ARGS
 {
 #pragma unused(arg2)
-       int error, s, tt;
+       int error, temp;
+       long s, tt;
 
        tt = *(int *)arg1;
-       if (tt < 0 || tt >= INT_MAX / 1000) {
+       s = tt * 1000 / TCP_RETRANSHZ;
+       if (tt < 0 || s > INT_MAX) {
                return EINVAL;
        }
-       s = tt * 1000 / TCP_RETRANSHZ;
+       temp = (int)s;
 
-       error = sysctl_handle_int(oidp, &s, 0, req);
+       error = sysctl_handle_int(oidp, &temp, 0, req);
        if (error || !req->newptr) {
                return error;
        }
 
        tt = s * TCP_RETRANSHZ / 1000;
-       if (tt < 1) {
+       if (tt < 1 || tt > INT_MAX) {
                return EINVAL;
        }
 
-       *(int *)arg1 = tt;
+       *(int *)arg1 = (int)tt;
        SYSCTL_SKMEM_UPDATE_AT_OFFSET(arg2, *(int*)arg1);
        return 0;
 }
index e2dfd716bb384f174b6cf65d779de744f108d60a..7e2151c4be5f4ddaae82b6473ca8d2f99536eb21 100644 (file)
@@ -483,53 +483,53 @@ ip6fw_report(struct ip6_fw *f, struct ip6_hdr *ip6,
 
        switch (nxt) {
        case IPPROTO_TCP:
-               len = snprintf(SNPARGS(proto, 0), "TCP [%s]",
+               len = scnprintf(SNPARGS(proto, 0), "TCP [%s]",
                    ip6_sprintf(&ip6->ip6_src));
                if (off > 0) {
-                       len += snprintf(SNPARGS(proto, len), ":%d ",
+                       len += scnprintf(SNPARGS(proto, len), ":%d ",
                            ntohs(tcp6->th_sport));
                } else {
-                       len += snprintf(SNPARGS(proto, len), " ");
+                       len += scnprintf(SNPARGS(proto, len), " ");
                }
-               len += snprintf(SNPARGS(proto, len), "[%s]",
+               len += scnprintf(SNPARGS(proto, len), "[%s]",
                    ip6_sprintf(&ip6->ip6_dst));
                if (off > 0) {
-                       snprintf(SNPARGS(proto, len), ":%d",
+                       scnprintf(SNPARGS(proto, len), ":%d",
                            ntohs(tcp6->th_dport));
                }
                break;
        case IPPROTO_UDP:
-               len = snprintf(SNPARGS(proto, 0), "UDP [%s]",
+               len = scnprintf(SNPARGS(proto, 0), "UDP [%s]",
                    ip6_sprintf(&ip6->ip6_src));
                if (off > 0) {
-                       len += snprintf(SNPARGS(proto, len), ":%d ",
+                       len += scnprintf(SNPARGS(proto, len), ":%d ",
                            ntohs(udp->uh_sport));
                } else {
-                       len += snprintf(SNPARGS(proto, len), " ");
+                       len += scnprintf(SNPARGS(proto, len), " ");
                }
-               len += snprintf(SNPARGS(proto, len), "[%s]",
+               len += scnprintf(SNPARGS(proto, len), "[%s]",
                    ip6_sprintf(&ip6->ip6_dst));
                if (off > 0) {
-                       snprintf(SNPARGS(proto, len), ":%d",
+                       scnprintf(SNPARGS(proto, len), ":%d",
                            ntohs(udp->uh_dport));
                }
                break;
        case IPPROTO_ICMPV6:
                if (off > 0) {
-                       len = snprintf(SNPARGS(proto, 0), "IPV6-ICMP:%u.%u ",
+                       len = scnprintf(SNPARGS(proto, 0), "IPV6-ICMP:%u.%u ",
                            icmp6->icmp6_type, icmp6->icmp6_code);
                } else {
-                       len = snprintf(SNPARGS(proto, 0), "IPV6-ICMP ");
+                       len = scnprintf(SNPARGS(proto, 0), "IPV6-ICMP ");
                }
-               len += snprintf(SNPARGS(proto, len), "[%s]",
+               len += scnprintf(SNPARGS(proto, len), "[%s]",
                    ip6_sprintf(&ip6->ip6_src));
-               snprintf(SNPARGS(proto, len), " [%s]",
+               scnprintf(SNPARGS(proto, len), " [%s]",
                    ip6_sprintf(&ip6->ip6_dst));
                break;
        default:
-               len = snprintf(SNPARGS(proto, 0), "P:%d [%s]", nxt,
+               len = scnprintf(SNPARGS(proto, 0), "P:%d [%s]", nxt,
                    ip6_sprintf(&ip6->ip6_src));
-               snprintf(SNPARGS(proto, len), " [%s]",
+               scnprintf(SNPARGS(proto, len), " [%s]",
                    ip6_sprintf(&ip6->ip6_dst));
                break;
        }
index 0adab689bc5fb2c0c258e5eed824b4dd8bbba145..d0a6fd32765c48916a55b56ea11dcb4f86a49b0c 100644 (file)
@@ -328,9 +328,9 @@ nfs_location_mntfromname(struct nfs_fs_locations *locs, struct nfs_location_inde
                        if (*fsl->nl_servers[idx.nli_serv]->ns_addresses[idx.nli_addr]) {
                                name = fsl->nl_servers[idx.nli_serv]->ns_addresses[idx.nli_addr];
                        }
-                       cnt = snprintf(p, size, "<%s>:", name);
+                       cnt = scnprintf(p, size, "<%s>:", name);
                } else {
-                       cnt = snprintf(p, size, "%s:", name);
+                       cnt = scnprintf(p, size, "%s:", name);
                }
                p += cnt;
                size -= cnt;
@@ -345,7 +345,7 @@ nfs_location_mntfromname(struct nfs_fs_locations *locs, struct nfs_location_inde
        }
        /* append each server path component */
        for (i = 0; (size > 0) && (i < (int)fsl->nl_path.np_compcount); i++) {
-               cnt = snprintf(p, size, "/%s", fsl->nl_path.np_components[i]);
+               cnt = scnprintf(p, size, "/%s", fsl->nl_path.np_components[i]);
                p += cnt;
                size -= cnt;
        }
index 0e83375cdd27820b0b87d439b4ed417f2c1d56b1..5d6361ccae5bf8fd2f47b73af9ddeef38fd40f50 100644 (file)
@@ -461,7 +461,7 @@ workq_thread_needs_params_change(workq_threadreq_t req, struct uthread *uth)
                return true;
        }
 
-       if ((req_flags & TRP_POLICY) && cur_trp.trp_pol != cur_trp.trp_pol) {
+       if ((req_flags & TRP_POLICY) && req_trp.trp_pol != cur_trp.trp_pol) {
                return true;
        }
 
@@ -1856,7 +1856,6 @@ fixedpri:
                }
        }
 
-
 done:
        if (qos_rv && voucher_rv) {
                /* Both failed, give that a unique error. */
@@ -3127,9 +3126,8 @@ again:
                 */
                wq->wq_creator = uth = workq_pop_idle_thread(wq, UT_WORKQ_OVERCOMMIT,
                    &needs_wakeup);
-               if (workq_thread_needs_priority_change(req, uth)) {
-                       workq_thread_reset_pri(wq, uth, req, /*unpark*/ true);
-               }
+               /* Always reset the priorities on the newly chosen creator */
+               workq_thread_reset_pri(wq, uth, req, /*unpark*/ true);
                workq_turnstile_update_inheritor(wq, uth->uu_thread,
                    TURNSTILE_INHERITOR_THREAD);
                WQ_TRACE_WQ(TRACE_wq_creator_select | DBG_FUNC_NONE,
index 0824413708e55c8ec7108ce3ead9395678f4d012..67a0b9b2bfc8612e56cfe26c3e7ddda8e5070f59 100644 (file)
@@ -302,7 +302,6 @@ enum workq_set_self_flags {
        WORKQ_SET_SELF_FIXEDPRIORITY_FLAG   = 0x04,
        WORKQ_SET_SELF_TIMESHARE_FLAG       = 0x08,
        WORKQ_SET_SELF_WQ_KEVENT_UNBIND     = 0x10,
-       WORKQ_SET_SELF_ALTERNATE_AMX        = 0x20,
 };
 
 void workq_proc_suspended(struct proc *p);
index 25e569fcb8c6e754c035dfd0737238071a3d12e9..7b5d56379bcc7ef200c5e954cbd6372a94ddb7d7 100644 (file)
@@ -38,6 +38,8 @@
 /* MAC flags used by F_ADDFILESIGS_* */
 #define MAC_VNODE_CHECK_DYLD_SIM 0x1   /* tells the MAC framework that dyld-sim is being loaded */
 
+#define CLEAR_LV_ENTITLEMENT "com.apple.private.security.clear-library-validation"
+
 /* csops  operations */
 #define CS_OPS_STATUS           0       /* return status */
 #define CS_OPS_MARKINVALID      1       /* invalidate process */
@@ -56,6 +58,7 @@
 #define CS_OPS_CLEARINSTALLER   12      /* clear INSTALLER flag */
 #define CS_OPS_CLEARPLATFORM 13 /* clear platform binary status (DEVELOPMENT-only) */
 #define CS_OPS_TEAMID       14  /* get team id */
+#define CS_OPS_CLEAR_LV     15  /* clear the library validation flag */
 
 #define CS_MAX_TEAMID_LEN       64
 
index cfc07b33fe813b8b77d2232857e8f8b5ec23fed2..e7bb586970f8910b3710f569f407669645d9eb90 100644 (file)
@@ -1185,6 +1185,13 @@ typedef struct dtrace_cred {
        uint16_t                dcr_action;
 } dtrace_cred_t;
 
+typedef struct dtrace_format {
+       uint64_t dtf_refcount;
+       char dtf_str[];
+} dtrace_format_t;
+
+#define DTRACE_FORMAT_SIZE(fmt) (strlen(fmt->dtf_str) + 1 + sizeof(dtrace_format_t))
+
 /*
  * DTrace Consumer State
  *
@@ -1224,7 +1231,7 @@ struct dtrace_state {
        char dts_speculates;                    /* boolean: has speculations */
        char dts_destructive;                   /* boolean: has dest. actions */
        int dts_nformats;                       /* number of formats */
-       char **dts_formats;                     /* format string array */
+       dtrace_format_t **dts_formats;          /* format string array */
        dtrace_optval_t dts_options[DTRACEOPT_MAX]; /* options */
        dtrace_cred_t dts_cred;                 /* credentials */
        size_t dts_nretained;                   /* number of retained enabs */
@@ -1314,7 +1321,6 @@ typedef struct dtrace_errhash {
 
 #endif /* DTRACE_ERRDEBUG */
 
-
 typedef struct dtrace_string dtrace_string_t;
 
 typedef struct dtrace_string {
index 87907d17242875d16b927bc9c593f5950720b232..7b1d26944316b84224f4a0b047a7f2ffcea9e8ed 100644 (file)
@@ -322,7 +322,7 @@ persona_desc(struct persona *persona, int locked)
        char *end = p + sizeof(persona->pna_desc) - 1;
 
        *end = 0;
-       p += snprintf(p, end - p, "%s/%d:%d",
+       p += scnprintf(p, end - p, "%s/%d:%d",
            persona->pna_login,
            kauth_cred_getuid(persona->pna_cred),
            kauth_cred_getgid(persona->pna_cred));
index 3a3622fc781d3d2a3ec20470a4869891537fc858..6b1d11c5c4c2a8cc408c1eb64627687718e833d8 100644 (file)
@@ -263,7 +263,7 @@ xnupost_export_testdata(void * outp, uint32_t size, uint32_t * lenp)
        kret = copyout(&version[0], user_addr, length_to_copy);
        RET_IF_OP_FAIL;
 
-       length_to_copy = MIN((uint32_t)(strlen(PE_boot_args()) + 1), OSVERSIZE);
+       length_to_copy = MIN((uint32_t)(strlen(PE_boot_args()) + 1), BOOT_LINE_LENGTH);
        kret           = kcdata_get_memory_addr(&kcd, STACKSHOT_KCTYPE_BOOTARGS, length_to_copy, &user_addr);
        RET_IF_OP_FAIL;
        kret = copyout(PE_boot_args(), user_addr, length_to_copy);
diff --git a/bsd/tests/ctrr_test_sysctl.c b/bsd/tests/ctrr_test_sysctl.c
new file mode 100644 (file)
index 0000000..bea84e1
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+#include <sys/sysctl.h>
+
index 693bf9de740a5d8cfc1bb886267c18612e1b9061..c85c8485f19b7c3bd9b6e14497fd79d84aa4090b 100644 (file)
@@ -1253,7 +1253,7 @@ vfs_context_get_special_port(vfs_context_t ctx, int which, ipc_port_t *portp)
  *              int                            Index of special port
  *              ipc_port_t                     New special port
  *
- * Returns:    kern_return_t                   see task_set_special_port()
+ * Returns:    kern_return_t                   see task_set_special_port_internal()
  */
 kern_return_t
 vfs_context_set_special_port(vfs_context_t ctx, int which, ipc_port_t port)
@@ -1264,7 +1264,7 @@ vfs_context_set_special_port(vfs_context_t ctx, int which, ipc_port_t port)
                task = get_threadtask(ctx->vc_thread);
        }
 
-       return task_set_special_port(task, which, port);
+       return task_set_special_port_internal(task, which, port);
 }
 
 /*
index 5fe5b737a4e2482dc7ac2ddfc4337a1e14083d87..85d47741ee3c9fea99a9709b9d45e49bd584b61d 100644 (file)
@@ -374,17 +374,23 @@ retry_copy:
         * we can release the icoount which we used to get our usecount.
         */
        proc_fdlock(p);
+       if (!(fdp->fd_flags & FD_CHROOT)) {
+               ndp->ni_rootdir = rootvnode;
+       } else {
+               ndp->ni_rootdir = fdp->fd_rdir;
+       }
 
-       if ((ndp->ni_rootdir = fdp->fd_rdir) == NULLVP) {
+       if (!ndp->ni_rootdir) {
                if (!(fdp->fd_flags & FD_CHROOT)) {
-                       ndp->ni_rootdir = rootvnode;
+                       proc_fdunlock(p);
+                       printf("rootvnode is not set\n");
                } else {
                        proc_fdunlock(p);
                        /* This should be a panic */
-                       printf("proc is chrooted but does not have a root directory set\n");
-                       error = ENOENT;
-                       goto error_out;
+                       printf("fdp->fd_rdir is not set\n");
                }
+               error = ENOENT;
+               goto error_out;
        }
 
        /*
index 727d2dafcaf2cb6ce38bc6c0135dd10502c37d7d..e1497887b2e011700690c12c14e2ca85fdb80001 100644 (file)
@@ -4191,7 +4191,7 @@ open_extended(proc_t p, struct open_extended_args *uap, int32_t *retval)
 
        VATTR_INIT(&va);
        cmode = ((uap->mode & ~fdp->fd_cmask) & ALLPERMS) & ~S_ISTXT;
-       VATTR_SET(&va, va_mode, cmode);
+       VATTR_SET(&va, va_mode, cmode & ACCESSPERMS);
        if (uap->uid != KAUTH_UID_NONE) {
                VATTR_SET(&va, va_uid, uap->uid);
        }
index dacd51db9199289654e031c9045f82866236bf23..d649dd232e93f3261e77ea87f85d987e400bd5a9 100644 (file)
@@ -2816,20 +2816,26 @@ get_xattrinfo(vnode_t xvp, int setting, attr_info_t *ainfop, vfs_context_t conte
                        /* We found the Finder Info entry. */
                        ainfop->finderinfo = &filehdr->entries[i];
 
-                       /*
-                        * Is the Finder Info "empty" (all zeroes)?  If so,
-                        * we'll pretend like the Finder Info extended attribute
-                        * does not exist.
+                       /* At this point check_and_swap_apple_double_header() call above
+                        * verified that all apple double entires are valid:
+                        * they point somewhere within the file.
                         *
-                        * Note: we have to make sure the Finder Info is
-                        * contained within the buffer we have already read,
-                        * to avoid accidentally accessing a bogus address.
-                        * If it is outside the buffer, we just assume the
-                        * Finder Info is non-empty.
+                        * Now for finderinfo make sure that the fixed portion
+                        * is within the buffer we read in.
                         */
-                       if (ainfop->finderinfo->offset + FINDERINFOSIZE <= ainfop->rawsize &&
-                           bcmp((u_int8_t*)ainfop->filehdr + ainfop->finderinfo->offset, emptyfinfo, sizeof(emptyfinfo)) == 0) {
-                               ainfop->emptyfinderinfo = 1;
+                       if (((ainfop->finderinfo->offset + FINDERINFOSIZE) > ainfop->finderinfo->offset) &&
+                           ((ainfop->finderinfo->offset + FINDERINFOSIZE) <= ainfop->rawsize)) {
+                               /*
+                                * Is the Finder Info "empty" (all zeroes)?  If so,
+                                * we'll pretend like the Finder Info extended attribute
+                                * does not exist.
+                                */
+                               if (bcmp((u_int8_t*)ainfop->filehdr + ainfop->finderinfo->offset, emptyfinfo, sizeof(emptyfinfo)) == 0) {
+                                       ainfop->emptyfinderinfo = 1;
+                               }
+                       } else {
+                               error = ENOATTR;
+                               goto bail;
                        }
                }
                if (filehdr->entries[i].type == AD_RESOURCE) {
index 5d3ed37cca558695fc07a6fae80850784afec13c..db83ede818be7d4fe2e39ea2fc3f9d23d98127a4 100644 (file)
@@ -192,6 +192,7 @@ __ZN24IOBufferMemoryDescriptor15initWithOptionsEmjj
 __ZN24IOBufferMemoryDescriptor15initWithOptionsEmjjP4task
 __ZN24IOBufferMemoryDescriptor17getVirtualSegmentEmPm
 __ZN24IOBufferMemoryDescriptor17inTaskWithOptionsEP4taskmjj
+__ZN24IOBufferMemoryDescriptor17inTaskWithOptionsEP4taskmjjjj
 __ZN24IOBufferMemoryDescriptor20initWithPhysicalMaskEP4taskmyyy
 __ZN24IOBufferMemoryDescriptor22inTaskWithPhysicalMaskEP4taskmyy
 __ZN24IOBufferMemoryDescriptor9setLengthEj
index 85e40f71132e5359eecd2e79272f4c4541fa8dcc..691beb39003cbb1124373dd2a258d992e893c808 100644 (file)
@@ -165,6 +165,7 @@ __ZN24IOBufferMemoryDescriptor12setDirectionEj
 __ZN24IOBufferMemoryDescriptor12withCapacityEmjb
 __ZN24IOBufferMemoryDescriptor14getBytesNoCopyEmm
 __ZN24IOBufferMemoryDescriptor17inTaskWithOptionsEP4taskjmm
+__ZN24IOBufferMemoryDescriptor17inTaskWithOptionsEP4taskjmmjj
 __ZN24IOBufferMemoryDescriptor20initWithPhysicalMaskEP4taskjyyy
 __ZN24IOBufferMemoryDescriptor22inTaskWithPhysicalMaskEP4taskjyy
 __ZN24IOBufferMemoryDescriptor9setLengthEm
index 721f17eb72e50fc82431165305aa4eda986db05f..91e3992003caca6d6373edca95babb8edfdcaa94 100644 (file)
@@ -326,6 +326,7 @@ __ZN24IOBufferMemoryDescriptor12setDirectionEj
 __ZN24IOBufferMemoryDescriptor12withCapacityEmjb
 __ZN24IOBufferMemoryDescriptor14getBytesNoCopyEmm
 __ZN24IOBufferMemoryDescriptor17inTaskWithOptionsEP4taskjmm
+__ZN24IOBufferMemoryDescriptor17inTaskWithOptionsEP4taskjmmjj
 __ZN24IOBufferMemoryDescriptor20initWithPhysicalMaskEP4taskjyyy
 __ZN24IOBufferMemoryDescriptor22inTaskWithPhysicalMaskEP4taskjyy
 __ZN24IOBufferMemoryDescriptor34_RESERVEDIOBufferMemoryDescriptor0Ev
index 735ea69c3877bb701b547f12cd6e18cd44566f9f..199aff61c6cf6c1e355a93c98db0928037fbed6a 100644 (file)
@@ -720,6 +720,7 @@ _sha1_init:_SHA1Init
 _sha1_loop:_SHA1Update
 _sha1_result:_SHA1Final_r
 _snprintf
+_scnprintf
 _sscanf
 _strcasecmp
 _strchr
@@ -758,6 +759,7 @@ _version_stage
 _version_variant
 _vprintf
 _vsnprintf
+_vscnprintf
 _vsscanf
 _zError
 _zlibVersion
index f72373b1c86395efd49fa741843d6f524953e110..b123f4ec5dd49fea63d998948e7805290a880753 100644 (file)
@@ -1,4 +1,4 @@
-19.0.0
+19.2.0
 
 # The first line of this file contains the master version number for the kernel.
 # All other instances of the kernel version in xnu are derived from this file.
index 112bf79fd3b7ba46911bafca92081beca3aa08a8..19cb85579746590d042641f2840042008bfe793b 100644 (file)
@@ -52,6 +52,7 @@ enum {
 
 #define _IOBUFFERMEMORYDESCRIPTOR_INTASKWITHOPTIONS_            1
 #define _IOBUFFERMEMORYDESCRIPTOR_HOSTPHYSICALLYCONTIGUOUS_     1
+#define IOBUFFERMEMORYDESCRIPTOR_SUPPORTS_INTASKWITHOPTIONS_TAGS        1
 /*!
  *   @class IOBufferMemoryDescriptor
  *   @abstract Provides a simple memory descriptor that allocates its own buffer memory.
@@ -176,6 +177,34 @@ public:
                vm_size_t    capacity,
                vm_offset_t  alignment = 1);
 
+/*! @function inTaskWithOptions
+ *   @abstract Creates a memory buffer with memory descriptor for that buffer.
+ *   @discussion Added in Mac OS X 10.2, this method allocates a memory buffer with a given size and alignment in the task's address space specified, and returns a memory descriptor instance representing the memory. It is recommended that memory allocated for I/O or sharing via mapping be created via IOBufferMemoryDescriptor. Options passed with the request specify the kind of memory to be allocated - pageablity and sharing are specified with option bits. This function may block and so should not be called from interrupt level or while a simple lock is held.
+ *   @param inTask The task the buffer will be allocated in.
+ *   @param options Options for the allocation:<br>
+ *   kIODirectionOut, kIODirectionIn - set the direction of the I/O transfer.<br>
+ *   kIOMemoryPhysicallyContiguous - pass to request memory be physically contiguous. This option is heavily discouraged. The request may fail if memory is fragmented, may cause large amounts of paging activity, and may take a very long time to execute.<br>
+ *   kIOMemoryPageable - pass to request memory be non-wired - the default for kernel allocated memory is wired.<br>
+ *   kIOMemoryPurgeable - pass to request memory that may later have its purgeable state set with IOMemoryDescriptor::setPurgeable. Only supported for kIOMemoryPageable allocations.<br>
+ *   kIOMemoryKernelUserShared - pass to request memory that will be mapped into both the kernel and client applications.<br>
+ *   kIOMapInhibitCache - allocate memory with inhibited cache setting. <br>
+ *   kIOMapWriteThruCache - allocate memory with writethru cache setting. <br>
+ *   kIOMapCopybackCache - allocate memory with copyback cache setting. <br>
+ *   kIOMapWriteCombineCache - allocate memory with writecombined cache setting.
+ *   @param capacity The number of bytes to allocate.
+ *   @param alignment The minimum required alignment of the buffer in bytes - 1 is the default for no required alignment. For example, pass 256 to get memory allocated at an address with bits 0-7 zero.
+ *   @param kernTag The kernel memory tag
+ *   @param userTag The user memory tag
+ *   @result Returns an instance of class IOBufferMemoryDescriptor to be released by the caller, which will free the memory desriptor and associated buffer. */
+
+       static IOBufferMemoryDescriptor * inTaskWithOptions(
+               task_t       inTask,
+               IOOptionBits options,
+               vm_size_t    capacity,
+               vm_offset_t  alignment,
+               uint32_t     kernTag,
+               uint32_t     userTag);
+
 /*! @function inTaskWithPhysicalMask
  *   @abstract Creates a memory buffer with memory descriptor for that buffer.
  *   @discussion Added in Mac OS X 10.5, this method allocates a memory buffer with a given size and alignment in the task's address space specified, and returns a memory descriptor instance representing the memory. It is recommended that memory allocated for I/O or sharing via mapping be created via IOBufferMemoryDescriptor. Options passed with the request specify the kind of memory to be allocated - pageablity and sharing are specified with option bits. This function may block and so should not be called from interrupt level or while a simple lock is held.
index dfe4b08ba5674b3ce8ea7786f163c73a05ffad05..29437390a86be7ffe4ecd6a4144a4ea53c879320 100644 (file)
@@ -425,6 +425,28 @@ IOBufferMemoryDescriptor::inTaskWithOptions(
        return me;
 }
 
+IOBufferMemoryDescriptor *
+IOBufferMemoryDescriptor::inTaskWithOptions(
+       task_t       inTask,
+       IOOptionBits options,
+       vm_size_t    capacity,
+       vm_offset_t  alignment,
+       uint32_t     kernTag,
+       uint32_t     userTag)
+{
+       IOBufferMemoryDescriptor *me = new IOBufferMemoryDescriptor;
+
+       if (me) {
+               me->setVMTags(kernTag, userTag);
+
+               if (!me->initWithPhysicalMask(inTask, options, capacity, alignment, 0)) {
+                       me->release();
+                       me = NULL;
+               }
+       }
+       return me;
+}
+
 IOBufferMemoryDescriptor *
 IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
        task_t            inTask,
index 624d7a812a1934be0739f8b40f7bccc9200c55f0..c1114f9ec1e7d94738614c86d34ed44f1fe44a8c 100644 (file)
@@ -9883,7 +9883,7 @@ IOPMrootDomain::acceptSystemWakeEvents( bool accept )
                }
                _acceptSystemWakeEvents = (_systemWakeEventsArray != NULL);
 #if !(defined(RC_HIDE_N144) || defined(RC_HIDE_N146))
-               if (!(kIOPMWakeEventAOTExitFlags & _aotPendingFlags))
+               if (!(_aotNow && (kIOPMWakeEventAOTExitFlags & _aotPendingFlags)))
 #endif /* !(defined(RC_HIDE_N144) || defined(RC_HIDE_N146)) */
                {
                        gWakeReasonString[0] = '\0';
index bbe9448fd3b1eacaf7a155dc077aa7aef8ae83bf..ae3296b4e5d57f89c6dc37d388370975435fc22d 100644 (file)
@@ -3548,10 +3548,12 @@ GetPropertiesEditor(void                  * reference,
 
 #endif /* CONFIG_MACF */
 
-/* Routine io_registry_entry_get_properties */
+/* Routine io_registry_entry_get_properties_bin_buf */
 kern_return_t
-is_io_registry_entry_get_properties_bin(
+is_io_registry_entry_get_properties_bin_buf(
        io_object_t registry_entry,
+       mach_vm_address_t buf,
+       mach_vm_size_t *bufsize,
        io_buf_ptr_t *properties,
        mach_msg_type_number_t *propertiesCnt)
 {
@@ -3585,21 +3587,48 @@ is_io_registry_entry_get_properties_bin(
 
        if (kIOReturnSuccess == err) {
                len = s->getLength();
-               *propertiesCnt = len;
-               err = copyoutkdata(s->text(), len, properties);
+               if (buf && bufsize && len <= *bufsize) {
+                       *bufsize = len;
+                       *propertiesCnt = 0;
+                       *properties = nullptr;
+                       if (copyout(s->text(), buf, len)) {
+                               err = kIOReturnVMError;
+                       } else {
+                               err = kIOReturnSuccess;
+                       }
+               } else {
+                       if (bufsize) {
+                               *bufsize = 0;
+                       }
+                       *propertiesCnt = len;
+                       err = copyoutkdata( s->text(), len, properties );
+               }
        }
        s->release();
 
        return err;
 }
 
-/* Routine io_registry_entry_get_property_bin */
+/* Routine io_registry_entry_get_properties_bin */
 kern_return_t
-is_io_registry_entry_get_property_bin(
+is_io_registry_entry_get_properties_bin(
+       io_object_t registry_entry,
+       io_buf_ptr_t *properties,
+       mach_msg_type_number_t *propertiesCnt)
+{
+       return is_io_registry_entry_get_properties_bin_buf(registry_entry,
+                  0, NULL, properties, propertiesCnt);
+}
+
+/* Routine io_registry_entry_get_property_bin_buf */
+kern_return_t
+is_io_registry_entry_get_property_bin_buf(
        io_object_t registry_entry,
        io_name_t plane,
        io_name_t property_name,
        uint32_t options,
+       mach_vm_address_t buf,
+       mach_vm_size_t *bufsize,
        io_buf_ptr_t *properties,
        mach_msg_type_number_t *propertiesCnt )
 {
@@ -3648,8 +3677,22 @@ is_io_registry_entry_get_property_bin(
 
        if (obj->serialize( s )) {
                len = s->getLength();
-               *propertiesCnt = len;
-               err = copyoutkdata( s->text(), len, properties );
+               if (buf && bufsize && len <= *bufsize) {
+                       *bufsize = len;
+                       *propertiesCnt = 0;
+                       *properties = nullptr;
+                       if (copyout(s->text(), buf, len)) {
+                               err = kIOReturnVMError;
+                       } else {
+                               err = kIOReturnSuccess;
+                       }
+               } else {
+                       if (bufsize) {
+                               *bufsize = 0;
+                       }
+                       *propertiesCnt = len;
+                       err = copyoutkdata( s->text(), len, properties );
+               }
        } else {
                err = kIOReturnUnsupported;
        }
@@ -3660,6 +3703,20 @@ is_io_registry_entry_get_property_bin(
        return err;
 }
 
+/* Routine io_registry_entry_get_property_bin */
+kern_return_t
+is_io_registry_entry_get_property_bin(
+       io_object_t registry_entry,
+       io_name_t plane,
+       io_name_t property_name,
+       uint32_t options,
+       io_buf_ptr_t *properties,
+       mach_msg_type_number_t *propertiesCnt )
+{
+       return is_io_registry_entry_get_property_bin_buf(registry_entry, plane,
+                  property_name, options, 0, NULL, properties, propertiesCnt);
+}
+
 
 /* Routine io_registry_entry_set_properties */
 kern_return_t
index cbdef89e21bde45ad23d873c04bb64ae40a5a5da..5a761d48b3294c3bf9b22f787b8378b3b977735c 100644 (file)
@@ -453,20 +453,20 @@ OSKextVersionGetString(
                return TRUE;
        }
 
-       cpos = snprintf(buffer, bufferLength, "%u", (uint32_t)vers_major);
+       cpos = scnprintf(buffer, bufferLength, "%u", (uint32_t)vers_major);
 
        /* Always include the minor version; it just looks weird without.
         */
        buffer[cpos] = '.';
        cpos++;
-       cpos += snprintf(buffer + cpos, bufferLength - cpos, "%u", (uint32_t)vers_minor);
+       cpos += scnprintf(buffer + cpos, bufferLength - cpos, "%u", (uint32_t)vers_minor);
 
        /* The revision is displayed only if nonzero.
         */
        if (vers_revision) {
                buffer[cpos] = '.';
                cpos++;
-               cpos += snprintf(buffer + cpos, bufferLength - cpos, "%u",
+               cpos += scnprintf(buffer + cpos, bufferLength - cpos, "%u",
                    (uint32_t)vers_revision);
        }
 
index 7bf58353d09d7ae30b6e9343cc5d8ff851b4057d..195a2e6d3f9f81fdc4bc207db428804877515a04 100644 (file)
@@ -54,7 +54,7 @@
  * it can be tested at build-time and not require rev-locked submissions of xnu
  * and AppleImage4.
  */
-#define IMG4_INTERFACE_VERSION (3u)
+#define IMG4_INTERFACE_VERSION (4u)
 
 /*!
  * @typedef img4_init_t
@@ -161,13 +161,23 @@ typedef errno_t (*const img4_nonce_domain_roll_nonce_t)(
  * @typedef img4_payload_init_with_vnode_4xnu_t
  * A type describing the {@link img4_payload_init_with_vnode_4xnu} function.
  */
-typedef errno_t (*img4_payload_init_with_vnode_4xnu_t)(
+typedef errno_t (*const img4_payload_init_with_vnode_4xnu_t)(
        img4_payload_t *i4p,
        img4_tag_t tag,
        vnode_t vn,
        img4_payload_flags_t flags
        );
 
+/*!
+ * @typedef img4_environment_init_identity_t
+ * A type describing the {@link img4_environment_init_identity} function.
+ */
+typedef errno_t (*const img4_environment_init_identity_t)(
+       img4_environment_t *i4e,
+       size_t len,
+       const img4_identity_t *i4id
+       );
+
 /*!
  * @typedef img4_interface_t
  * A structure describing the interface to the AppleImage4 kext.
@@ -231,6 +241,9 @@ typedef errno_t (*img4_payload_init_with_vnode_4xnu_t)(
  *
  * @field i4if_v3.nonce_domain_cryptex
  * The {@link IMG4_NONCE_DOMAIN_CRYPTEX} global.
+ *
+ * @field i4if_v4.environment_init_identity
+ * A pointer to the {@link img4_environment_init_identity} function.
  */
 
 typedef struct _img4_interface {
@@ -258,7 +271,10 @@ typedef struct _img4_interface {
                const img4_nonce_domain_t *nonce_domain_pdi;
                const img4_nonce_domain_t *nonce_domain_cryptex;
        } i4if_v3;
-       void *__reserved[15];
+       struct {
+               const img4_environment_init_identity_t environment_init_identity;
+       } i4if_v4;
+       void *__reserved[14];
 } img4_interface_t;
 
 __BEGIN_DECLS
index c1fdba73c027d347da0ee9c81347cccef21d6863..2d898d0d1a0ec552bee8a351ea9d40edd4c83ed0 100644 (file)
@@ -170,7 +170,7 @@ inet_ntop6(const u_char *src, char *dst, socklen_t size)
                        tp += strlen(tp);
                        break;
                }
-               tp += snprintf(tp, sizeof(tmp), "%x", words[i]);
+               tp += scnprintf(tp, sizeof(tmp), "%x", words[i]);
        }
        /* Was it a trailing run of 0x00's? */
        if (best.base != -1 && (best.base + best.len) ==
index b01f583220daf4baee8218ee9d4b0064806f2e7b..dd447891373105f06dd70e592ac490aa757af47f 100644 (file)
@@ -753,7 +753,7 @@ kern_return_t test_os_log_parallel(void);
        T_LOG("Doing os_log of %llu TESTLOG msgs for fn " ident, count);                                   \
        for (uint64_t i = 0; i < count; i++)                                                               \
        {                                                                                                  \
-           datalen = snprintf(databuffer, sizeof(databuffer), TESTOSLOGFMT(ident), uniqid, i + 1, count); \
+           datalen = scnprintf(databuffer, sizeof(databuffer), TESTOSLOGFMT(ident), uniqid, i + 1, count); \
            checksum = crc32(0, databuffer, datalen);                                                      \
            callout_f(OS_LOG_DEFAULT, TESTOSLOG(ident), checksum, uniqid, i + 1, count);                   \
        /*T_LOG(TESTOSLOG(ident), checksum, uniqid, i + 1, count);*/                                   \
@@ -797,16 +797,16 @@ test_os_log()
        T_ASSERT_NE_UINT(0, uniqid, "random number should not be zero");
        T_ASSERT_NE_ULLONG(0, a, "absolute time should not be zero");
 
-       datalen = snprintf(databuffer, sizeof(databuffer), TESTOSLOGFMT("printf_only"), uniqid, seqno, total_seqno);
+       datalen = scnprintf(databuffer, sizeof(databuffer), TESTOSLOGFMT("printf_only"), uniqid, seqno, total_seqno);
        checksum = crc32(0, databuffer, datalen);
        printf(TESTOSLOG("printf_only") "mat%llu\n", checksum, uniqid, seqno, total_seqno, a);
 
        seqno += 1;
-       datalen = snprintf(databuffer, sizeof(databuffer), TESTOSLOGFMT("printf_only"), uniqid, seqno, total_seqno);
+       datalen = scnprintf(databuffer, sizeof(databuffer), TESTOSLOGFMT("printf_only"), uniqid, seqno, total_seqno);
        checksum = crc32(0, databuffer, datalen);
        printf(TESTOSLOG("printf_only") "mat%llu\n", checksum, uniqid, seqno, total_seqno, a);
 
-       datalen = snprintf(databuffer, sizeof(databuffer), "kernel^0^test^printf_only#mat%llu", a);
+       datalen = scnprintf(databuffer, sizeof(databuffer), "kernel^0^test^printf_only#mat%llu", a);
        match_count = find_pattern_in_buffer(databuffer, datalen, total_seqno);
        T_EXPECT_EQ_UINT(match_count, 2, "verify printf_only goes to systemlog buffer");
 
@@ -827,12 +827,12 @@ test_os_log()
        total_msg = oslog_p_total_msgcount;
        saved_msg = oslog_p_saved_msgcount;
        dropped_msg = oslog_p_dropped_msgcount;
-       datalen = snprintf(databuffer, sizeof(databuffer), TESTOSLOGFMT("oslog_info"), uniqid, seqno, total_seqno);
+       datalen = scnprintf(databuffer, sizeof(databuffer), TESTOSLOGFMT("oslog_info"), uniqid, seqno, total_seqno);
        checksum = crc32(0, databuffer, datalen);
        os_log_info(log_handle, TESTOSLOG("oslog_info") "mat%llu", checksum, uniqid, seqno, total_seqno, a);
        T_EXPECT_GE_UINT((oslog_p_total_msgcount - total_msg), 1, "total message count in buffer");
 
-       datalen = snprintf(databuffer, sizeof(databuffer), "kernel^0^test^oslog_info#mat%llu", a);
+       datalen = scnprintf(databuffer, sizeof(databuffer), "kernel^0^test^oslog_info#mat%llu", a);
        match_count = find_pattern_in_buffer(databuffer, datalen, total_seqno);
        T_EXPECT_EQ_UINT(match_count, 1, "verify oslog_info does not go to systemlog buffer");
 
index 42d753130b6a04e926974a95c3ecd86dd2c819f3..939e5eec6faaa73af0ff6de60997d5d3d54024b1 100644 (file)
@@ -999,7 +999,6 @@ DebuggerXCall(
        /* Any cleanup for our pushed context should go here */
 }
 
-
 void
 DebuggerCall(
        unsigned int    reason,
@@ -1019,3 +1018,9 @@ DebuggerCall(
        /* TODO: decide what to do if no debugger config */
 #endif
 }
+
+boolean_t
+bootloader_valid_page(ppnum_t ppn)
+{
+       return pmap_bootloader_page(ppn);
+}
index 92b3562d71e05a4916eae54683b3498a48ae243b..f40eeb88c51a76757a13b321df5819ab0941d6bf 100644 (file)
@@ -806,6 +806,7 @@ typedef struct pmap_io_range {
        uint64_t addr;
        uint64_t len;
        #define PMAP_IO_RANGE_STRONG_SYNC (1UL << 31) // Strong DSB required for pages in this range
+       #define PMAP_IO_RANGE_CARVEOUT (1UL << 30) // Corresponds to memory carved out by bootloader
        uint32_t wimg; // lower 16 bits treated as pp_attr_t, upper 16 bits contain additional mapping flags
        uint32_t signature; // 4CC
 } __attribute__((packed)) pmap_io_range_t;
@@ -1493,7 +1494,7 @@ PMAP_SUPPORT_PROTOTYPES(
 
 PMAP_SUPPORT_PROTOTYPES(
        kern_return_t,
-       mapping_replenish, (void), MAPPING_REPLENISH_INDEX);
+       mapping_replenish, (uint32_t kern_target_count, uint32_t user_target_count), MAPPING_REPLENISH_INDEX);
 
 PMAP_SUPPORT_PROTOTYPES(
        boolean_t,
@@ -2134,15 +2135,10 @@ uint32_t pv_kern_alloc_chunk MARK_AS_PMAP_DATA;
 
 thread_t mapping_replenish_thread;
 event_t mapping_replenish_event;
-event_t pmap_user_pv_throttle_event;
 volatile uint32_t mappingrecurse = 0;
 
-uint64_t pmap_pv_throttle_stat;
-uint64_t pmap_pv_throttled_waiters;
-
 unsigned pmap_mapping_thread_wakeups;
-unsigned pmap_kernel_reserve_replenish_stat MARK_AS_PMAP_DATA;
-unsigned pmap_user_reserve_replenish_stat MARK_AS_PMAP_DATA;
+unsigned pmap_reserve_replenish_stat MARK_AS_PMAP_DATA;
 unsigned pmap_kern_reserve_alloc_stat MARK_AS_PMAP_DATA;
 
 
@@ -2160,10 +2156,7 @@ pv_init(
 
 static inline void      PV_ALLOC(pv_entry_t **pv_ep);
 static inline void      PV_KERN_ALLOC(pv_entry_t **pv_e);
-static inline void      PV_FREE_LIST(pv_entry_t *pv_eh, pv_entry_t *pv_et, int pv_cnt);
-static inline void      PV_KERN_FREE_LIST(pv_entry_t *pv_eh, pv_entry_t *pv_et, int pv_cnt);
-
-static inline void      pmap_pv_throttle(pmap_t p);
+static inline void      PV_FREE_LIST(pv_entry_t *pv_eh, pv_entry_t *pv_et, int pv_cnt, uint32_t kern_target);
 
 static boolean_t
 pv_alloc(
@@ -2225,7 +2218,7 @@ pv_alloc(
                                        pv_cnt++;
                                        pv_e++;
                                }
-                               PV_KERN_FREE_LIST(pv_eh, pv_et, pv_cnt);
+                               PV_FREE_LIST(pv_eh, pv_et, pv_cnt, pv_kern_low_water_mark);
                                if (pmap != NULL) {
                                        PMAP_LOCK(pmap);
                                }
@@ -2235,45 +2228,45 @@ pv_alloc(
                } else {
                        UNLOCK_PVH(pai);
                        PMAP_UNLOCK(pmap);
-                       pmap_pv_throttle(pmap);
-                       {
-                               pv_entry_t              *pv_e;
-                               pv_entry_t              *pv_eh;
-                               pv_entry_t              *pv_et;
-                               int                             pv_cnt;
-                               unsigned                j;
-                               pmap_paddr_t    pa;
-                               kern_return_t   ret;
 
-                               ret = pmap_pages_alloc(&pa, PAGE_SIZE, 0);
+                       pv_entry_t              *pv_e;
+                       pv_entry_t              *pv_eh;
+                       pv_entry_t              *pv_et;
+                       int                             pv_cnt;
+                       unsigned                j;
+                       pmap_paddr_t    pa;
+                       kern_return_t   ret;
 
-                               if (ret != KERN_SUCCESS) {
-                                       panic("%s: failed to alloc page, ret=%d, "
-                                           "pmap=%p, pai=%u, pvepp=%p",
-                                           __FUNCTION__, ret,
-                                           pmap, pai, pvepp);
-                               }
+                       ret = pmap_pages_alloc(&pa, PAGE_SIZE, 0);
 
-                               pv_page_count++;
+                       if (ret != KERN_SUCCESS) {
+                               panic("%s: failed to alloc page, ret=%d, "
+                                   "pmap=%p, pai=%u, pvepp=%p",
+                                   __FUNCTION__, ret,
+                                   pmap, pai, pvepp);
+                       }
 
-                               pv_e = (pv_entry_t *)phystokv(pa);
-                               pv_cnt = 0;
-                               pv_eh = pv_et = PV_ENTRY_NULL;
-                               *pvepp = pv_e;
-                               pv_e++;
+                       pv_page_count++;
 
-                               for (j = 1; j < (PAGE_SIZE / sizeof(pv_entry_t)); j++) {
-                                       pv_e->pve_next = pv_eh;
-                                       pv_eh = pv_e;
+                       pv_e = (pv_entry_t *)phystokv(pa);
+                       pv_cnt = 0;
+                       pv_eh = pv_et = PV_ENTRY_NULL;
+                       *pvepp = pv_e;
+                       pv_e++;
 
-                                       if (pv_et == PV_ENTRY_NULL) {
-                                               pv_et = pv_e;
-                                       }
-                                       pv_cnt++;
-                                       pv_e++;
+                       for (j = 1; j < (PAGE_SIZE / sizeof(pv_entry_t)); j++) {
+                               pv_e->pve_next = pv_eh;
+                               pv_eh = pv_e;
+
+                               if (pv_et == PV_ENTRY_NULL) {
+                                       pv_et = pv_e;
                                }
-                               PV_FREE_LIST(pv_eh, pv_et, pv_cnt);
+                               pv_cnt++;
+                               pv_e++;
                        }
+
+                       PV_FREE_LIST(pv_eh, pv_et, pv_cnt, pv_kern_low_water_mark);
+
                        PMAP_LOCK(pmap);
                        LOCK_PVH(pai);
                        return FALSE;
@@ -2287,7 +2280,7 @@ static void
 pv_free(
        pv_entry_t *pvep)
 {
-       PV_FREE_LIST(pvep, pvep, 1);
+       PV_FREE_LIST(pvep, pvep, 1, pv_kern_low_water_mark);
 }
 
 static void
@@ -2296,7 +2289,7 @@ pv_list_free(
        pv_entry_t *pvetp,
        unsigned int cnt)
 {
-       PV_FREE_LIST(pvehp, pvetp, cnt);
+       PV_FREE_LIST(pvehp, pvetp, cnt, pv_kern_low_water_mark);
 }
 
 static inline void
@@ -2313,12 +2306,16 @@ static inline void
 PV_ALLOC(pv_entry_t **pv_ep)
 {
        assert(*pv_ep == PV_ENTRY_NULL);
+       if (pv_kern_free_count < pv_kern_low_water_mark) {
+               /*
+                * If the kernel reserved pool is low, let non-kernel mappings wait for a page
+                * from the VM.
+                */
+               return;
+       }
        pmap_simple_lock(&pv_free_list_lock);
-       /*
-        * If the kernel reserved pool is low, let non-kernel mappings allocate
-        * synchronously, possibly subject to a throttle.
-        */
-       if ((pv_kern_free_count >= pv_kern_low_water_mark) && ((*pv_ep = pv_free_list) != 0)) {
+
+       if ((*pv_ep = pv_free_list) != 0) {
                pv_free_list = (pv_entry_t *)(*pv_ep)->pve_next;
                (*pv_ep)->pve_next = PV_ENTRY_NULL;
                pv_free_count--;
@@ -2328,13 +2325,25 @@ PV_ALLOC(pv_entry_t **pv_ep)
 }
 
 static inline void
-PV_FREE_LIST(pv_entry_t *pv_eh, pv_entry_t *pv_et, int pv_cnt)
+PV_FREE_LIST(pv_entry_t *pv_eh, pv_entry_t *pv_et, int pv_cnt, uint32_t kern_target)
 {
-       pmap_simple_lock(&pv_free_list_lock);
-       pv_et->pve_next = (pv_entry_t *)pv_free_list;
-       pv_free_list = pv_eh;
-       pv_free_count += pv_cnt;
-       pmap_simple_unlock(&pv_free_list_lock);
+       bool use_kernel_list = false;
+       pmap_simple_lock(&pv_kern_free_list_lock);
+       if (pv_kern_free_count < kern_target) {
+               pv_et->pve_next = pv_kern_free_list;
+               pv_kern_free_list = pv_eh;
+               pv_kern_free_count += pv_cnt;
+               use_kernel_list = true;
+       }
+       pmap_simple_unlock(&pv_kern_free_list_lock);
+
+       if (!use_kernel_list) {
+               pmap_simple_lock(&pv_free_list_lock);
+               pv_et->pve_next = (pv_entry_t *)pv_free_list;
+               pv_free_list = pv_eh;
+               pv_free_count += pv_cnt;
+               pmap_simple_unlock(&pv_free_list_lock);
+       }
 }
 
 static inline void
@@ -2353,32 +2362,6 @@ PV_KERN_ALLOC(pv_entry_t **pv_e)
        pmap_simple_unlock(&pv_kern_free_list_lock);
 }
 
-static inline void
-PV_KERN_FREE_LIST(pv_entry_t *pv_eh, pv_entry_t *pv_et, int pv_cnt)
-{
-       pmap_simple_lock(&pv_kern_free_list_lock);
-       pv_et->pve_next = pv_kern_free_list;
-       pv_kern_free_list = pv_eh;
-       pv_kern_free_count += pv_cnt;
-       pmap_simple_unlock(&pv_kern_free_list_lock);
-}
-
-static inline void
-pmap_pv_throttle(__unused pmap_t p)
-{
-       assert(p != kernel_pmap);
-       /* Apply throttle on non-kernel mappings */
-       if (pv_kern_free_count < (pv_kern_low_water_mark / 2)) {
-               pmap_pv_throttle_stat++;
-               /* This doesn't need to be strictly accurate, merely a hint
-                * to eliminate the timeout when the reserve is replenished.
-                */
-               pmap_pv_throttled_waiters++;
-               assert_wait_timeout(&pmap_user_pv_throttle_event, THREAD_UNINT, 1, 1000 * NSEC_PER_USEC);
-               thread_block(THREAD_CONTINUE_NULL);
-       }
-}
-
 /*
  * Creates a target number of free pv_entry_t objects for the kernel free list
  * and the general free list.
@@ -2386,17 +2369,6 @@ pmap_pv_throttle(__unused pmap_t p)
 MARK_AS_PMAP_TEXT static kern_return_t
 mapping_free_prime_internal(void)
 {
-       unsigned       j;
-       pmap_paddr_t   pa;
-       kern_return_t  ret;
-       pv_entry_t    *pv_e;
-       pv_entry_t    *pv_eh;
-       pv_entry_t    *pv_et;
-       int            pv_cnt;
-       int            alloc_options = 0;
-       int            needed_pv_cnt = 0;
-       int            target_pv_free_cnt = 0;
-
        SECURITY_READ_ONLY_LATE(static boolean_t) mapping_free_prime_internal_called = FALSE;
        SECURITY_READ_ONLY_LATE(static boolean_t) mapping_free_prime_internal_done = FALSE;
 
@@ -2416,85 +2388,7 @@ mapping_free_prime_internal(void)
                pv_alloc_chunk = PV_ALLOC_CHUNK_INITIAL;
        }
 
-       pv_cnt = 0;
-       pv_eh = pv_et = PV_ENTRY_NULL;
-       target_pv_free_cnt = PV_ALLOC_INITIAL_TARGET;
-
-       /*
-        * We don't take the lock to read pv_free_count, as we should not be
-        * invoking this from a multithreaded context.
-        */
-       needed_pv_cnt = target_pv_free_cnt - pv_free_count;
-
-       if (needed_pv_cnt > target_pv_free_cnt) {
-               needed_pv_cnt = 0;
-       }
-
-       while (pv_cnt < needed_pv_cnt) {
-               ret = pmap_pages_alloc(&pa, PAGE_SIZE, alloc_options);
-
-               assert(ret == KERN_SUCCESS);
-
-               pv_page_count++;
-
-               pv_e = (pv_entry_t *)phystokv(pa);
-
-               for (j = 0; j < (PAGE_SIZE / sizeof(pv_entry_t)); j++) {
-                       pv_e->pve_next = pv_eh;
-                       pv_eh = pv_e;
-
-                       if (pv_et == PV_ENTRY_NULL) {
-                               pv_et = pv_e;
-                       }
-                       pv_cnt++;
-                       pv_e++;
-               }
-       }
-
-       if (pv_cnt) {
-               PV_FREE_LIST(pv_eh, pv_et, pv_cnt);
-       }
-
-       pv_cnt = 0;
-       pv_eh = pv_et = PV_ENTRY_NULL;
-       target_pv_free_cnt = PV_KERN_ALLOC_INITIAL_TARGET;
-
-       /*
-        * We don't take the lock to read pv_kern_free_count, as we should not
-        * be invoking this from a multithreaded context.
-        */
-       needed_pv_cnt = target_pv_free_cnt - pv_kern_free_count;
-
-       if (needed_pv_cnt > target_pv_free_cnt) {
-               needed_pv_cnt = 0;
-       }
-
-       while (pv_cnt < needed_pv_cnt) {
-               ret = pmap_pages_alloc(&pa, PAGE_SIZE, alloc_options);
-
-               assert(ret == KERN_SUCCESS);
-               pv_page_count++;
-
-               pv_e = (pv_entry_t *)phystokv(pa);
-
-               for (j = 0; j < (PAGE_SIZE / sizeof(pv_entry_t)); j++) {
-                       pv_e->pve_next = pv_eh;
-                       pv_eh = pv_e;
-
-                       if (pv_et == PV_ENTRY_NULL) {
-                               pv_et = pv_e;
-                       }
-                       pv_cnt++;
-                       pv_e++;
-               }
-       }
-
-       if (pv_cnt) {
-               PV_KERN_FREE_LIST(pv_eh, pv_et, pv_cnt);
-       }
-
-       mapping_free_prime_internal_done = TRUE;
-       return KERN_SUCCESS;
+       return mapping_replenish_internal(PV_KERN_ALLOC_INITIAL_TARGET, PV_ALLOC_INITIAL_TARGET);
 }
 
 void
@@ -2529,7 +2423,7 @@ mapping_adjust(void)
  * Fills the kernel and general PV free lists back up to their low watermarks.
  */
 MARK_AS_PMAP_TEXT static kern_return_t
-mapping_replenish_internal(void)
+mapping_replenish_internal(uint32_t kern_target_count, uint32_t user_target_count)
 {
        pv_entry_t    *pv_e;
        pv_entry_t    *pv_eh;
@@ -2539,7 +2433,7 @@ mapping_replenish_internal(void)
        pmap_paddr_t   pa;
        kern_return_t  ret = KERN_SUCCESS;
 
-       while (pv_kern_free_count < pv_kern_low_water_mark) {
+       while ((pv_free_count < user_target_count) || (pv_kern_free_count < kern_target_count)) {
                pv_cnt = 0;
                pv_eh = pv_et = PV_ENTRY_NULL;
 
@@ -2560,33 +2454,8 @@ mapping_replenish_internal(void)
                        pv_cnt++;
                        pv_e++;
                }
-               pmap_kernel_reserve_replenish_stat += pv_cnt;
-               PV_KERN_FREE_LIST(pv_eh, pv_et, pv_cnt);
-       }
-
-       while (pv_free_count < pv_low_water_mark) {
-               pv_cnt = 0;
-               pv_eh = pv_et = PV_ENTRY_NULL;
-
-               ret = pmap_pages_alloc(&pa, PAGE_SIZE, 0);
-               assert(ret == KERN_SUCCESS);
-
-               pv_page_count++;
-
-               pv_e = (pv_entry_t *)phystokv(pa);
-
-               for (j = 0; j < (PAGE_SIZE / sizeof(pv_entry_t)); j++) {
-                       pv_e->pve_next = pv_eh;
-                       pv_eh = pv_e;
-
-                       if (pv_et == PV_ENTRY_NULL) {
-                               pv_et = pv_e;
-                       }
-                       pv_cnt++;
-                       pv_e++;
-               }
-               pmap_user_reserve_replenish_stat += pv_cnt;
-               PV_FREE_LIST(pv_eh, pv_et, pv_cnt);
+               pmap_reserve_replenish_stat += pv_cnt;
+               PV_FREE_LIST(pv_eh, pv_et, pv_cnt, kern_target_count);
        }
 
        return ret;
@@ -2606,20 +2475,12 @@ mapping_replenish(void)
        current_thread()->options |= TH_OPT_VMPRIV;
 
        for (;;) {
-               kr = mapping_replenish_internal();
+               kr = mapping_replenish_internal(pv_kern_low_water_mark, pv_low_water_mark);
 
                if (kr != KERN_SUCCESS) {
                        panic("%s: failed, kr=%d", __FUNCTION__, kr);
                }
 
-               /*
-                * Wake threads throttled while the kernel reserve was being replenished.
-                */
-               if (pmap_pv_throttled_waiters) {
-                       pmap_pv_throttled_waiters = 0;
-                       thread_wakeup(&pmap_user_pv_throttle_event);
-               }
-
                /* Check if the kernel pool has been depleted since the
                 * first pass, to reduce refill latency.
                 */
@@ -10190,6 +10051,19 @@ pmap_valid_page(
        return pa_valid(ptoa(pn));
 }
 
+boolean_t
+pmap_bootloader_page(
+       ppnum_t pn)
+{
+       pmap_paddr_t paddr = ptoa(pn);
+
+       if (pa_valid(paddr)) {
+               return FALSE;
+       }
+       pmap_io_range_t *io_rgn = pmap_find_io_attr(paddr);
+       return (io_rgn != NULL) && (io_rgn->wimg & PMAP_IO_RANGE_CARVEOUT);
+}
+
 MARK_AS_PMAP_TEXT static boolean_t
 pmap_is_empty_internal(
        pmap_t pmap,
index 92d4a167a1cc989d68c580d4c28a2fcdc165ee28..e56129770d4359677d608bae3eb7fa962f104892 100644 (file)
@@ -472,6 +472,7 @@ extern void pt_fake_zone_info(int *, vm_size_t *, vm_size_t *, vm_size_t *, vm_s
     uint64_t *, int *, int *, int *);
 
 extern boolean_t pmap_valid_page(ppnum_t pn);
+extern boolean_t pmap_bootloader_page(ppnum_t pn);
 
 #define MACHINE_PMAP_IS_EMPTY 1
 extern boolean_t pmap_is_empty(pmap_t pmap, vm_map_offset_t start, vm_map_offset_t end);
index cc887d62d03d185395cb4082902fa47b496f478f..163b9093568d149f1584f14b39a8aa018ee55ce0 100644 (file)
@@ -288,7 +288,7 @@ _cnputs(char * c, int size)
 #ifdef __x86_64__
        uint32_t lock_timeout_ticks = UINT32_MAX;
 #else
-       uint32_t lock_timeout_ticks = LockTimeOut;
+       uint32_t lock_timeout_ticks = LockTimeOut * 2; // 250ms is not enough, 500 is just right
 #endif
 
        mp_disable_preemption();
index 0d3b24380e1f95066e3c85b41572e94fb5621e79..afb0bd3065611417954f2a9ffa0985a63677dc7b 100644 (file)
@@ -814,6 +814,23 @@ routine io_device_tree_entry_exists_with_name(
        out exists              : boolean_t
        );
 
+routine io_registry_entry_get_properties_bin_buf(
+           registry_entry      : io_object_t;
+       in  buf                 : mach_vm_address_t;
+       inout  bufsize          : mach_vm_size_t;
+       out properties          : io_buf_ptr_t, physicalcopy
+       );
+
+routine io_registry_entry_get_property_bin_buf(
+           registry_entry      : io_object_t;
+       in  plane               : io_name_t;
+       in  property_name       : io_name_t;
+       in  options             : uint32_t;
+       in  buf                 : mach_vm_address_t;
+       inout  bufsize          : mach_vm_size_t;
+       out properties          : io_buf_ptr_t, physicalcopy
+       );
+
 #endif /* IOKIT */
 
 /* vim: set ft=c : */
index f1cc26e1e2916d391fef5bfcc32d7063ff98d151..91d1b477093536094a6342cbb16c76f342f435f6 100644 (file)
@@ -72,7 +72,7 @@
 #include <mach/port.h>
 
 #if PRIVATE
-#define IOKIT_SERVER_VERSION    20190423
+#define IOKIT_SERVER_VERSION    20190926
 #endif
 
 
index f6b970194709183d2fd65b363bb582ac27136393..5aae6aaeedaa76365def0a6e705f2ad7b9c01cd2 100644 (file)
@@ -561,7 +561,7 @@ efi_init(void)
 
 /* Returns TRUE if a page belongs to the EFI Runtime Services (code or data) */
 boolean_t
-efi_valid_page(ppnum_t ppn)
+bootloader_valid_page(ppnum_t ppn)
 {
        boot_args *args = (boot_args *)PE_state.bootArgs;
        ppnum_t    pstart = args->efiRuntimeServicesPageStart;
index aef78bcbd7b4bcbc347cfdf7b169907c3acf0be3..8f20ce6eb6f2e274810823e24fec3ca509c912e2 100644 (file)
@@ -259,7 +259,7 @@ physmap_init_L3(int startIndex, uint64_t highest_phys, uint64_t *physStart, pt_e
 }
 
 static void
-physmap_init(uint8_t phys_random_L3)
+physmap_init(uint8_t phys_random_L3, uint64_t *new_physmap_base, uint64_t *new_physmap_max)
 {
        pt_entry_t *l3pte;
        int pml4_index, i;
@@ -341,14 +341,14 @@ physmap_init(uint8_t phys_random_L3)
                    | INTEL_PTE_WRITE;
        }
 
-       physmap_base = KVADDR(kernPhysPML4Index, phys_random_L3, 0, 0);
+       *new_physmap_base = KVADDR(kernPhysPML4Index, phys_random_L3, 0, 0);
        /*
         * physAddr contains the last-mapped physical address, so that's what we
         * add to physmap_base to derive the ending VA for the physmap.
         */
-       physmap_max = physmap_base + physAddr;
+       *new_physmap_max = *new_physmap_base + physAddr;
 
-       DBG("Physical address map base: 0x%qx\n", physmap_base);
+       DBG("Physical address map base: 0x%qx\n", *new_physmap_base);
        for (i = kernPhysPML4Index; i < (kernPhysPML4Index + kernPhysPML4EntryCount); i++) {
                DBG("Physical map idlepml4[%d]: 0x%llx\n", i, IdlePML4[i]);
        }
@@ -360,6 +360,7 @@ static void
 Idle_PTs_init(void)
 {
        uint64_t        rand64;
+       uint64_t        new_physmap_base, new_physmap_max;
 
        /* Allocate the "idle" kernel page tables: */
        KPTphys  = ALLOCPAGES(NKPT);            /* level 1 */
@@ -391,13 +392,22 @@ Idle_PTs_init(void)
         * two 8-bit entropy values needed for address randomization.
         */
        rand64 = early_random();
-       physmap_init(rand64 & 0xFF);
+       physmap_init(rand64 & 0xFF, &new_physmap_base, &new_physmap_max);
        doublemap_init((rand64 >> 8) & 0xFF);
        idt64_remap();
 
        postcode(VSTART_SET_CR3);
 
-       // Switch to the page tables..
+       /*
+        * Switch to the page tables. We set physmap_base and physmap_max just
+        * before switching to the new page tables to avoid someone calling
+        * kprintf() or otherwise using physical memory in between.
+        * This is needed because kprintf() writes to physical memory using
+        * ml_phys_read_data and PHYSMAP_PTOV, which requires physmap_base to be
+        * set correctly.
+        */
+       physmap_base = new_physmap_base;
+       physmap_max = new_physmap_max;
        set_cr3_raw((uintptr_t)ID_MAP_VTOP(IdlePML4));
 }
 
@@ -569,6 +579,10 @@ vstart(vm_offset_t boot_args_start)
        boolean_t       is_boot_cpu = !(boot_args_start == 0);
        int             cpu = 0;
        uint32_t        lphysfree;
+#if DEBUG
+       uint64_t        gsbase;
+#endif
+
 
        postcode(VSTART_ENTRY);
 
@@ -657,8 +671,11 @@ vstart(vm_offset_t boot_args_start)
                set_cr3_raw((uintptr_t)ID_MAP_VTOP(IdlePML4));
                /* Find our logical cpu number */
                cpu = lapic_to_cpu[(LAPIC_READ(ID) >> LAPIC_ID_SHIFT) & LAPIC_ID_MASK];
-               DBG("CPU: %d, GSBASE initial value: 0x%llx\n", cpu, rdmsr64(MSR_IA32_GS_BASE));
+#if DEBUG
+               gsbase = rdmsr64(MSR_IA32_GS_BASE);
+#endif
                cpu_desc_load(cpu_datap(cpu));
+               DBG("CPU: %d, GSBASE initial value: 0x%llx\n", cpu, gsbase);
        }
 
        early_boot = 0;
@@ -704,6 +721,8 @@ i386_init(void)
 
        lck_mod_init();
 
+       printf_init();                  /* Init this in case we need debugger */
+
        /*
         * Initialize the timer callout world
         */
@@ -713,7 +732,6 @@ i386_init(void)
 
        postcode(CPU_INIT_D);
 
-       printf_init();                  /* Init this in case we need debugger */
        panic_init();                   /* Init this in case we need debugger */
 
        /* setup debugging output if one has been chosen */
index 5971b1cfe29116bf3b8c420e97e8cac3b2137ea0..0033e27cb6238d47ad816595d56c8705fec671b2 100644 (file)
@@ -828,7 +828,7 @@ pmap_traverse_present_mappings(pmap_t __unused pmap,
        if (ppn != 0)
        {
            if (((vcur < debug_start) || (vcur >= debug_end))
-               && !(EFI_VALID_PAGE(ppn) || pmap_valid_page(ppn))
+               && !(pmap_valid_page(ppn) || bootloader_valid_page(ppn))
 #if defined(XNU_TARGET_OS_BRIDGE)
                // include the macOS panic region if it's mapped
                && ((vcur < macos_panic_start) || (vcur >= macos_panic_end))
index a297107f3a73d6d310ca00e8a89ca4a03a757313..1b93c16e9dda78269cd280d74ad5c558083f071c 100644 (file)
@@ -174,12 +174,7 @@ int kern_dump_record_file(void *kdp_core_out_vars, const char *filename, uint64_
 
 int kern_dump_seek_to_next_file(void *kdp_core_out_varss, uint64_t next_file_offset);
 
-extern boolean_t efi_valid_page(ppnum_t ppn);
-#if defined(__x86_64__)
-#define EFI_VALID_PAGE(x)       efi_valid_page(x)
-#elif defined(__arm__) || defined(__arm64__)
-#define EFI_VALID_PAGE(x)       (FALSE)
-#endif /* defined (__x86_64__) */
+extern boolean_t bootloader_valid_page(ppnum_t ppn);
 
 #endif /* PRIVATE */
 
index cf83fb96e964b4958fd8fd70e27d167c3bf2d54e..5a26da66734e35b93223847e7eb620aa7522d66a 100644 (file)
@@ -129,11 +129,12 @@ enum {
        CS_HASH_MAX_SIZE = 48, /* max size of the hash we'll support */
 
 /*
- * Currently only to support Legacy VPN plugins,
+ * Currently only to support Legacy VPN plugins, and Mac App Store
  * but intended to replace all the various platform code, dev code etc. bits.
  */
        CS_SIGNER_TYPE_UNKNOWN = 0,
        CS_SIGNER_TYPE_LEGACYVPN = 5,
+       CS_SIGNER_TYPE_MAC_APP_STORE = 6,
 };
 
 #define KERNEL_HAVE_CS_CODEDIRECTORY 1
index 8af9d9cb20d09eb1541f90a14d130efb1773e02a..7fa53a8aaf95656ecb4315ca94b88ce2587852fe 100644 (file)
 
 #include <security/mac_mach_internal.h>
 
+#if CONFIG_CSR
+#include <sys/csr.h>
+#endif
+
 #if CONFIG_EMBEDDED && !SECURE_KERNEL
 extern int cs_relax_platform_task_ports;
 #endif
@@ -1168,7 +1172,7 @@ task_get_special_port(
  *             KERN_INVALID_ARGUMENT   The task is null.
  *             KERN_FAILURE            The task/space is dead.
  *             KERN_INVALID_ARGUMENT   Invalid special port.
- *              KERN_NO_ACCESS         Attempted overwrite of seatbelt port.
+ *      KERN_NO_ACCESS         Restricted access to set port.
  */
 
 kern_return_t
@@ -1177,9 +1181,6 @@ task_set_special_port(
        int             which,
        ipc_port_t      port)
 {
-       ipc_port_t *whichp;
-       ipc_port_t old;
-
        if (task == TASK_NULL) {
                return KERN_INVALID_ARGUMENT;
        }
@@ -1188,6 +1189,56 @@ task_set_special_port(
                return KERN_NO_ACCESS;
        }
 
+       switch (which) {
+       case TASK_KERNEL_PORT:
+       case TASK_HOST_PORT:
+#if CONFIG_CSR
+               if (csr_check(CSR_ALLOW_KERNEL_DEBUGGER) == 0) {
+                       /*
+                        * Only allow setting of task-self / task-host
+                        * special ports from user-space when SIP is
+                        * disabled (for Mach-on-Mach emulation).
+                        */
+                       break;
+               }
+#endif
+               return KERN_NO_ACCESS;
+       default:
+               break;
+       }
+
+       return task_set_special_port_internal(task, which, port);
+}
+
+/*
+ *     Routine:        task_set_special_port_internal
+ *     Purpose:
+ *             Changes one of the task's special ports,
+ *             setting it to the supplied send right.
+ *     Conditions:
+ *             Nothing locked.  If successful, consumes
+ *             the supplied send right.
+ *     Returns:
+ *             KERN_SUCCESS            Changed the special port.
+ *             KERN_INVALID_ARGUMENT   The task is null.
+ *             KERN_FAILURE            The task/space is dead.
+ *             KERN_INVALID_ARGUMENT   Invalid special port.
+ *      KERN_NO_ACCESS         Restricted access to overwrite port.
+ */
+
+kern_return_t
+task_set_special_port_internal(
+       task_t          task,
+       int             which,
+       ipc_port_t      port)
+{
+       ipc_port_t *whichp;
+       ipc_port_t old;
+
+       if (task == TASK_NULL) {
+               return KERN_INVALID_ARGUMENT;
+       }
+
        switch (which) {
        case TASK_KERNEL_PORT:
                whichp = &task->itk_sself;
@@ -1223,11 +1274,17 @@ task_set_special_port(
                return KERN_FAILURE;
        }
 
-       /* do not allow overwrite of seatbelt or task access ports */
-       if ((TASK_SEATBELT_PORT == which || TASK_ACCESS_PORT == which)
-           && IP_VALID(*whichp)) {
-               itk_unlock(task);
-               return KERN_NO_ACCESS;
+       /* Never allow overwrite of seatbelt, or task access ports */
+       switch (which) {
+       case TASK_SEATBELT_PORT:
+       case TASK_ACCESS_PORT:
+               if (IP_VALID(*whichp)) {
+                       itk_unlock(task);
+                       return KERN_NO_ACCESS;
+               }
+               break;
+       default:
+               break;
        }
 
        old = *whichp;
@@ -1240,7 +1297,6 @@ task_set_special_port(
        return KERN_SUCCESS;
 }
 
-
 /*
  *     Routine:        mach_ports_register [kernel call]
  *     Purpose:
index 8a9c4cd75920fde2c3b40204f73d056ac9b5d10f..e571487faff1f1dbb696c4f96cfc89ccdd0c90ac 100644 (file)
@@ -2070,7 +2070,7 @@ kdp_stackshot_kcdata_format(int pid, uint32_t trace_flags, uint32_t * pBytesTrac
                kcd_exit_on_error(kcdata_get_memory_addr(stackshot_kcdata_p, STACKSHOT_KCTYPE_OSVERSION, length_to_copy, &out_addr));
                stackshot_strlcpy((char*)out_addr, &version[0], length_to_copy);
 
-               length_to_copy =  MIN((uint32_t)(strlen(PE_boot_args()) + 1), OSVERSIZE);
+               length_to_copy =  MIN((uint32_t)(strlen(PE_boot_args()) + 1), BOOT_LINE_LENGTH);
                kcd_exit_on_error(kcdata_get_memory_addr(stackshot_kcdata_p, STACKSHOT_KCTYPE_BOOTARGS, length_to_copy, &out_addr));
                stackshot_strlcpy((char*)out_addr, PE_boot_args(), length_to_copy);
 
@@ -2637,6 +2637,7 @@ stackshot_coalition_jetsam_snapshot(void *arg, int i, coalition_t coal)
        task_t leader = TASK_NULL;
        jcs->jcs_id = coalition_id(coal);
        jcs->jcs_flags = 0;
+       jcs->jcs_thread_group = 0;
 
        if (coalition_term_requested(coal)) {
                jcs->jcs_flags |= kCoalitionTermRequested;
index a2585e4731d5c7617291dfa0e832eedb636e22c8..21742d6649ed3759bf2f34b158c8e77909a38c1f 100644 (file)
@@ -179,6 +179,7 @@ extern int kdb_printf_unbuffered(const char *format, ...) __printflike(1, 2);
 extern void printf_init(void);
 
 extern int snprintf(char *, size_t, const char *, ...) __printflike(3, 4);
+extern int scnprintf(char *, size_t, const char *, ...) __printflike(3, 4);
 
 extern void log(int level, char *fmt, ...);
 
index 917ae6db5c3823e5500820dad3d931080fd5741b..04e9db25eb20b5a300410fd2dbd14aa1f164b07a 100644 (file)
@@ -405,6 +405,11 @@ kernel_bootstrap(void)
        /* initialize exceptions */
        exception_init();
 
+#if CONFIG_SCHED_SFI
+       kernel_bootstrap_log("sfi_init");
+       sfi_init();
+#endif
+
        /*
         *      Create a kernel thread to execute the kernel bootstrap.
         */
@@ -636,11 +641,6 @@ kernel_bootstrap_thread(void)
        arm_vm_prot_finalize(PE_state.bootArgs);
 #endif
 
-#if CONFIG_SCHED_SFI
-       kernel_bootstrap_log("sfi_init");
-       sfi_init();
-#endif
-
        /*
         * Initialize the globals used for permuting kernel
         * addresses that may be exported to userland as tokens
index ebd6c2bb2ec5eb8fdee16c935cd542462d93b58b..832c774b4c5d2b445d9b1a61ff83cf23025dd093 100644 (file)
@@ -2213,7 +2213,7 @@ task_mark_corpse(task_t task)
 
        ipc_task_reset(task);
        /* Remove the naked send right for task port, needed to arm no sender notification */
-       task_set_special_port(task, TASK_KERNEL_PORT, IPC_PORT_NULL);
+       task_set_special_port_internal(task, TASK_KERNEL_PORT, IPC_PORT_NULL);
        ipc_task_enable(task);
 
        task_unlock(task);
@@ -4338,7 +4338,6 @@ host_security_set_task_token(
        task_lock(task);
        task->sec_token = sec_token;
        task->audit_token = audit_token;
-
        task_unlock(task);
 
        if (host_priv != HOST_PRIV_NULL) {
@@ -4347,7 +4346,8 @@ host_security_set_task_token(
                kr = host_get_host_port(host_priv_self(), &host_port);
        }
        assert(kr == KERN_SUCCESS);
-       kr = task_set_special_port(task, TASK_HOST_PORT, host_port);
+
+       kr = task_set_special_port_internal(task, TASK_HOST_PORT, host_port);
        return kr;
 }
 
index e47bb217c0aa9dc1f3d7d8ef9c9ba2871afb6e46..1c7ec758b822272c5ed669aef9c9a95fe7934c76 100644 (file)
@@ -697,6 +697,11 @@ extern kern_return_t    task_create_internal(
        uint8_t         t_returnwaitflags,
        task_t          *child_task);                                                   /* OUT */
 
+extern kern_return_t    task_set_special_port_internal(
+       task_t                  task,
+       int                     which,
+       ipc_port_t              port);
+
 extern kern_return_t    task_info(
        task_t                  task,
        task_flavor_t           flavor,
index 9f88ebefa21ba6bd6e54796d09a8d07188b28566..2e35400716c4d6c3051753b22ee07a76246cd6b7 100644 (file)
@@ -172,7 +172,7 @@ print_test_mtx_stats_string_name(
                break;
        }
 
-       return snprintf(buffer, size, "%s ", type);
+       return scnprintf(buffer, size, "%s ", type);
 }
 
 int
@@ -183,7 +183,7 @@ get_test_mtx_stats_string(
        int string_off = 0;
        int ret = 0;
 
-       ret = snprintf(&buffer[string_off], size, "\n");
+       ret = scnprintf(&buffer[string_off], size, "\n");
        size -= ret;
        string_off += ret;
 
@@ -191,40 +191,40 @@ get_test_mtx_stats_string(
        for (i = 0; i < TEST_MTX_MAX_STATS; i++) {
                struct lck_mtx_test_stats_elem* stat = &lck_mtx_test_stats[i];
 
-               ret = snprintf(&buffer[string_off], size, "{ ");
+               ret = scnprintf(&buffer[string_off], size, "{ ");
                size -= ret;
                string_off += ret;
 
                lck_spin_lock(&stat->lock);
                uint64_t time;
 
-               ret = snprintf(&buffer[string_off], size, "samples %llu, ", stat->samples);
+               ret = scnprintf(&buffer[string_off], size, "samples %llu, ", stat->samples);
                size -= ret;
                string_off += ret;
 
                absolutetime_to_nanoseconds(stat->tot, &time);
-               ret = snprintf(&buffer[string_off], size, "tot %llu ns, ", time);
+               ret = scnprintf(&buffer[string_off], size, "tot %llu ns, ", time);
                size -= ret;
                string_off += ret;
 
                absolutetime_to_nanoseconds(stat->avg, &time);
-               ret = snprintf(&buffer[string_off], size, "avg %llu ns, ", time);
+               ret = scnprintf(&buffer[string_off], size, "avg %llu ns, ", time);
                size -= ret;
                string_off += ret;
 
                absolutetime_to_nanoseconds(stat->max, &time);
-               ret = snprintf(&buffer[string_off], size, "max %llu ns, ", time);
+               ret = scnprintf(&buffer[string_off], size, "max %llu ns, ", time);
                size -= ret;
                string_off += ret;
 
                absolutetime_to_nanoseconds(stat->min, &time);
-               ret = snprintf(&buffer[string_off], size, "min %llu ns", time);
+               ret = scnprintf(&buffer[string_off], size, "min %llu ns", time);
                size -= ret;
                string_off += ret;
 
                lck_spin_unlock(&stat->lock);
 
-               ret = snprintf(&buffer[string_off], size, " } ");
+               ret = scnprintf(&buffer[string_off], size, " } ");
                size -= ret;
                string_off += ret;
 
@@ -232,7 +232,7 @@ get_test_mtx_stats_string(
                size -= ret;
                string_off += ret;
 
-               ret = snprintf(&buffer[string_off], size, "\n");
+               ret = scnprintf(&buffer[string_off], size, "\n");
                size -= ret;
                string_off += ret;
        }
@@ -494,12 +494,12 @@ lck_mtx_test_mtx_uncontended_loop_time(
        int string_off = 0;
        int ret = 0;
 
-       ret = snprintf(&buffer[string_off], size, "\n");
+       ret = scnprintf(&buffer[string_off], size, "\n");
        size -= ret;
        string_off += ret;
 
        for (i = 0; i < TEST_MTX_MAX_STATS - 2; i++) {
-               ret = snprintf(&buffer[string_off], size, "total time %llu ns total run time %llu ns ", tot_time[i], run_time[i]);
+               ret = scnprintf(&buffer[string_off], size, "total time %llu ns total run time %llu ns ", tot_time[i], run_time[i]);
                size -= ret;
                string_off += ret;
 
@@ -507,7 +507,7 @@ lck_mtx_test_mtx_uncontended_loop_time(
                size -= ret;
                string_off += ret;
 
-               ret = snprintf(&buffer[string_off], size, "\n");
+               ret = scnprintf(&buffer[string_off], size, "\n");
                size -= ret;
                string_off += ret;
        }
@@ -1015,10 +1015,10 @@ lck_mtx_test_mtx_contended_loop_time(
        absolutetime_to_nanoseconds(end_loop_time - start_loop_time, &time);
        absolutetime_to_nanoseconds(end_loop_time_run - start_loop_time_run, &time_run);
 
-       ret = snprintf(buffer, buffer_size, "\n");
-       ret += snprintf(&buffer[ret], buffer_size - ret, "total time %llu ns total run time %llu ns ", time, time_run);
+       ret = scnprintf(buffer, buffer_size, "\n");
+       ret += scnprintf(&buffer[ret], buffer_size - ret, "total time %llu ns total run time %llu ns ", time, time_run);
        ret += print_test_mtx_stats_string_name(TEST_MTX_LOCK_STATS, &buffer[ret], buffer_size - ret);
-       ret += snprintf(&buffer[ret], buffer_size - ret, "\n");
+       ret += scnprintf(&buffer[ret], buffer_size - ret, "\n");
 
        return ret;
 }
index 13fbdad05bb3cbe19e939b8c469ab80fabbd3d68..548c48e1c59b77ad97011faea7bf791a719e0358 100644 (file)
@@ -412,7 +412,7 @@ static inline void
 mask_saved_state_cpsr(arm_saved_state_t *iss, uint32_t set_bits, uint32_t clear_bits)
 {
        iss->cpsr |= set_bits;
-       iss->cpsr &= clear_bits;
+       iss->cpsr &= ~clear_bits;
 }
 
 static inline void
index d20642916da4e5849dd1fe15a54c78999a575c07..62dfb35f5200debe487faf688981ef366cccfabb 100644 (file)
@@ -76,6 +76,7 @@
 #include <kern/misc_protos.h>
 #include <vm/cpm.h>
 #include <kern/ledger.h>
+#include <kern/bits.h>
 
 #include <string.h>
 
@@ -1347,6 +1348,59 @@ kmem_suballoc(
        *new_map = map;
        return KERN_SUCCESS;
 }
+/*
+ * The default percentage of memory that can be mlocked is scaled based on the total
+ * amount of memory in the system. These percentages are caclulated
+ * offline and stored in this table. We index this table by
+ * log2(max_mem) - VM_USER_WIREABLE_MIN_CONFIG. We clamp this index in the range
+ * [0, sizeof(wire_limit_percents) / sizeof(vm_map_size_t))
+ *
+ * Note that these values were picked for mac.
+ * If we ever have very large memory config arm devices, we may want to revisit
+ * since the kernel overhead is smaller there due to the larger page size.
+ */
+
+/* Start scaling iff we're managing > 2^32 = 4GB of RAM. */
+#define VM_USER_WIREABLE_MIN_CONFIG 32
+static vm_map_size_t wire_limit_percents[] =
+{ 70, 73, 76, 79, 82, 85, 88, 91, 94, 97};
+
+/*
+ * Sets the default global user wire limit which limits the amount of
+ * memory that can be locked via mlock() based on the above algorithm..
+ * This can be overridden via a sysctl.
+ */
+static void
+kmem_set_user_wire_limits(void)
+{
+       uint64_t available_mem_log;
+       uint64_t max_wire_percent;
+       size_t wire_limit_percents_length = sizeof(wire_limit_percents) /
+           sizeof(vm_map_size_t);
+       vm_map_size_t limit;
+       available_mem_log = bit_floor(max_mem);
+
+       if (available_mem_log < VM_USER_WIREABLE_MIN_CONFIG) {
+               available_mem_log = 0;
+       } else {
+               available_mem_log -= VM_USER_WIREABLE_MIN_CONFIG;
+       }
+       if (available_mem_log >= wire_limit_percents_length) {
+               available_mem_log = wire_limit_percents_length - 1;
+       }
+       max_wire_percent = wire_limit_percents[available_mem_log];
+
+       limit = max_mem * max_wire_percent / 100;
+       /* Cap the number of non lockable bytes at VM_NOT_USER_WIREABLE_MAX */
+       if (max_mem - limit > VM_NOT_USER_WIREABLE_MAX) {
+               limit = max_mem - VM_NOT_USER_WIREABLE_MAX;
+       }
+
+       vm_global_user_wire_limit = limit;
+       /* the default per task limit is the same as the global limit */
+       vm_per_task_user_wire_limit = limit;
+}
+
 
 /*
  *     kmem_init:
@@ -1443,21 +1497,9 @@ kmem_init(
        }
 #endif
 
-       /*
-        * Set the default global user wire limit which limits the amount of
-        * memory that can be locked via mlock().  We set this to the total
-        * amount of memory that are potentially usable by a user app (max_mem)
-        * minus a certain amount.  This can be overridden via a sysctl.
-        */
-       vm_global_no_user_wire_amount = MIN(max_mem * 20 / 100,
-           VM_NOT_USER_WIREABLE);
-       vm_global_user_wire_limit = max_mem - vm_global_no_user_wire_amount;
-
-       /* the default per user limit is the same as the global limit */
-       vm_user_wire_limit = vm_global_user_wire_limit;
+       kmem_set_user_wire_limits();
 }
 
-
 /*
  *     Routine:        copyinmap
  *     Purpose:
index 9d25f2777b192ef0755bd39d83f83bbf68f26ed2..7a046695156165c3e7a7891ccd6ad403edffb6df 100644 (file)
@@ -278,7 +278,6 @@ extern void             kmem_init(
        vm_offset_t     start,
        vm_offset_t     end);
 
-
 extern kern_return_t    copyinmap(
        vm_map_t        map,
        vm_map_offset_t fromaddr,
index d130132c30bd3b34ab6251047e6b1e0ce9a688b9..305c8d67700ad6386fba685f4475045d90215f71 100644 (file)
@@ -867,6 +867,9 @@ int malloc_no_cow = 0;
 #define VM_PROTECT_WX_FAIL 1
 #endif /* CONFIG_EMBEDDED */
 uint64_t vm_memory_malloc_no_cow_mask = 0ULL;
+#if DEBUG
+int vm_check_map_sanity = 0;
+#endif
 
 /*
  *     vm_map_init:
@@ -1016,6 +1019,15 @@ vm_map_init(
                    &vm_memory_malloc_no_cow_mask,
                    sizeof(vm_memory_malloc_no_cow_mask));
        }
+
+#if DEBUG
+       PE_parse_boot_argn("vm_check_map_sanity", &vm_check_map_sanity, sizeof(vm_check_map_sanity));
+       if (vm_check_map_sanity) {
+               kprintf("VM sanity checking enabled\n");
+       } else {
+               kprintf("VM sanity checking disabled. Set bootarg vm_check_map_sanity=1 to enable\n");
+       }
+#endif /* DEBUG */
 }
 
 void
@@ -6135,14 +6147,13 @@ add_wire_counts(
                        /*
                         * Since this is the first time the user is wiring this map entry, check to see if we're
                         * exceeding the user wire limits.  There is a per map limit which is the smaller of either
-                        * the process's rlimit or the global vm_user_wire_limit which caps this value.  There is also
+                        * the process's rlimit or the global vm_per_task_user_wire_limit which caps this value.  There is also
                         * a system-wide limit on the amount of memory all users can wire.  If the user is over either
                         * limit, then we fail.
                         */
 
-                       if (size + map->user_wire_size > MIN(map->user_wire_limit, vm_user_wire_limit) ||
-                           size + ptoa_64(total_wire_count) > vm_global_user_wire_limit ||
-                           size + ptoa_64(total_wire_count) > max_mem - vm_global_no_user_wire_amount) {
+                       if (size + map->user_wire_size > MIN(map->user_wire_limit, vm_per_task_user_wire_limit) ||
+                           size + ptoa_64(total_wire_count) > vm_global_user_wire_limit) {
                                return KERN_RESOURCE_SHORTAGE;
                        }
 
@@ -11376,37 +11387,20 @@ vm_map_copyin_internal(
                 *      Attempt non-blocking copy-on-write optimizations.
                 */
 
-               if (src_destroy &&
-                   (src_object == VM_OBJECT_NULL ||
-                   (src_object->internal &&
-                   src_object->copy_strategy == MEMORY_OBJECT_COPY_SYMMETRIC &&
-                   src_entry->vme_start <= src_addr &&
-                   src_entry->vme_end >= src_end &&
-                   !map_share))) {
-                       /*
-                        * If we are destroying the source, and the object
-                        * is internal, we can move the object reference
-                        * from the source to the copy.  The copy is
-                        * copy-on-write only if the source is.
-                        * We make another reference to the object, because
-                        * destroying the source entry will deallocate it.
-                        *
-                        * This memory transfer has to be atomic (to prevent
-                        * the VM object from being shared or copied while
-                        * it's being moved here), so we can only do this
-                        * if we won't have to unlock the VM map, i.e. the
-                        * entire range must be covered by this map entry.
-                        */
-                       vm_object_reference(src_object);
-
-                       /*
-                        * Copy is always unwired.  vm_map_copy_entry
-                        * set its wired count to zero.
-                        */
-
-                       goto CopySuccessful;
-               }
-
+               /*
+                * If we are destroying the source, and the object
+                * is internal, we could move the object reference
+                * from the source to the copy.  The copy is
+                * copy-on-write only if the source is.
+                * We make another reference to the object, because
+                * destroying the source entry will deallocate it.
+                *
+                * This memory transfer has to be atomic, (to prevent
+                * the VM object from being shared or copied while
+                * it's being moved here), so we could only do this
+                * if we won't have to unlock the VM map until the
+                * original mapping has been fully removed.
+                */
 
 RestartCopy:
                if ((src_object == VM_OBJECT_NULL ||
index b036575e71b9ffb050d97ed0e267ec1afb327c84..bcecbea57ee45acc43dd53b8305572310264e0f6 100644 (file)
@@ -217,6 +217,8 @@ vm_map_delete_hole(vm_map_t map, vm_map_entry_t hole_entry)
  */
 
 #if DEBUG
+extern int vm_check_map_sanity;
+
 static void
 check_map_sanity(vm_map_t map, vm_map_entry_t old_hole_entry)
 {
@@ -369,7 +371,9 @@ update_holes_on_entry_deletion(vm_map_t map, vm_map_entry_t old_entry)
                                }
                                create_new_hole = FALSE;
 #if DEBUG
-                               check_map_sanity(map, &old_hole_entry);
+                               if (vm_check_map_sanity) {
+                                       check_map_sanity(map, &old_hole_entry);
+                               }
 #endif /* DEBUG */
                                break;
                        }
@@ -386,7 +390,9 @@ update_holes_on_entry_deletion(vm_map_t map, vm_map_entry_t old_entry)
                                create_new_hole = FALSE;
 
 #if DEBUG
-                               check_map_sanity(map, &old_hole_entry);
+                               if (vm_check_map_sanity) {
+                                       check_map_sanity(map, &old_hole_entry);
+                               }
 #endif /* DEBUG */
                                break;
                        }
@@ -461,7 +467,9 @@ update_holes_on_entry_deletion(vm_map_t map, vm_map_entry_t old_entry)
        }
 
 #if DEBUG
-       check_map_sanity(map, &old_hole_entry);
+       if (vm_check_map_sanity) {
+               check_map_sanity(map, &old_hole_entry);
+       }
 #endif /* DEBUG */
 
        SAVE_HINT_HOLE_WRITE(map, (struct vm_map_links*) hole_entry);
@@ -535,7 +543,7 @@ update_holes_on_entry_creation(vm_map_t map, vm_map_entry_t new_entry)
                        vm_map_delete_hole(map, hole_entry);
 
 #if DEBUG
-                       if (check_map_with_hole_sanity) {
+                       if (vm_check_map_sanity && check_map_with_hole_sanity) {
                                check_map_sanity(map, &old_hole_entry);
                        }
 #endif /* DEBUG */
@@ -564,7 +572,7 @@ update_holes_on_entry_creation(vm_map_t map, vm_map_entry_t new_entry)
                        assert(new_hole_entry->start < new_hole_entry->end);
 
 #if DEBUG
-                       if (check_map_with_hole_sanity) {
+                       if (vm_check_map_sanity && check_map_with_hole_sanity) {
                                check_map_sanity(map, &old_hole_entry);
                        }
 #endif /* DEBUG */
@@ -588,7 +596,7 @@ update_holes_on_entry_creation(vm_map_t map, vm_map_entry_t new_entry)
                        }
 
 #if DEBUG
-                       if (check_map_with_hole_sanity) {
+                       if (vm_check_map_sanity && check_map_with_hole_sanity) {
                                check_map_sanity(map, &old_hole_entry);
                        }
 #endif /* DEBUG */
@@ -611,7 +619,7 @@ update_holes_on_entry_creation(vm_map_t map, vm_map_entry_t new_entry)
                        }
 
 #if DEBUG
-                       if (check_map_with_hole_sanity) {
+                       if (vm_check_map_sanity && check_map_with_hole_sanity) {
                                check_map_sanity(map, &old_hole_entry);
                        }
 #endif /* DEBUG */
index e9a3fbdf8ee7cac32ed7a654de8b6498e3522af6..7ae8651903b24f297e6a601f0e1adb7dda00b85c 100644 (file)
@@ -1020,22 +1020,28 @@ unsigned int    vm_cache_geometry_colors; /* optimal #colors based on cache geom
  * Wired memory is a very limited resource and we can't let users exhaust it
  * and deadlock the entire system.  We enforce the following limits:
  *
- * vm_user_wire_limit (default: all memory minus vm_global_no_user_wire_amount)
+ * vm_per_task_user_wire_limit
  *      how much memory can be user-wired in one user task
  *
- * vm_global_user_wire_limit (default: same as vm_user_wire_limit)
+ * vm_global_user_wire_limit (default: same as vm_per_task_user_wire_limit)
  *      how much memory can be user-wired in all user tasks
  *
- * vm_global_no_user_wire_amount (default: VM_NOT_USER_WIREABLE)
- *     how much memory must remain user-unwired at any time
+ * These values are set to defaults based on the number of pages managed
+ * by the VM system. They can be overriden via sysctls.
+ * See kmem_set_user_wire_limits for details on the default values.
+ *
+ * Regardless of the amount of memory in the system, we never reserve
+ * more than VM_NOT_USER_WIREABLE_MAX bytes as unlockable.
  */
-#define VM_NOT_USER_WIREABLE (64*1024*1024)     /* 64MB */
+#if defined(__LP64__)
+#define VM_NOT_USER_WIREABLE_MAX (32ULL*1024*1024*1024)     /* 32GB */
+#else
+#define VM_NOT_USER_WIREABLE_MAX (1UL*1024*1024*1024)     /* 1GB */
+#endif /* __LP64__ */
 extern
-vm_map_size_t   vm_user_wire_limit;
+vm_map_size_t   vm_per_task_user_wire_limit;
 extern
 vm_map_size_t   vm_global_user_wire_limit;
-extern
-vm_map_size_t   vm_global_no_user_wire_amount;
 
 /*
  *     Each pageable resident page falls into one of three lists:
index cec75e459be6af135216980993f5c1efcfe8d00a..d66ac2f6447afb8224a740eeb6b12c6a652f87c9 100644 (file)
@@ -339,7 +339,7 @@ kasan_report_leak(vm_address_t base, vm_size_t sz, vm_offset_t offset, vm_size_t
                size_t l = 0;
                num_frames = kasan_alloc_retrieve_bt(base, alloc_bt);
                for (vm_size_t i = 0; i < num_frames; i++) {
-                       l += snprintf(string_rep + l, sizeof(string_rep) - l, " %lx", alloc_bt[i]);
+                       l += scnprintf(string_rep + l, sizeof(string_rep) - l, " %lx", alloc_bt[i]);
                }
        }
 
@@ -445,7 +445,7 @@ kasan_shadow_crashlog(uptr p, char *buf, size_t len)
        shadow &= ~((uptr)0xf);
        shadow -= 16 * before;
 
-       n += snprintf(buf+n, len-n,
+       n += scnprintf(buf+n, len-n,
                        " Shadow             0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n");
 
        for (i = 0; i < 1 + before + after; i++, shadow += 16) {
@@ -454,7 +454,7 @@ kasan_shadow_crashlog(uptr p, char *buf, size_t len)
                        continue;
                }
 
-               n += snprintf(buf+n, len-n, " %16lx:", shadow);
+               n += scnprintf(buf+n, len-n, " %16lx:", shadow);
 
                char *left = " ";
                char *right;
@@ -470,13 +470,13 @@ kasan_shadow_crashlog(uptr p, char *buf, size_t len)
                                right = "";
                        }
 
-                       n += snprintf(buf+n, len-n, "%s%02x%s", left, (unsigned)*x, right);
+                       n += scnprintf(buf+n, len-n, "%s%02x%s", left, (unsigned)*x, right);
                        left = "";
                }
-               n += snprintf(buf+n, len-n, "\n");
+               n += scnprintf(buf+n, len-n, "\n");
        }
 
-       n += snprintf(buf+n, len-n, "\n");
+       n += scnprintf(buf+n, len-n, "\n");
        return n;
 }
 
@@ -496,11 +496,11 @@ kasan_report_internal(uptr p, uptr width, access_t access, violation_t reason, b
        buf[0] = '\0';
 
        if (reason == REASON_MOD_OOB || reason == REASON_BAD_METADATA) {
-               n += snprintf(buf+n, len-n, "KASan: free of corrupted/invalid object %#lx\n", p);
+               n += scnprintf(buf+n, len-n, "KASan: free of corrupted/invalid object %#lx\n", p);
        } else if (reason == REASON_MOD_AFTER_FREE) {
-               n += snprintf(buf+n, len-n, "KASan: UaF of quarantined object %#lx\n", p);
+               n += scnprintf(buf+n, len-n, "KASan: UaF of quarantined object %#lx\n", p);
        } else {
-               n += snprintf(buf+n, len-n, "KASan: invalid %lu-byte %s %#lx [%s]\n",
+               n += scnprintf(buf+n, len-n, "KASan: invalid %lu-byte %s %#lx [%s]\n",
                                width, access_str(access), p, shadow_str);
        }
        n += kasan_shadow_crashlog(p, buf+n, len-n);
@@ -540,11 +540,11 @@ kasan_log_report(uptr p, uptr width, access_t access, violation_t reason)
            NULL); /* ignore current frame */
 
        buf[0] = '\0';
-       l += snprintf(buf+l, len-l, "Backtrace: ");
+       l += scnprintf(buf+l, len-l, "Backtrace: ");
        for (uint32_t i = 0; i < nframes; i++) {
-               l += snprintf(buf+l, len-l, "%lx,", VM_KERNEL_UNSLIDE(bt[i]));
+               l += scnprintf(buf+l, len-l, "%lx,", VM_KERNEL_UNSLIDE(bt[i]));
        }
-       l += snprintf(buf+l, len-l, "\n");
+       l += scnprintf(buf+l, len-l, "\n");
 
        printf("%s", buf);
 }
index 04eea747f6eec8ebba3d4a0ace13e6f3dac385d3..0259027d1c5bcc3c712f48c53b5be4d68bedb6de 100644 (file)
@@ -37,7 +37,7 @@ static const char *get_type_check_kind(uint8_t kind);
 static size_t
 format_loc(struct san_src_loc *loc, char *dst, size_t sz)
 {
-       return snprintf(dst, sz, "  loc: %s:%d:%d\n",
+       return scnprintf(dst, sz, "  loc: %s:%d:%d\n",
                   loc->filename,
                   loc->line & ~line_acquired,
                   loc->col
@@ -73,7 +73,7 @@ static size_t
 format_overflow(struct ubsan_violation *v, char *buf, size_t sz)
 {
        struct san_type_desc *ty = v->overflow->ty;
-       return snprintf(buf, sz,
+       return scnprintf(buf, sz,
                   "%s overflow, op = %s, ty = %s, width = %d, lhs = 0x%llx, rhs = 0x%llx\n",
                   ty->issigned ? "signed" : "unsigned",
                   overflow_str[v->ubsan_type],
@@ -91,9 +91,9 @@ format_shift(struct ubsan_violation *v, char *buf, size_t sz)
        struct san_type_desc *l = v->shift->lhs_t;
        struct san_type_desc *r = v->shift->rhs_t;
 
-       n += snprintf(buf + n, sz - n, "bad shift\n");
-       n += snprintf(buf + n, sz - n, "  lhs: 0x%llx, ty = %s, signed = %d, width = %d\n", v->lhs, l->name, l->issigned, 1 << l->width);
-       n += snprintf(buf + n, sz - n, "  rhs: 0x%llx, ty = %s, signed = %d, width = %d\n", v->rhs, r->name, r->issigned, 1 << r->width);
+       n += scnprintf(buf + n, sz - n, "bad shift\n");
+       n += scnprintf(buf + n, sz - n, "  lhs: 0x%llx, ty = %s, signed = %d, width = %d\n", v->lhs, l->name, l->issigned, 1 << l->width);
+       n += scnprintf(buf + n, sz - n, "  rhs: 0x%llx, ty = %s, signed = %d, width = %d\n", v->rhs, r->name, r->issigned, 1 << r->width);
 
        return n;
 }
@@ -122,14 +122,14 @@ format_type_mismatch(struct ubsan_violation *v, char *buf, size_t sz)
        const char * kind = get_type_check_kind(v->align->kind);
        if (NULL == ptr) {
                //null pointer use
-               n += snprintf(buf + n, sz - n, "%s NULL pointer of type %s\n", kind, v->align->ty->name);
+               n += scnprintf(buf + n, sz - n, "%s NULL pointer of type %s\n", kind, v->align->ty->name);
        } else if (alignment && ((uintptr_t)ptr & (alignment - 1))) {
                //misaligned pointer use
-               n += snprintf(buf + n, sz - n, "%s mis-aligned address %p for type %s ", kind, (void*)v->lhs, v->align->ty->name);
-               n += snprintf(buf + n, sz - n, "which requires %d byte alignment\n", 1 << v->align->align);
+               n += scnprintf(buf + n, sz - n, "%s mis-aligned address %p for type %s ", kind, (void*)v->lhs, v->align->ty->name);
+               n += scnprintf(buf + n, sz - n, "which requires %d byte alignment\n", 1 << v->align->align);
        } else {
                //insufficient object size
-               n += snprintf(buf + n, sz - n, "%s address %p with insufficient space for an object of type %s\n",
+               n += scnprintf(buf + n, sz - n, "%s address %p with insufficient space for an object of type %s\n",
                    kind, ptr, v->align->ty->name);
        }
 
@@ -144,10 +144,10 @@ format_oob(struct ubsan_violation *v, char *buf, size_t sz)
        struct san_type_desc *ity = v->oob->index_ty;
        uintptr_t idx = v->lhs;
 
-       n += snprintf(buf + n, sz - n, "OOB array access\n");
-       n += snprintf(buf + n, sz - n, "  idx %ld\n", idx);
-       n += snprintf(buf + n, sz - n, "  aty: ty = %s, signed = %d, width = %d\n", aty->name, aty->issigned, 1 << aty->width);
-       n += snprintf(buf + n, sz - n, "  ity: ty = %s, signed = %d, width = %d\n", ity->name, ity->issigned, 1 << ity->width);
+       n += scnprintf(buf + n, sz - n, "OOB array access\n");
+       n += scnprintf(buf + n, sz - n, "  idx %ld\n", idx);
+       n += scnprintf(buf + n, sz - n, "  aty: ty = %s, signed = %d, width = %d\n", aty->name, aty->issigned, 1 << aty->width);
+       n += scnprintf(buf + n, sz - n, "  ity: ty = %s, signed = %d, width = %d\n", ity->name, ity->issigned, 1 << ity->width);
 
        return n;
 }
@@ -162,7 +162,7 @@ ubsan_format(struct ubsan_violation *v, char *buf, size_t sz)
                n += format_overflow(v, buf + n, sz - n);
                break;
        case UBSAN_UNREACHABLE:
-               n += snprintf(buf + n, sz - n, "unreachable\n");
+               n += scnprintf(buf + n, sz - n, "unreachable\n");
                break;
        case UBSAN_SHIFT:
                n += format_shift(v, buf + n, sz - n);
@@ -171,13 +171,13 @@ ubsan_format(struct ubsan_violation *v, char *buf, size_t sz)
                n += format_type_mismatch(v, buf + n, sz - n);
                break;
        case UBSAN_POINTER_OVERFLOW:
-               n += snprintf(buf + n, sz - n, "pointer overflow, before = 0x%llx, after = 0x%llx\n", v->lhs, v->rhs);
+               n += scnprintf(buf + n, sz - n, "pointer overflow, before = 0x%llx, after = 0x%llx\n", v->lhs, v->rhs);
                break;
        case UBSAN_OOB:
                n += format_oob(v, buf + n, sz - n);
                break;
        case UBSAN_GENERIC:
-               n += snprintf(buf + n, sz - n, "%s\n", v->func);
+               n += scnprintf(buf + n, sz - n, "%s\n", v->func);
                break;
        default:
                panic("unknown violation");
index 4c5e65c907222f3f7dd190bfcfdbeb5c169082c1..c559c84d1aaf491abcfaf3c5a0468c713ded419e 100644 (file)
@@ -97,6 +97,10 @@ stackshot_tests: OTHER_CFLAGS += -Wno-objc-messaging-id
 stackshot_tests: OTHER_LDFLAGS += -lkdd -ldarwintest_utils -framework Foundation
 stackshot_tests: INVALID_ARCHS = i386
 
+stackshot_accuracy: OTHER_CFLAGS += -ldarwintest_utils -Wno-objc-messaging-id
+stackshot_accuracy: OTHER_LDFLAGS += -lkdd -ldarwintest_utils -framework Foundation
+stackshot_accuracy: INVALID_ARCHS = i386
+
 telemetry: OTHER_LDFLAGS = -framework ktrace -framework CoreFoundation
 telemetry: INVALID_ARCHS = i386
 
diff --git a/tests/route_output_stack_oflow_56033075.c b/tests/route_output_stack_oflow_56033075.c
new file mode 100644 (file)
index 0000000..becd258
--- /dev/null
@@ -0,0 +1,88 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+#include <net/route.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <darwintest.h>
+
+#define ROUNDUP32(n) (((n) + sizeof(uint32_t) - 1) & ~(sizeof(uint32_t) - 1))
+
+T_DECL(route_output_stack_oflow_56033075, "Stack overflow via ma_copy through route_output")
+{
+       int s;
+       uint8_t buf[
+               sizeof(struct rt_msghdr) +
+               ROUNDUP32(sizeof(struct sockaddr_storage) + 1) + /* RTAX_DST */
+               ROUNDUP32(sizeof(struct sockaddr_storage) + 1) + /* RTAX_GATEWAY */
+               ROUNDUP32(sizeof(struct sockaddr_storage) + 1)   /* RTAX_NETMASK */
+       ];
+       struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
+       struct sockaddr *sa;
+       size_t len;
+
+       bzero(buf, sizeof(buf));
+       rtm->rtm_type = RTM_GET;
+       rtm->rtm_version = RTM_VERSION;
+       rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
+       len = sizeof(struct rt_msghdr);
+
+       /* RTAX_DST: */
+       sa = (struct sockaddr *)(rtm + 1);
+       sa->sa_family = AF_INET6;
+       sa->sa_len = sizeof(struct sockaddr_storage) + 1;
+       memset(&sa->sa_data[0], 0xff, sa->sa_len);
+       len += ROUNDUP32(sa->sa_len);
+
+       /* RTAX_GATEWAY: */
+       sa = (struct sockaddr *)((void *)buf + len);
+       sa->sa_family = AF_INET6;
+       sa->sa_len = sizeof(struct sockaddr_storage) + 1;
+       memset(&sa->sa_data[0], 0xff, sa->sa_len);
+       len += ROUNDUP32(sa->sa_len);
+
+       /* RTAX_NETMASK: */
+       sa = (struct sockaddr *)((void *)buf + len);
+       sa->sa_family = AF_INET6;
+       sa->sa_len = sizeof(struct sockaddr_storage) + 1;
+       memset(&sa->sa_data[0], 0x41, sa->sa_len);
+       len += ROUNDUP32(sa->sa_len);
+
+       T_SETUPBEGIN;
+       T_ASSERT_POSIX_SUCCESS(s = socket(PF_ROUTE, SOCK_RAW, PF_ROUTE), NULL);
+       T_SETUPEND;
+
+       /* check we get EINVAL for > sizeof(struct sockaddr_storage): */
+       rtm->rtm_msglen = len;
+       T_ASSERT_EQ(-1, send(s, buf, len, 0), NULL);
+       T_ASSERT_EQ(EINVAL, errno, NULL);
+
+       /* now check the ok case: */
+       len = sizeof(struct rt_msghdr);
+
+       /* RTAX_DST: */
+       sa = (struct sockaddr *)(rtm + 1);
+       sa->sa_family = AF_INET6;
+       sa->sa_len = sizeof(struct sockaddr_storage);
+       len += ROUNDUP32(sa->sa_len);
+
+       /* RTAX_GATEWAY: */
+       sa = (struct sockaddr *)((void *)buf + len);
+       sa->sa_family = AF_INET6;
+       sa->sa_len = sizeof(struct sockaddr_storage);
+       len += ROUNDUP32(sa->sa_len);
+
+       /* RTAX_NETMASK: */
+       sa = (struct sockaddr *)((void *)buf + len);
+       sa->sa_family = AF_INET6;
+       sa->sa_len = sizeof(struct sockaddr_storage);
+       len += ROUNDUP32(sa->sa_len);
+
+       rtm->rtm_msglen = len;
+       T_ASSERT_EQ(-1, send(s, buf, len, 0), NULL);
+       T_ASSERT_EQ(ESRCH, errno, NULL);
+}
diff --git a/tests/stackshot_accuracy.m b/tests/stackshot_accuracy.m
new file mode 100644 (file)
index 0000000..a183a87
--- /dev/null
@@ -0,0 +1,558 @@
+#include <darwintest.h>
+#include <darwintest_utils.h>
+#include <sys/kern_memorystatus.h>
+#include <kern/debug.h>
+#include <mach-o/dyld.h>
+#include <sys/stackshot.h>
+#include <kdd.h>
+#include <signal.h>
+
+#define RECURSIONS 25
+#define FIRST_RECURSIVE_FRAME 3
+
+T_GLOBAL_META(
+               T_META_NAMESPACE("xnu.stackshot.accuracy"),
+               T_META_CHECK_LEAKS(false),
+               T_META_ASROOT(true)
+               );
+
+
+void child_init(void);
+void parent_helper_singleproc(int);
+
+#define CHECK_FOR_FAULT_STATS         (1 << 0)
+#define WRITE_STACKSHOT_BUFFER_TO_TMP (1 << 1)
+#define CHECK_FOR_KERNEL_THREADS      (1 << 2)
+int check_stackshot(void *, int);
+
+/* used for WRITE_STACKSHOT_BUFFER_TO_TMP */
+static char const *current_scenario_name;
+static pid_t child_pid;
+
+/* helpers */
+
+static void __attribute__((noinline))
+child_recurse(int r, int spin, void (^cb)(void))
+{
+       if (r > 0) {
+               child_recurse(r - 1, spin, cb);
+       }
+
+       cb();
+
+       /* wait forever */
+       if (spin == 0) {
+               sleep(100000);
+       } else if (spin == 2) {
+               int v = 1;
+               /* ssh won't let the session die if we still have file handles open to its output. */
+               close(STDERR_FILENO);
+               close(STDOUT_FILENO);
+               T_ASSERT_POSIX_SUCCESS(sysctlbyname("kern.wedge_thread", NULL, NULL, &v, sizeof(v)),
+                                       "wedged thread in the kernel");
+       } else {
+               while (1) {
+                       __asm__ volatile("" : : : "memory");
+               }
+       }
+}
+
+T_HELPER_DECL(simple_child_process, "child process that will be frozen and others")
+{
+       child_init();
+}
+
+T_HELPER_DECL(sid_child_process, "child process that setsid()s")
+{
+       pid_t ppid = getppid();
+
+       T_ASSERT_POSIX_SUCCESS(setsid(), "session id set");
+
+       child_recurse(RECURSIONS, 2, ^{
+               kill(ppid, SIGUSR1);
+       });
+
+       T_ASSERT_FAIL("child_init returned!");
+}
+
+static void
+kill_children(void)
+{
+       kill(child_pid, SIGKILL);
+}
+
+static void *
+take_stackshot(pid_t target_pid, uint32_t extra_flags, uint64_t since_timestamp)
+{
+       void *stackshot_config;
+       int err, retries = 5;
+       uint32_t stackshot_flags = STACKSHOT_KCDATA_FORMAT |
+                                                               STACKSHOT_THREAD_WAITINFO |
+                                                               STACKSHOT_GET_DQ;
+
+       /* we should be able to verify delta stackshots */
+       if (since_timestamp != 0) {
+               stackshot_flags |= STACKSHOT_COLLECT_DELTA_SNAPSHOT;
+       }
+
+       stackshot_flags |= extra_flags;
+
+       stackshot_config = stackshot_config_create();
+       T_ASSERT_NOTNULL(stackshot_config, "allocate stackshot config");
+
+       err = stackshot_config_set_flags(stackshot_config, stackshot_flags);
+       T_ASSERT_EQ(err, 0, "set flags on stackshot config");
+
+       err = stackshot_config_set_pid(stackshot_config, target_pid);
+       T_ASSERT_EQ(err, 0, "set target pid on stackshot config");
+
+       if (since_timestamp != 0) {
+               err = stackshot_config_set_delta_timestamp(stackshot_config, since_timestamp);
+               T_ASSERT_EQ(err, 0, "set prev snapshot time on stackshot config");
+       }
+
+       while (retries > 0) {
+               err = stackshot_capture_with_config(stackshot_config);
+               if (err == 0) {
+                       break;
+               } else if (err == EBUSY || err == ETIMEDOUT) {
+                       T_LOG("stackshot capture returned %d (%s)\n", err, strerror(err));
+                       if (retries == 0) {
+                               T_ASSERT_FAIL("failed to take stackshot with error after retries: %d: %s\n", err, strerror(err));
+                       }
+
+                       retries--;
+                       continue;
+               } else {
+                       T_ASSERT_FAIL("failed to take stackshot with error: %d: %s\n", err, strerror(err));
+               }
+       }
+
+       return stackshot_config;
+}
+
+int
+check_stackshot(void *stackshot_config, int flags)
+{
+       void *buf;
+       uint32_t buflen, kcdata_type;
+       kcdata_iter_t iter;
+       NSError *nserror = nil;
+       pid_t target_pid;
+       int ret = 0;
+       uint64_t expected_return_addr = 0;
+       bool found_fault_stats = false;
+       struct stackshot_fault_stats fault_stats = {0};
+
+       buf = stackshot_config_get_stackshot_buffer(stackshot_config);
+       T_ASSERT_NOTNULL(buf, "stackshot buffer is not null");
+       buflen = stackshot_config_get_stackshot_size(stackshot_config);
+       T_ASSERT_GT(buflen, 0, "valid stackshot buffer length");
+       target_pid = ((struct stackshot_config*)stackshot_config)->sc_pid;
+       T_ASSERT_GT(target_pid, 0, "valid target_pid");
+
+       /* if need to write it to fs, do it now */
+       if (flags & WRITE_STACKSHOT_BUFFER_TO_TMP) {
+               char sspath[MAXPATHLEN];
+               strlcpy(sspath, current_scenario_name, sizeof(sspath));
+               strlcat(sspath, ".kcdata", sizeof(sspath));
+               T_QUIET; T_ASSERT_POSIX_ZERO(dt_resultfile(sspath, sizeof(sspath)),
+                               "create result file path");
+
+               FILE *f = fopen(sspath, "w");
+               T_WITH_ERRNO; T_QUIET; T_ASSERT_NOTNULL(f,
+                               "open stackshot output file");
+
+               size_t written = fwrite(buf, buflen, 1, f);
+               T_QUIET; T_ASSERT_POSIX_SUCCESS(written, "wrote stackshot to file");
+
+               fclose(f);
+       }
+
+       /* begin iterating */
+       iter = kcdata_iter(buf, buflen);
+       T_ASSERT_EQ(kcdata_iter_type(iter), KCDATA_BUFFER_BEGIN_STACKSHOT, "buffer is a stackshot");
+
+       /* time to iterate */
+       iter = kcdata_iter_next(iter);
+       KCDATA_ITER_FOREACH(iter) {
+               kcdata_type = kcdata_iter_type(iter);
+               NSNumber *parsedPid;
+               NSMutableDictionary *parsedContainer, *parsedThreads;
+
+               if ((flags & CHECK_FOR_FAULT_STATS) != 0 &&
+                               kcdata_type == STACKSHOT_KCTYPE_STACKSHOT_FAULT_STATS) {
+                       memcpy(&fault_stats, kcdata_iter_payload(iter), sizeof(fault_stats));
+                       found_fault_stats = true;
+               }
+
+               if (kcdata_type != KCDATA_TYPE_CONTAINER_BEGIN) {
+                       continue;
+               }
+               
+               if (kcdata_iter_container_type(iter) != STACKSHOT_KCCONTAINER_TASK) {
+                       continue;
+               }
+
+               parsedContainer = parseKCDataContainer(&iter, &nserror);
+               T_ASSERT_NOTNULL(parsedContainer, "parsedContainer is not null");
+               T_ASSERT_NULL(nserror, "no NSError occured while parsing the kcdata container");
+
+               /* 
+                * given that we've targetted the pid, we can be sure that this
+                * ts_pid will be the pid we expect
+                */
+               parsedPid = parsedContainer[@"task_snapshots"][@"task_snapshot"][@"ts_pid"];
+               T_ASSERT_EQ([parsedPid intValue], target_pid, "found correct pid");
+
+               /* start parsing the threads */
+               parsedThreads = parsedContainer[@"task_snapshots"][@"thread_snapshots"];
+               for (id th_key in parsedThreads) {
+                       uint32_t frame_index = 0;
+
+                       if ((flags & CHECK_FOR_KERNEL_THREADS) == 0) {
+                               /* skip threads that don't have enough frames */
+                               if ([parsedThreads[th_key][@"user_stack_frames"] count] < RECURSIONS) {
+                                       continue;
+                               }
+
+                               for (id frame in parsedThreads[th_key][@"user_stack_frames"]) {
+                                       if ((frame_index >= FIRST_RECURSIVE_FRAME) && (frame_index < (RECURSIONS - FIRST_RECURSIVE_FRAME))) {
+                                               if (expected_return_addr == 0ull) {
+                                                       expected_return_addr = [frame[@"lr"] unsignedLongLongValue];
+                                               } else {
+                                                       T_QUIET;
+                                                       T_ASSERT_EQ(expected_return_addr, [frame[@"lr"] unsignedLongLongValue], "expected return address found");
+                                               }
+                                       }
+                                       frame_index ++;
+                               }
+                       } else {
+                               T_ASSERT_NOTNULL(parsedThreads[th_key][@"kernel_stack_frames"],
+                                               "found kernel stack frames");
+                       }
+
+               }
+       }
+
+       if (found_fault_stats) {
+               T_LOG("number of pages faulted in: %d", fault_stats.sfs_pages_faulted_in);
+               T_LOG("MATUs spent faulting: %lld", fault_stats.sfs_time_spent_faulting);
+               T_LOG("MATUS fault time limit: %lld", fault_stats.sfs_system_max_fault_time);
+               T_LOG("did we stop because of the limit?: %s", fault_stats.sfs_stopped_faulting ? "yes" : "no");
+               if (expected_return_addr != 0ull) {
+                       T_ASSERT_GT(fault_stats.sfs_pages_faulted_in, 0, "faulted at least one page in");
+                       T_LOG("NOTE: successfully faulted in the pages");
+               } else {
+                       T_LOG("NOTE: We were not able to fault the stack's pages back in");
+
+                       /* if we couldn't fault the pages back in, then at least verify that we tried */
+                       T_ASSERT_GT(fault_stats.sfs_time_spent_faulting, 0ull, "spent time trying to fault");
+               }
+       } else if ((flags & CHECK_FOR_KERNEL_THREADS) == 0) {
+               T_ASSERT_NE(expected_return_addr, 0ull, "found child thread with recursions");
+       }
+
+       if (flags & CHECK_FOR_FAULT_STATS) {
+               T_ASSERT_EQ(found_fault_stats, true, "found fault stats");
+       }
+
+       return ret;
+}
+
+void
+child_init(void)
+{
+#if !TARGET_OS_OSX
+       int freeze_state;
+#endif /* !TARGET_OS_OSX */
+       pid_t pid = getpid();
+       char padding[16 * 1024];
+       __asm__ volatile(""::"r"(padding));
+
+       T_LOG("child pid: %d\n", pid);
+
+#if !TARGET_OS_OSX
+       /* allow us to be frozen */
+       freeze_state = memorystatus_control(MEMORYSTATUS_CMD_GET_PROCESS_IS_FREEZABLE, pid, 0, NULL, 0);
+       if (freeze_state == -1) {
+               T_SKIP("This device doesn't have CONFIG_FREEZE enabled.");
+       } else if (freeze_state == 0) {
+               T_LOG("CHILD was found to be UNFREEZABLE, enabling freezing.");
+               memorystatus_control(MEMORYSTATUS_CMD_SET_PROCESS_IS_FREEZABLE, pid, 1, NULL, 0);
+               freeze_state = memorystatus_control(MEMORYSTATUS_CMD_GET_PROCESS_IS_FREEZABLE, pid, 0, NULL, 0);
+               T_ASSERT_EQ(freeze_state, 1, "successfully set freezeability");
+       }
+#else
+       T_LOG("Cannot change freezeability as freezing is only available on embedded devices");
+#endif /* !TARGET_OS_OSX */
+
+       /* 
+        * recurse a bunch of times to generate predictable data in the stackshot,
+        * then send SIGUSR1 to the parent to let it know that we are done.
+        */
+       child_recurse(RECURSIONS, 0, ^{
+               kill(getppid(), SIGUSR1);
+       });
+
+       T_ASSERT_FAIL("child_recurse returned, but it must not?");
+}
+
+void
+parent_helper_singleproc(int spin)
+{
+       dispatch_semaphore_t child_done_sema = dispatch_semaphore_create(0);
+       dispatch_queue_t dq = dispatch_queue_create("com.apple.stackshot_accuracy.basic_sp", NULL);
+       void *stackshot_config;
+
+       dispatch_async(dq, ^{
+               char padding[16 * 1024];
+               __asm__ volatile(""::"r"(padding));
+
+               child_recurse(RECURSIONS, spin, ^{
+                       dispatch_semaphore_signal(child_done_sema);
+               });
+       });
+
+       dispatch_semaphore_wait(child_done_sema, DISPATCH_TIME_FOREVER);
+       T_LOG("done waiting for child");
+
+       /* take the stackshot and parse it */
+       stackshot_config = take_stackshot(getpid(), 0, 0);
+
+       /* check that the stackshot has the stack frames */
+       check_stackshot(stackshot_config, 0);
+
+       T_LOG("done!");
+}
+
+T_DECL(basic, "test that no-fault stackshot works correctly")
+{
+       char path[PATH_MAX];
+       uint32_t path_size = sizeof(path);
+       char *args[] = { path, "-n", "simple_child_process", NULL };
+       dispatch_queue_t dq = dispatch_queue_create("com.apple.stackshot_accuracy.basic", NULL);
+       dispatch_semaphore_t child_done_sema = dispatch_semaphore_create(0);
+       dispatch_source_t child_sig_src;
+       void *stackshot_config;
+
+       current_scenario_name = __func__;
+
+       T_LOG("parent pid: %d\n", getpid());
+       T_QUIET; T_ASSERT_POSIX_ZERO(_NSGetExecutablePath(path, &path_size), "_NSGetExecutablePath");
+
+       /* setup signal handling */
+       signal(SIGUSR1, SIG_IGN);
+       child_sig_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGUSR1, 0, dq);
+       dispatch_source_set_event_handler(child_sig_src, ^{
+               dispatch_semaphore_signal(child_done_sema);
+       });
+       dispatch_activate(child_sig_src);
+
+       /* create the child process */
+       T_ASSERT_POSIX_SUCCESS(dt_launch_tool(&child_pid, args, false, NULL, NULL), "child launched");
+       T_ATEND(kill_children);
+
+       /* wait until the child has recursed enough */
+       dispatch_semaphore_wait(child_done_sema, DISPATCH_TIME_FOREVER);
+
+       T_LOG("child finished, parent executing");
+
+       /* take the stackshot and parse it */
+       stackshot_config = take_stackshot(child_pid, 0, 0);
+
+       /* check that the stackshot has the stack frames */
+       check_stackshot(stackshot_config, 0);   
+
+       T_LOG("all done, killing child");
+
+       /* tell the child to quit */
+       T_ASSERT_POSIX_SUCCESS(kill(child_pid, SIGTERM), "killed child");
+}
+
+T_DECL(basic_singleproc, "test that no-fault stackshot works correctly in single process setting")
+{
+       current_scenario_name = __func__;
+       parent_helper_singleproc(0);
+}
+
+T_DECL(basic_singleproc_spin, "test that no-fault stackshot works correctly in single process setting with spinning")
+{
+       current_scenario_name = __func__;
+       parent_helper_singleproc(1);
+}
+
+T_DECL(fault, "test that faulting stackshots work correctly")
+{
+       dispatch_queue_t dq = dispatch_queue_create("com.apple.stackshot_fault_accuracy", NULL);
+       dispatch_source_t child_sig_src;
+       dispatch_semaphore_t child_done_sema = dispatch_semaphore_create(0);
+       void *stackshot_config;
+       int oldftm, newval = 1, freeze_enabled, oldratio, newratio = 0;
+       size_t oldlen = sizeof(oldftm), fe_len = sizeof(freeze_enabled), ratiolen = sizeof(oldratio);
+       char path[PATH_MAX];
+       uint32_t path_size = sizeof(path);
+       char *args[] = { path, "-n", "simple_child_process", NULL };
+
+       current_scenario_name = __func__;
+       T_QUIET; T_ASSERT_POSIX_ZERO(_NSGetExecutablePath(path, &path_size), "_NSGetExecutablePath");
+
+#if TARGET_OS_OSX
+       T_SKIP("freezing is not available on macOS");
+#endif /* TARGET_OS_OSX */
+
+       /* Try checking if freezing is enabled at all */
+       if (sysctlbyname("vm.freeze_enabled", &freeze_enabled, &fe_len, NULL, 0) == -1) {
+               if (errno == ENOENT) {
+                       T_SKIP("This device doesn't have CONFIG_FREEZE enabled.");
+               } else {
+                       T_FAIL("failed to query vm.freeze_enabled, errno: %d", errno);
+               }
+       }
+
+       if (!freeze_enabled) {
+               T_SKIP("Freeze is not enabled, skipping test.");
+       }
+
+       /* signal handling */
+       signal(SIGUSR1, SIG_IGN);
+       child_sig_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGUSR1, 0, dq);
+       dispatch_source_set_event_handler(child_sig_src, ^{
+               dispatch_semaphore_signal(child_done_sema);
+       });
+       dispatch_activate(child_sig_src);
+
+       T_ASSERT_POSIX_SUCCESS(dt_launch_tool(&child_pid, args, false, NULL, NULL), "child launched");
+       T_ATEND(kill_children);
+
+       dispatch_semaphore_wait(child_done_sema, DISPATCH_TIME_FOREVER);
+
+       /* keep processes in memory */
+       T_ASSERT_POSIX_SUCCESS(sysctlbyname("kern.memorystatus_freeze_to_memory", &oldftm, &oldlen, &newval, sizeof(newval)),
+                       "disabled freezing to disk");
+
+       /* set the ratio to zero */
+       T_ASSERT_POSIX_SUCCESS(sysctlbyname("kern.memorystatus_freeze_private_shared_pages_ratio", &oldratio, &ratiolen, &newratio, sizeof(newratio)), "disabled private:shared ratio checking");
+
+       /* freeze the child */
+       T_ASSERT_POSIX_SUCCESS(sysctlbyname("kern.memorystatus_freeze", NULL, 0, &child_pid, sizeof(child_pid)),
+                       "froze child");
+
+       /* Sleep to allow the compressor to finish compressing the child */
+       sleep(5);
+
+       /* take the stackshot and parse it */
+       stackshot_config = take_stackshot(child_pid, STACKSHOT_ENABLE_BT_FAULTING | STACKSHOT_ENABLE_UUID_FAULTING, 0);
+
+       /* check that the stackshot has the stack frames */
+       check_stackshot(stackshot_config, CHECK_FOR_FAULT_STATS);
+
+       T_ASSERT_POSIX_SUCCESS(sysctlbyname("kern.memorystatus_freeze_to_memory", NULL, 0, &oldftm, sizeof(oldftm)),
+                       "reset freezing to disk");
+
+       /* reset the private:shared ratio */
+       T_ASSERT_POSIX_SUCCESS(sysctlbyname("kern.memorystatus_freeze_private_shared_pages_ratio", NULL, 0, &oldratio, sizeof(oldratio)), "reset private:shared ratio");
+
+       T_LOG("all done, killing child");
+
+       /* tell the child to quit */
+       T_ASSERT_POSIX_SUCCESS(kill(child_pid, SIGTERM), "killed child");
+}
+
+T_DECL(fault_singleproc, "test that faulting stackshots work correctly in a single process setting")
+{
+       dispatch_semaphore_t child_done_sema = dispatch_semaphore_create(0);
+       dispatch_queue_t dq = dispatch_queue_create("com.apple.stackshot_accuracy.fault_sp", NULL);
+       void *stackshot_config;
+       __block pthread_t child_thread;
+       char *child_stack;
+       size_t child_stacklen;
+
+#if !TARGET_OS_OSX
+       T_SKIP("madvise(..., ..., MADV_PAGEOUT) is not available on embedded platforms");
+#endif /* !TARGET_OS_OSX */
+
+       dispatch_async(dq, ^{
+               char padding[16 * 1024];
+               __asm__ volatile(""::"r"(padding));
+
+               child_recurse(RECURSIONS, 0, ^{
+                       child_thread = pthread_self();
+                       dispatch_semaphore_signal(child_done_sema);
+               });
+       });
+
+       dispatch_semaphore_wait(child_done_sema, DISPATCH_TIME_FOREVER);
+       T_LOG("done waiting for child");
+
+       child_stack = pthread_get_stackaddr_np(child_thread);
+       child_stacklen = pthread_get_stacksize_np(child_thread);
+       child_stack -= child_stacklen;
+       T_LOG("child stack: [0x%p - 0x%p]: 0x%zu bytes", (void *)child_stack,
+                       (void *)(child_stack + child_stacklen), child_stacklen);
+
+       /* paging out the child */
+       T_ASSERT_POSIX_SUCCESS(madvise(child_stack, child_stacklen, MADV_PAGEOUT), "paged out via madvise(2) the child stack");
+
+       /* take the stackshot and parse it */
+       stackshot_config = take_stackshot(getpid(), STACKSHOT_ENABLE_BT_FAULTING | STACKSHOT_ENABLE_UUID_FAULTING, 0);
+
+       /* check that the stackshot has the stack frames */
+       check_stackshot(stackshot_config, CHECK_FOR_FAULT_STATS);
+
+       T_LOG("done!");
+}
+
+T_DECL(zombie, "test that threads wedged in the kernel can be stackshot'd")
+{
+       dispatch_queue_t dq = dispatch_queue_create("com.apple.stackshot_accuracy.zombie", NULL);
+       dispatch_semaphore_t child_done_sema = dispatch_semaphore_create(0);
+       dispatch_source_t child_sig_src;
+       void *stackshot_config;
+       char path[PATH_MAX];
+       uint32_t path_size = sizeof(path);
+       char *args[] = { path, "-n", "sid_child_process", NULL };
+
+       current_scenario_name = __func__;
+       T_QUIET; T_ASSERT_POSIX_ZERO(_NSGetExecutablePath(path, &path_size), "_NSGetExecutablePath");
+
+       T_LOG("parent pid: %d\n", getpid());
+
+       /* setup signal handling */
+       signal(SIGUSR1, SIG_IGN);
+       child_sig_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGUSR1, 0, dq);
+       dispatch_source_set_event_handler(child_sig_src, ^{
+               dispatch_semaphore_signal(child_done_sema);
+       });
+       dispatch_activate(child_sig_src);
+
+       /* create the child process */
+       T_ASSERT_POSIX_SUCCESS(dt_launch_tool(&child_pid, args, false, NULL, NULL), "child launched");
+       T_ATEND(kill_children);
+
+       /* wait until the child has recursed enough */
+       dispatch_semaphore_wait(child_done_sema, DISPATCH_TIME_FOREVER);
+
+       T_LOG("child finished, parent executing. invoking jetsam");
+
+       T_ASSERT_POSIX_SUCCESS(memorystatus_control(MEMORYSTATUS_CMD_TEST_JETSAM, child_pid, 0, 0, 0),
+                       "jetsam'd the child");
+
+       /* Sleep to allow the target process to become zombified */
+       sleep(1);
+
+       /* take the stackshot and parse it */
+       stackshot_config = take_stackshot(child_pid, 0, 0);
+
+       /* check that the stackshot has the stack frames */
+       check_stackshot(stackshot_config, CHECK_FOR_KERNEL_THREADS);
+
+       T_LOG("all done, unwedging and killing child");
+
+       int v = 1;
+       T_ASSERT_POSIX_SUCCESS(sysctlbyname("kern.unwedge_thread", NULL, NULL, &v, sizeof(v)),
+                       "unwedged child");
+
+       /* tell the child to quit */
+       T_ASSERT_POSIX_SUCCESS(kill(child_pid, SIGTERM), "killed child");
+}
index f1a1ffbce882ac4324a2b23f1e69d127c939b0c5..cedc9f7ece8b4ac4103df7cf935e906242959a38 100644 (file)
@@ -32,16 +32,16 @@ main_test(void)
        kr = vm_allocate(__self, &tmp_buf, tmp_size, VM_FLAGS_ANYWHERE | VM_FLAGS_PURGABLE);
        T_QUIET;
        T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_allocate(%zu) error 0x%x (%s)",
-           tmp_size, kr, mach_error_string(kr));
+           (size_t) tmp_size, kr, mach_error_string(kr));
        T_QUIET;
-       T_EXPECT_NE(tmp_buf, 0UL, "failed to allocate temporary purgable buffer\n");
+       T_EXPECT_NE(tmp_buf, (vm_address_t) 0, "failed to allocate temporary purgable buffer\n");
 
        kr = vm_allocate(__self, &tmp_buf2, tmp_size, VM_FLAGS_ANYWHERE | VM_FLAGS_PURGABLE);
        T_QUIET;
        T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_allocate(%zu) error 0x%x (%s)",
-           tmp_size, kr, mach_error_string(kr));
+           (size_t) tmp_size, kr, mach_error_string(kr));
        T_QUIET;
-       T_EXPECT_NE(tmp_buf2, 0UL, "failed to allocate temporary purgable buffer\n");
+       T_EXPECT_NE(tmp_buf2, (vm_address_t) 0, "failed to allocate temporary purgable buffer\n");
 
        /* expected failures */
        out_size = tmp_size;
diff --git a/tests/sysctl_wire_limits.c b/tests/sysctl_wire_limits.c
new file mode 100644 (file)
index 0000000..165f060
--- /dev/null
@@ -0,0 +1,198 @@
+#include <time.h>
+#include <errno.h>
+
+#include <mach/mach.h>
+#include <sys/kern_sysctl.h>
+#include <sys/mman.h>
+
+#include <darwintest.h>
+#include <darwintest_utils.h>
+
+
+static const char *g_sysctl_no_wire_name = "vm.global_no_user_wire_amount";
+static const char *g_sysctl_wire_name = "vm.global_user_wire_limit";
+static const char *g_sysctl_per_task_wire_name = "vm.user_wire_limit";
+static const char *g_sysctl_current_wired_count_name = "vm.page_wire_count";
+static const char *g_sysctl_current_free_count_name = "vm.lopage_free_count";
+static const char *g_sysctl_vm_page_size_name = "vm.pagesize";
+static const char *g_sysctl_memsize_name = "hw.memsize";
+
+static size_t
+ptoa(size_t num_pages)
+{
+       static size_t page_size = 0;
+       int ret;
+       size_t page_size_size = sizeof(page_size);
+       if (page_size == 0) {
+               ret = sysctlbyname(g_sysctl_vm_page_size_name, &page_size, &page_size_size, NULL, 0);
+               T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "Unable to get page size");
+       }
+       return num_pages * (size_t) page_size;
+}
+
+
+T_DECL(global_no_user_wire_amount, "no_user_wire_amount <= 32G") {
+       int ret;
+       vm_map_size_t no_wire;
+       size_t no_wire_size = sizeof(no_wire);
+       ret = sysctlbyname(g_sysctl_no_wire_name, &no_wire, &no_wire_size, NULL, 0);
+       T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "no_user_wire sysctl failed");
+       T_QUIET; T_EXPECT_LE(no_wire, 32 * 2ULL << 30, "no_user_wire_amount is too big.");
+}
+
+T_DECL(user_wire_amount, "max_mem > user_wire_amount >= 0.7 * max_mem") {
+       int ret;
+       vm_map_size_t wire;
+       uint64_t max_mem;
+       size_t max_mem_size = sizeof(max_mem);
+       size_t wire_size = sizeof(wire);
+       ret = sysctlbyname(g_sysctl_memsize_name, &max_mem, &max_mem_size, NULL, 0);
+       T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "memsize sysctl failed");
+       ret = sysctlbyname(g_sysctl_wire_name, &wire, &wire_size, NULL, 0);
+       T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "user_wire sysctl failed");
+       T_QUIET; T_ASSERT_LT(wire, max_mem, "wire limit is too big");
+       T_QUIET; T_ASSERT_GE(wire, max_mem * 70 / 100, "wire limit is too small.");
+}
+
+/*
+ * Sets the no wire limit, and ensures that the wire_limit
+ * changes correctly.
+ */
+static void
+set_no_wire_limit(vm_map_size_t value, uint64_t max_mem)
+{
+       vm_map_size_t wire;
+       size_t wire_size = sizeof(wire);
+       int ret;
+       ret = sysctlbyname(g_sysctl_no_wire_name, NULL, 0, &value, sizeof(value));
+       T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "no_user_wire sysctl set failed");
+       ret = sysctlbyname(g_sysctl_wire_name, &wire, &wire_size, NULL, 0);
+       T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "user_wire sysctl failed");
+       T_QUIET; T_ASSERT_EQ(max_mem - wire, value, "no wire size is incorrect");
+}
+
+/*
+ * Sets the wire limit, and ensures that the no_wire_limit
+ * changes correctly.
+ */
+static void
+set_wire_limit(vm_map_size_t value, uint64_t max_mem)
+{
+       vm_map_size_t no_wire;
+       size_t no_wire_size = sizeof(no_wire);
+       int ret;
+       ret = sysctlbyname(g_sysctl_wire_name, NULL, 0, &value, sizeof(value));
+       T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "user_wire sysctl set failed");
+       ret = sysctlbyname(g_sysctl_no_wire_name, &no_wire, &no_wire_size, NULL, 0);
+       T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "no_user_wire sysctl failed");
+       T_QUIET; T_ASSERT_EQ(max_mem - value, no_wire, "no wire size is incorrect");
+}
+
+T_DECL(set_global_no_user_wire_amount, "Setting no_user_wire_amount changes global_user_wire_amount", T_META_ASROOT(true)) {
+       int ret;
+       vm_map_size_t no_wire, wire;
+       vm_map_size_t no_wire_delta = 16 * (1 << 10);
+       uint64_t max_mem;
+       size_t no_wire_size = sizeof(no_wire);
+       size_t wire_size = sizeof(wire);
+       size_t max_mem_size = sizeof(max_mem);
+       ret = sysctlbyname(g_sysctl_memsize_name, &max_mem, &max_mem_size, NULL, 0);
+       T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "max_mem sysctl failed");
+       ret = sysctlbyname(g_sysctl_no_wire_name, &no_wire, &no_wire_size, NULL, 0);
+       T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "no_user_wire sysctl failed");
+       ret = sysctlbyname(g_sysctl_wire_name, &wire, &wire_size, NULL, 0);
+       T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "user_wire sysctl failed");
+       T_QUIET; T_ASSERT_EQ(max_mem - wire, no_wire, "no wire size is incorrect");
+
+       // Set the no_wire limit and ensure that the wire_size changed.
+       set_no_wire_limit(no_wire + no_wire_delta, max_mem);
+       set_no_wire_limit(no_wire, max_mem);
+       // Set the wire limit and ensure that the no_wire_limit has changed
+       set_wire_limit(wire - no_wire_delta, max_mem);
+       set_wire_limit(wire, max_mem);
+}
+
+T_DECL(set_user_wire_limit, "Set user_wire_limit", T_META_ASROOT(true)) {
+       vm_map_size_t wire, original_wire;
+       size_t wire_size = sizeof(wire);
+       int ret;
+       vm_map_size_t wire_delta = 48 * (1 << 10);
+       ret = sysctlbyname(g_sysctl_per_task_wire_name, &original_wire, &wire_size, NULL, 0);
+       T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "user_wire sysctl get failed");
+       wire = original_wire + wire_delta;
+       ret = sysctlbyname(g_sysctl_per_task_wire_name, NULL, 0, &wire, wire_size);
+       T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "user_wire sysctl set failed");
+       ret = sysctlbyname(g_sysctl_per_task_wire_name, &wire, &wire_size, NULL, 0);
+       T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "user_wire sysctl get failed");
+       T_QUIET; T_ASSERT_EQ(wire, original_wire + wire_delta, "user_wire sysctl didn't set the correct value.");
+
+       // Cleanup
+       ret = sysctlbyname(g_sysctl_per_task_wire_name, NULL, 0, &original_wire, wire_size);
+       T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "user_wire sysctl set failed");
+}
+
+#if TARGET_OS_OSX
+/*
+ * Test that wiring up to the limit doesn't hang the system.
+ * We only test this on OS X. On all other platforms, we'd expect
+ * to get jetsamm'ed for doing this.
+ */
+static void *
+wire_to_limit(size_t limit, size_t *size)
+{
+       // Trying to wire directly to the limit is likely to fail
+       // repeatedly since other wired pages are probably coming and going
+       // so we just try to get close.
+       const unsigned int wiggle_room_pages = 1000;
+       int ret;
+       unsigned int current_wired, current_free;
+       size_t buffer_size, offset_from_limit;
+       void *buffer;
+       size_t current_wired_size = sizeof(current_wired);
+       size_t current_free_size = sizeof(current_free);
+       while (true) {
+               ret = sysctlbyname(g_sysctl_current_wired_count_name, &current_wired, &current_wired_size, NULL, 0);
+               T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "get current wired count failed");
+               ret = sysctlbyname(g_sysctl_current_free_count_name, &current_free, &current_free_size, NULL, 0);
+               T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "get current free count failed");
+               offset_from_limit = ptoa(current_wired + current_free + wiggle_room_pages);
+               T_QUIET; T_ASSERT_GE(limit, offset_from_limit, "more pages are wired than the limit.");
+               buffer_size = limit - offset_from_limit;
+               buffer = malloc(buffer_size);
+               T_QUIET; T_ASSERT_NOTNULL(buffer, "Unable to allocate buffer");
+               ret = mlock(buffer, buffer_size);
+               if (ret == 0) {
+                       break;
+               }
+               free(buffer);
+       }
+       *size = buffer_size;
+       return buffer;
+}
+
+T_DECL(wire_stress_test, "wire up to global_user_wire_limit and spin for 120 seconds.") {
+       static const int kNumSecondsToSpin = 120;
+       int ret;
+       struct timespec start, now;
+       size_t buffer_size;
+       size_t wire_limit;
+       size_t wire_limit_size = sizeof(wire_limit);
+       void *buffer;
+
+       ret = sysctlbyname(g_sysctl_wire_name, &wire_limit, &wire_limit_size, NULL, 0);
+       T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "user_wire sysctl failed");
+       buffer = wire_to_limit(wire_limit, &buffer_size);
+       ret = clock_gettime(CLOCK_MONOTONIC, &start);
+       T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "Unable to get current time.");
+       while (true) {
+               ret = clock_gettime(CLOCK_MONOTONIC, &now);
+               T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "Unable to get current time.");
+               if (now.tv_sec - start.tv_sec >= kNumSecondsToSpin) {
+                       break;
+               }
+       }
+       ret = munlock(buffer, buffer_size);
+       T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "Unable to unlock memory.");
+       free(buffer);
+}
+#endif /* TARGET_OS_OSX */
diff --git a/tests/tcp_input_outputopts_uaf_56155583.c b/tests/tcp_input_outputopts_uaf_56155583.c
new file mode 100644 (file)
index 0000000..cf0347c
--- /dev/null
@@ -0,0 +1,102 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <darwintest.h>
+
+/* sizeof(struct ip6_pktopts) */
+#define SIZEOF_STRUCT_IP6_PKTOPTS 192
+
+static int finished = 0;
+
+static void *
+setopt_thread(void *data)
+{
+       int s = *(int *)data;
+       uint8_t optbuf[CMSG_LEN(0)];
+       uint8_t spraybuf[SIZEOF_STRUCT_IP6_PKTOPTS];
+
+       memset(optbuf, 0, sizeof(optbuf));
+       memset(spraybuf, 0x41, sizeof(spraybuf));
+
+       while (!finished) {
+               T_ASSERT_POSIX_SUCCESS(setsockopt(s, IPPROTO_IPV6, IPV6_2292PKTOPTIONS, optbuf, sizeof(optbuf)), NULL);
+
+               /* force an error to free: */
+               T_ASSERT_EQ(setsockopt(s, IPPROTO_IPV6, IPV6_2292PKTOPTIONS, optbuf, 1), -1, NULL);
+
+               /* realloc: */
+               T_ASSERT_EQ(ioctl(-1, _IOW('x', 0, spraybuf), spraybuf), -1, NULL);
+       }
+
+       return NULL;
+}
+
+static void *
+connect_thread(void *data)
+{
+       struct sockaddr_in6 *dst = data;
+       int s;
+
+       while (!finished) {
+               T_ASSERT_POSIX_SUCCESS(s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP), NULL);
+               connect(s, (const struct sockaddr *)dst, sizeof(*dst));
+               close(s);
+       }
+
+       return NULL;
+}
+
+T_DECL(tcp_input_outputopts_uaf_56155583, "Use-after-free when accepting TCP6 connections.")
+{
+       int s;
+       struct sockaddr_in6 sin6 = {
+               .sin6_family = AF_INET6,
+               .sin6_port = htons(1337)
+       };
+       struct sockaddr_in6 addr;
+       socklen_t addr_len;
+       pthread_t threads[20];
+       int nthreads = 0;
+       int n;
+
+       T_SETUPBEGIN;
+       T_ASSERT_EQ(inet_pton(AF_INET6, "::1", &sin6.sin6_addr), 1, NULL);
+       T_ASSERT_POSIX_SUCCESS(s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP), NULL);
+       T_ASSERT_POSIX_SUCCESS(bind(s, (const struct sockaddr *)&sin6, sizeof(sin6)), NULL);
+       T_ASSERT_POSIX_SUCCESS(listen(s, 32), NULL);
+       T_ASSERT_POSIX_SUCCESS(fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK), NULL);
+       T_SETUPEND;
+
+       for (n = 0; n < 16; ++n) {
+               if (pthread_create(&threads[nthreads++], NULL, setopt_thread, &s)) {
+                       T_ASSERT_FAIL("pthread_create failed");
+               }
+       }
+
+       for (n = 0; n < 4; ++n) {
+               if (pthread_create(&threads[nthreads++], NULL, connect_thread, &sin6)) {
+                       T_ASSERT_FAIL("pthread_create failed");
+               }
+       }
+
+       for (n = 0; n < 200000; ++n) {
+               addr_len = sizeof(addr);
+               close(accept(s, (struct sockaddr *)&addr, &addr_len));
+       }
+
+       finished = 1;
+
+       for (n = 0; n < nthreads; ++n) {
+               pthread_join(threads[n], NULL);
+       }
+}
index 1e55dc2198db5170479186f776fe9be146584fdb..19fd2879945b7d6fc976acf1c9f3ff6c709b4fe4 100755 (executable)
@@ -1,7 +1,9 @@
 from xnu import *
 from utils import *
 from kdp import *
+from core import caching
 import sys
+from collections import deque
 
 ######################################
 # Globals
@@ -511,6 +513,117 @@ def ShowIOServicePM(cmd_args=None):
     
     print out_string
 
+
+@lldb_command("showinterruptvectors")
+def ShowInterruptVectorInfo(cmd_args=None):
+    """
+    Shows interrupt vectors.
+    """
+
+    # Constants
+    kInterruptTriggerModeMask  = 0x01
+    kInterruptTriggerModeEdge  = 0x00
+    kInterruptTriggerModeLevel = kInterruptTriggerModeMask
+    kInterruptPolarityMask     = 0x02
+    kInterruptPolarityHigh     = 0x00
+    kInterruptPolarityLow      = kInterruptPolarityMask
+    kInterruptShareableMask    = 0x04
+    kInterruptNotShareable     = 0x00
+    kInterruptIsShareable      = kInterruptShareableMask
+    kIOInterruptTypePCIMessaged = 0x00010000
+
+    # Get all interrupt controllers
+    interrupt_controllers = list(SearchInterruptControllerDrivers())
+
+    print("Interrupt controllers: ")
+    for ic in interrupt_controllers:
+        print("  {}".format(ic))
+    print("")
+
+    # Iterate over all entries in the registry
+    for entry in GetMatchingEntries(lambda _: True):
+        # Get the name of the entry
+        entry_name = GetRegistryEntryName(entry)
+
+        # Get the location of the entry
+        entry_location = GetRegistryEntryLocationInPlane(entry, kern.globals.gIOServicePlane)
+        if entry_location is None:
+            entry_location = ""
+        else:
+            entry_location = "@" + entry_location
+
+        # Get the interrupt properties
+        (msi_mode, vectorDataList, vectorContList) = GetRegistryEntryInterruptProperties(entry)
+        should_print = False
+        out_str = ""
+        for (vector_data, vector_cont) in zip(vectorDataList, vectorContList):
+            # vector_cont is the name of the interrupt controller. Find the matching controller from
+            # the list of controllers obtained earlier
+            matching_ics = filter(lambda ic: ic.name == vector_cont, interrupt_controllers)
+
+            if len(matching_ics) > 0:
+                should_print = True
+                # Take the first match
+                matchingIC = matching_ics[0]
+
+                # Use the vector_data to determine the vector and any flags
+                data_ptr = vector_data.data
+                data_length = vector_data.length
+
+                # Dereference vector_data as a uint32_t * and add the base vector number
+                gsi = unsigned(dereference(Cast(data_ptr, 'uint32_t *')))
+                gsi += matchingIC.base_vector_number
+
+                # If data_length is >= 8 then vector_data contains interrupt flags
+                if data_length >= 8:
+                    # Add sizeof(uint32_t) to data_ptr to get the flags pointer
+                    flags_ptr = kern.GetValueFromAddress(unsigned(data_ptr) + sizeof("uint32_t"))
+                    flags = unsigned(dereference(Cast(flags_ptr, 'uint32_t *')))
+                    out_str += "  +----- [Interrupt Controller {ic}] vector {gsi}, {trigger_level}, {active}, {shareable}{messaged}\n" \
+                            .format(ic=matchingIC.name, gsi=hex(gsi), 
+                                    trigger_level="level trigger" if flags & kInterruptTriggerModeLevel else "edge trigger",
+                                    active="active low" if flags & kInterruptPolarityLow else "active high",
+                                    shareable="shareable" if flags & kInterruptIsShareable else "exclusive",
+                                    messaged=", messaged" if flags & kIOInterruptTypePCIMessaged else "")
+                else:
+                    out_str += "  +----- [Interrupt Controller {ic}] vector {gsi}\n".format(ic=matchingIC.name, gsi=hex(gsi))
+        if should_print:
+            print("[ {entry_name}{entry_location} ]{msi_mode}\n{out_str}" \
+                .format(entry_name=entry_name,
+                        entry_location=entry_location,
+                        msi_mode=" - MSIs enabled" if msi_mode else "",
+                        out_str=out_str))
+
+@lldb_command("showiokitclasshierarchy")
+def ShowIOKitClassHierarchy(cmd_args=None):
+    """
+    Show class hierarchy for a IOKit class
+    """
+    if not cmd_args:
+        print("Usage: showiokitclasshierarchy <IOKit class name>")
+        return
+
+    class_name = cmd_args[0]
+    metaclasses = GetMetaClasses()
+    if class_name not in metaclasses:
+        print("Class {} does not exist".format(class_name))
+        return
+    metaclass = metaclasses[class_name]
+
+    # loop over superclasses
+    hierarchy = []
+    current_metaclass = metaclass
+    while current_metaclass is not None:
+        hierarchy.insert(0, current_metaclass)
+        current_metaclass = current_metaclass.superclass()
+
+    for (index, mc) in enumerate(hierarchy):
+        indent = ("    " * index) + "+---"
+        print("{}[ {} ] {}".format(indent, str(mc.className()), str(mc.data())))
+
+
+
+
 ######################################
 #  Helper routines
 ######################################
@@ -636,6 +749,478 @@ def FindRegistryObjectRecurse(entry, search_name):
                 return registry_object
     return None
 
+
+class IOKitMetaClass(object):
+    """
+    A class that represents a IOKit metaclass. This is used to represent the
+    IOKit inheritance hierarchy.
+    """
+
+    def __init__(self, meta):
+        """
+        Initialize a IOKitMetaClass object.
+
+        Args:
+            meta (core.cvalue.value): A LLDB value representing a
+                OSMetaClass *.
+        """
+        self._meta = meta
+        self._superclass = None
+
+    def data(self):
+        return self._meta
+
+    def setSuperclass(self, superclass):
+        """
+        Set the superclass for this metaclass.
+
+        Args:
+            superclass (core.cvalue.value): A LLDB value representing a
+                OSMetaClass *.
+        """
+        self._superclass = superclass
+
+    def superclass(self):
+        """
+        Get the superclass for this metaclass (set by the setSuperclass method).
+
+        Returns:
+            core.cvalue.value: A LLDB value representing a OSMetaClass *.
+        """
+        return self._superclass
+
+    def className(self):
+        """
+        Get the name of the class this metaclass represents.
+
+        Returns:
+            str: The class name
+        """
+        return self._meta.className.string
+
+    def inheritsFrom(self, other):
+        """
+        Check if the class represented by this metaclass inherits from a class
+        represented by another metaclass.
+
+        Args:
+            other (IOKitMetaClass): The other metaclass
+
+        Returns:
+            bool: Returns True if this class inherits from the other class and
+                False otherwise.
+        """
+        current = self
+        while current is not None:
+            if current == other:
+                return True
+            else:
+                current = current.superclass()
+
+
+def GetRegistryEntryClassName(entry):
+    """
+    Get the class name of a registry entry.
+
+    Args:
+        entry (core.cvalue.value): A LLDB value representing a
+            IORegistryEntry *.
+
+    Returns:
+        str: The class name of the entry or None if a class name could not be
+            found.
+    """
+    # Check using IOClass key
+    result = LookupKeyInOSDict(entry.fPropertyTable, kern.globals.gIOClassKey)
+    if result is not None:
+        return GetString(result).replace("\"", "")
+    else:
+        # Use the vtable of the entry to determine the concrete type
+        vt = dereference(Cast(entry, 'uintptr_t *')) - 2 * sizeof('uintptr_t')
+        vt = kern.StripKernelPAC(vt)
+        vtype = kern.SymbolicateFromAddress(vt)
+        if len(vtype) > 0:
+            vtableName = vtype[0].GetName()
+            return vtableName[11:] # strip off "vtable for "
+        else:
+            return None
+
+
+def GetRegistryEntryName(entry):
+    """
+    Get the name of a registry entry.
+
+    Args:
+        entry (core.cvalue.value): A LLDB value representing a
+            IORegistryEntry *.
+
+    Returns:
+        str: The name of the entry or None if a name could not be found.
+    """
+    name = None
+
+    # First check the IOService plane nameKey
+    result = LookupKeyInOSDict(entry.fRegistryTable, kern.globals.gIOServicePlane.nameKey)
+    if result is not None:
+        name = GetString(result)
+
+    # Check the global IOName key
+    if name is None:
+        result = LookupKeyInOSDict(entry.fRegistryTable, kern.globals.gIONameKey)
+        if result is not None:
+            name = GetString(result)
+
+    # Check the IOClass key
+    if name is None:
+        result = LookupKeyInOSDict(entry.fPropertyTable, kern.globals.gIOClassKey)
+        if result is not None:
+            name = GetString(result)
+
+    # Remove extra quotes        
+    if name is not None:
+        return name.replace("\"", "")
+    else:
+        return GetRegistryEntryClassName(entry)
+
+
+def GetRegistryEntryLocationInPlane(entry, plane):
+    """
+    Get the registry entry location in a IOKit plane.
+
+    Args:
+        entry (core.cvalue.value): A LLDB value representing a
+            IORegistryEntry *.
+        plane: An IOKit plane such as kern.globals.gIOServicePlane.
+
+    Returns:
+        str: The location of the entry or None if a location could not be
+            found.
+    """
+    # Check the plane's pathLocationKey
+    sym = LookupKeyInOSDict(entry.fRegistryTable, plane.pathLocationKey)
+
+    # Check the global IOLocation key
+    if sym is None:
+        sym = LookupKeyInOSDict(entry.fRegistryTable, kern.globals.gIOLocationKey)
+    if sym is not None:
+        return GetString(sym).replace("\"", "")
+    else:
+        return None
+
+
+def GetMetaClasses():
+    """
+    Enumerate all IOKit metaclasses. Uses dynamic caching.
+
+    Returns:
+        Dict[str, IOKitMetaClass]: A dictionary mapping each metaclass name to
+            a IOKitMetaClass object representing the metaclass.
+    """
+    METACLASS_CACHE_KEY = "iokit_metaclasses"
+    cached_data = caching.GetDynamicCacheData(METACLASS_CACHE_KEY)
+
+    # If we have cached data, return immediately
+    if cached_data is not None:
+        return cached_data
+
+    # This method takes a while, so it prints a progress indicator
+    print("Enumerating IOKit metaclasses: ")
+    
+    # Iterate over all classes present in sAllClassesDict
+    idx = 0
+    count = unsigned(kern.globals.sAllClassesDict.count)
+    metaclasses_by_address = {}
+    while idx < count:
+        # Print progress after every 10 items
+        if idx % 10 == 0:
+            print("  {} metaclass structures parsed...".format(idx))
+        
+        # Address of metaclass
+        address = kern.globals.sAllClassesDict.dictionary[idx].value
+
+        # Create IOKitMetaClass and store in dict
+        metaclasses_by_address[int(address)] = IOKitMetaClass(CastIOKitClass(kern.globals.sAllClassesDict.dictionary[idx].value, 'OSMetaClass *'))
+        idx += 1
+    
+    print("  Enumerated {} metaclasses.".format(count))
+
+    # At this point, each metaclass is independent of each other. We don't have superclass links set up yet.
+
+    for (address, metaclass) in metaclasses_by_address.items():
+        # Get the address of the superclass using the superClassLink in IOMetaClass
+        superclass_address = int(metaclass.data().superClassLink)
+
+        # Skip null superclass
+        if superclass_address == 0:
+            continue
+
+        # Find the superclass object in the dict
+        if superclass_address in metaclasses_by_address:
+            metaclass.setSuperclass(metaclasses_by_address[superclass_address])
+        else:
+            print("warning: could not find superclass for {}".format(str(metaclass.data())))
+    
+    # This method returns a dictionary mapping each class name to the associated metaclass object
+    metaclasses_by_name = {}
+    for (_, metaclass) in metaclasses_by_address.items():
+        metaclasses_by_name[str(metaclass.className())] = metaclass
+
+    # Save the result in the cache
+    caching.SaveDynamicCacheData(METACLASS_CACHE_KEY, metaclasses_by_name)
+
+    return metaclasses_by_name
+
+
+def GetMatchingEntries(matcher):
+    """
+    Iterate over the IOKit registry and find entries that match specific
+        criteria.
+
+    Args:
+        matcher (function): A matching function that returns True for a match
+            and False otherwise.
+
+    Yields:
+        core.cvalue.value: LLDB values that represent IORegistryEntry * for
+            each registry entry found.
+    """
+
+    # Perform a BFS over the IOKit registry tree
+    bfs_queue = deque()
+    bfs_queue.append(kern.globals.gRegistryRoot)
+    while len(bfs_queue) > 0:
+        # Dequeue an entry
+        entry = bfs_queue.popleft()
+
+        # Check if entry matches
+        if matcher(entry):
+            yield entry
+
+        # Find children of this entry and enqueue them
+        child_array = LookupKeyInOSDict(entry.fRegistryTable, kern.globals.gIOServicePlane.keys[1])
+        if child_array is not None:
+            idx = 0
+            ca = CastIOKitClass(child_array, 'OSArray *')
+            count = unsigned(ca.count)
+            while idx < count:
+                bfs_queue.append(CastIOKitClass(ca.array[idx], 'IORegistryEntry *'))
+                idx += 1
+
+
+def FindMatchingServices(matching_name):
+    """
+    Finds registry entries that match the given string. Works similarly to:
+
+    io_iterator_t iter;
+    IOServiceGetMatchingServices(..., IOServiceMatching(matching_name), &iter);
+    while (( io_object_t next = IOIteratorNext(iter))) { ... }
+
+    Args:
+        matching_name (str): The class name to search for.
+
+    Yields:
+        core.cvalue.value: LLDB values that represent IORegistryEntry * for
+            each registry entry found.
+    """
+
+    # Check if the argument is valid
+    metaclasses = GetMetaClasses()
+    if matching_name not in metaclasses:
+        return
+    matching_metaclass = metaclasses[matching_name]
+
+    # An entry matches if it inherits from matching_metaclass
+    def matcher(entry):
+        # Get the class name of the entry and the associated metaclass
+        entry_name = GetRegistryEntryClassName(entry)
+        if entry_name in metaclasses:
+            entry_metaclass = metaclasses[entry_name]
+            return entry_metaclass.inheritsFrom(matching_metaclass)
+        else:
+            return False
+    
+    # Search for entries
+    for entry in GetMatchingEntries(matcher):
+        yield entry
+
+
+def GetRegistryEntryParent(entry, iokit_plane=None):
+    """
+    Gets the parent entry of a registry entry.
+
+    Args:
+        entry (core.cvalue.value): A LLDB value representing a
+            IORegistryEntry *.
+        iokit_plane (core.cvalue.value, optional): A LLDB value representing a
+            IORegistryPlane *. By default, this method uses the IOService
+            plane.
+
+    Returns:
+        core.cvalue.value: A LLDB value representing a IORegistryEntry* that
+            is the parent entry of the entry argument in the specified plane.
+            Returns None if no entry could be found.
+    """
+    kParentSetIndex = 0
+    parent_key = None
+    if iokit_plane is None:
+        parent_key = kern.globals.gIOServicePlane.keys[kParentSetIndex]
+    else:
+        parent_key = plane.keys[kParentSetIndex]
+    parent_array = LookupKeyInOSDict(entry.fRegistryTable, parent_key)
+    parent_entry = None
+    if parent_array is not None:
+        idx = 0
+        ca = CastIOKitClass(parent_array, 'OSArray *')
+        count = unsigned(ca.count)
+        if count > 0:
+            parent_entry = CastIOKitClass(ca.array[0], 'IORegistryEntry *')
+    return parent_entry
+
+
+def GetRegistryEntryInterruptProperties(entry):
+    """
+    Get the interrupt properties of a registry entry.
+
+    Args:
+        entry (core.cvalue.value): A LLDB value representing a IORegistryEntry *.
+
+    Returns:
+        (bool, List[core.cvalue.value], List[str]): A tuple with the following
+            fields:
+                - First field (bool): Whether this entry has a non-null
+                    IOPCIMSIMode.
+                - Second field (List[core.cvalue.value]): A list of LLDB values
+                    representing OSData *. The OSData* pointer points to
+                    interrupt vector data.
+                - Third field (List[str]): A list of strings representing the
+                    interrupt controller names from the
+                    IOInterruptControllers property.
+    """
+    INTERRUPT_SPECIFIERS_PROPERTY = "IOInterruptSpecifiers"
+    INTERRUPT_CONTROLLERS_PROPERTY = "IOInterruptControllers"
+    MSI_MODE_PROPERTY = "IOPCIMSIMode"
+
+    # Check IOInterruptSpecifiers
+    interrupt_specifiers = LookupKeyInPropTable(entry.fPropertyTable, INTERRUPT_SPECIFIERS_PROPERTY)
+    if interrupt_specifiers is not None:
+        interrupt_specifiers = CastIOKitClass(interrupt_specifiers, 'OSArray *')
+    
+    # Check IOInterruptControllers
+    interrupt_controllers = LookupKeyInPropTable(entry.fPropertyTable, INTERRUPT_CONTROLLERS_PROPERTY)
+    if interrupt_controllers is not None:
+        interrupt_controllers = CastIOKitClass(interrupt_controllers, 'OSArray *')
+
+    # Check MSI mode
+    msi_mode = LookupKeyInPropTable(entry.fPropertyTable, MSI_MODE_PROPERTY)
+
+    result_vector_data = []
+    result_vector_cont = []
+    if interrupt_specifiers is not None and interrupt_controllers is not None:
+        interrupt_specifiers_array_count = unsigned(interrupt_specifiers.count)
+        interrupt_controllers_array_count = unsigned(interrupt_controllers.count)
+        # The array lengths should be the same
+        if interrupt_specifiers_array_count == interrupt_controllers_array_count and interrupt_specifiers_array_count > 0:
+            idx = 0
+            while idx < interrupt_specifiers_array_count:
+                # IOInterruptSpecifiers is an array of OSData *
+                vector_data = CastIOKitClass(interrupt_specifiers.array[idx], "OSData *")
+
+                # IOInterruptControllers is an array of OSString *
+                vector_cont = GetString(interrupt_controllers.array[idx])
+
+                result_vector_data.append(vector_data)
+                result_vector_cont.append(vector_cont)
+                idx += 1
+    
+    return (msi_mode is not None, result_vector_data, result_vector_cont)
+
+
+class InterruptControllerDevice(object):
+    """Represents a IOInterruptController"""
+
+    def __init__(self, device, driver, base_vector_number, name):
+        """
+        Initialize a InterruptControllerDevice.
+
+        Args:
+            device (core.cvalue.value): The device object.
+            driver (core.cvalue.value): The driver object.
+            base_vector_number (int): The base interrupt vector.
+            name (str): The name of this interrupt controller.
+
+        Note:
+            Use the factory method makeInterruptControllerDevice to validate
+            properties.
+        """
+        self.device = device
+        self.driver = driver
+        self.name = name
+        self.base_vector_number = base_vector_number
+
+
+    def __str__(self):
+        """
+        String representation of this InterruptControllerDevice.
+        """
+        return " Name {}, base vector = {}, device = {}, driver = {}".format(
+            self.name, hex(self.base_vector_number), str(self.device), str(self.driver))
+
+    @staticmethod
+    def makeInterruptControllerDevice(device, driver):
+        """
+        Factory method to create a InterruptControllerDevice.
+
+        Args:
+            device (core.cvalue.value): The device object.
+            driver (core.cvalue.value): The driver object.
+
+        Returns:
+            InterruptControllerDevice: Returns an instance of
+                InterruptControllerDevice or None if the arguments do not have
+                the required properties.
+        """
+        BASE_VECTOR_PROPERTY = "Base Vector Number"
+        INTERRUPT_CONTROLLER_NAME_PROPERTY = "InterruptControllerName"
+        base_vector = LookupKeyInPropTable(device.fPropertyTable, BASE_VECTOR_PROPERTY)
+        if base_vector is None:
+            base_vector = LookupKeyInPropTable(driver.fPropertyTable, BASE_VECTOR_PROPERTY)
+        device_name = LookupKeyInPropTable(device.fPropertyTable, INTERRUPT_CONTROLLER_NAME_PROPERTY)
+        if device_name is None:
+            device_name = LookupKeyInPropTable(driver.fPropertyTable, INTERRUPT_CONTROLLER_NAME_PROPERTY)
+
+        if device_name is not None:
+            # Some interrupt controllers do not have a base vector number. Assume it is 0.
+            base_vector_number = 0
+            if base_vector is not None:
+                base_vector_number = unsigned(GetNumber(base_vector))
+            device_name = GetString(device_name)
+            # Construct object and return
+            return InterruptControllerDevice(device, driver, base_vector_number, device_name)
+        else:
+            # error case
+            return None
+
+
+def SearchInterruptControllerDrivers():
+    """
+    Search the IOKit registry for entries that match IOInterruptController.
+
+    Yields:
+        core.cvalue.value: A LLDB value representing a IORegistryEntry * that
+        inherits from IOInterruptController.
+    """
+    for entry in FindMatchingServices("IOInterruptController"):
+        # Get parent
+        parent = GetRegistryEntryParent(entry)
+
+        # Make the interrupt controller object
+        ic = InterruptControllerDevice.makeInterruptControllerDevice(parent, entry)
+
+        # Yield object
+        if ic is not None:
+            yield ic
+
+
 def LookupKeyInOSDict(osdict, key):
     """ Returns the value corresponding to a given key in a OSDictionary
         Returns None if the key was not found
index 473e06a8cc2f2d9a0d9168482d266ab85b3c7460..6e58e3209985e6106a61d1455c9696031038de67 100755 (executable)
@@ -948,7 +948,7 @@ def WalkQueueHead(cmd_args=[], cmd_options={}):
 
 
 
-@lldb_command('walklist_entry', 'S')
+@lldb_command('walklist_entry', 'SE')
 def WalkList(cmd_args=[], cmd_options={}):
     """ iterate over a list as defined with LIST_ENTRY in bsd/sys/queue.h
         params:
@@ -956,7 +956,9 @@ def WalkList(cmd_args=[], cmd_options={}):
             element_type - str   : Type of the next element
             field_name   - str   : Name of the field in next element's structure
 
-        Option: -S - suppress summary output.
+        Options: -S - suppress summary output.
+                 -E - Iterate using SLIST_ENTRYs
+
         Usage: (lldb) walklist_entry  <obj with list_entry *> <struct type> <fieldname>
         ex:    (lldb) walklist_entry  0x7fffff80 "struct proc *" "p_sibling"
 
@@ -969,16 +971,19 @@ def WalkList(cmd_args=[], cmd_options={}):
     el_type = cmd_args[1]
     queue_head = kern.GetValueFromAddress(cmd_args[0], el_type)
     field_name = cmd_args[2]
-
     showsummary = False
     if el_type in lldb_summary_definitions:
         showsummary = True
     if '-S' in cmd_options:
         showsummary = False
+    if '-E' in cmd_options:
+        prefix = 's'
+    else:
+        prefix = ''
     elt = queue_head
     while unsigned(elt) != 0:
         i = elt
-        elt = elt.__getattr__(field_name).le_next
+        elt = elt.__getattr__(field_name).__getattr__(prefix + 'le_next')
         if showsummary:
             print lldb_summary_definitions[el_type](i)
         else:
@@ -1159,6 +1164,42 @@ def TrapTrace_cmd(cmd_args=[], cmd_options={}):
         kern.globals.traptrace_entries_per_cpu, MAX_TRAPTRACE_BACKTRACES)
                 
 
+@lldb_command('showsysctls', 'P:')
+def ShowSysctls(cmd_args=[], cmd_options={}):
+    """ Walks the list of sysctl data structures, printing out each during traversal.
+        Arguments:
+          -P <string> : Limit output to sysctls starting with the specified prefix.
+    """
+    if '-P' in cmd_options:
+        _ShowSysctl_prefix = cmd_options['-P']
+        allowed_prefixes = _ShowSysctl_prefix.split('.')
+        if allowed_prefixes:
+            for x in xrange(1, len(allowed_prefixes)):
+                allowed_prefixes[x] = allowed_prefixes[x - 1] + "." + allowed_prefixes[x]
+    else:
+        _ShowSysctl_prefix = ''
+        allowed_prefixes = []
+    def IterateSysctls(oid, parent_str, i):
+        headp = oid
+        parentstr = "<none>" if parent_str is None else parent_str
+        for pp in IterateListEntry(headp, 'struct sysctl_oid *', 'oid_link', 's'):
+            type = pp.oid_kind & 0xf
+            next_parent = str(pp.oid_name)
+            if parent_str is not None:
+                next_parent = parent_str + "." + next_parent
+            st = (" " * i) + str(pp.GetSBValue().Dereference()).replace("\n", "\n" + (" " * i))
+            if type == 1 and pp.oid_arg1 != 0:
+                # Check allowed_prefixes to see if we can recurse from root to the allowed prefix.
+                # To recurse further, we need to check only the the next parent starts with the user-specified
+                # prefix
+                if next_parent not in allowed_prefixes and next_parent.startswith(_ShowSysctl_prefix) is False:
+                    continue
+                print 'parent = "%s"' % parentstr, st[st.find("{"):]
+                IterateSysctls(Cast(pp.oid_arg1, "struct sysctl_oid_list *"), next_parent, i + 2)
+            elif _ShowSysctl_prefix == '' or next_parent.startswith(_ShowSysctl_prefix):
+                print ('parent = "%s"' % parentstr), st[st.find("{"):]
+    IterateSysctls(kern.globals.sysctl__children, None, 0)
+
 
 
 from memory import *
index 0783ebea0ff87d094d93b73974c9b0e80157dc09..fbe1bb0c3db30e0fa0f9a3d609313839a19412fc 100755 (executable)
@@ -66,7 +66,10 @@ def NewBt(cmd_args=None):
         if len(cmd_out) != 0:
             cmd_out1 = cmd_out.split('\n')
             if len(cmd_out1) != 0:
-                print OutputAddress([unsigned(link_register)]) + ": " + cmd_out1[0].split(':')[1]
+                address = OutputAddress([unsigned(link_register)])
+                if address is None:
+                    address = '0x%x <???>' % unsigned(link_register)
+                print address + ": " + cmd_out1[1].split(':', 1)[1]
         a = dereference(kern.GetValueFromAddress(unsigned(a), 'uintptr_t *'))
 
 # EndMacro: newbt