bsd/libkern/strsep.c standard
bsd/libkern/bcd.c standard
bsd/libkern/memchr.c standard
+bsd/libkern/url_encode.c standard
bsd/vfs/vfs_attrlist.c standard
bsd/vfs/vfs_bio.c standard
#endif
if (auth_root) {
- const char *path = root_path;
+ /* Copy the path to use locally */
+ char *path_alloc = kalloc(MAXPATHLEN);
+ if (path_alloc == NULL) {
+ panic("imageboot path allocation failed\n");
+ }
+
+ char *path = path_alloc;
+ strlcpy(path, root_path, MAXPATHLEN);
+
size_t len = strlen(kIBFilePrefix);
if (strncmp(kIBFilePrefix, path, len) == 0) {
- /* remove the file:// prefix */
+ /* its a URL - remove the file:// prefix and percent-decode */
path += len;
+ url_decode(path);
}
AUTHDBG("authenticating root image at %s", path);
panic("root image authentication failed (err = %d)\n", error);
}
AUTHDBG("successfully authenticated %s", path);
+
+ kfree_safe(path_alloc);
}
error = imageboot_mount_image(root_path, height);
if ( (error = vnode_getwithref(vp)) == 0 ) {
#define STK_PARAMS 128
- char stkbuf[STK_PARAMS];
+ char stkbuf[STK_PARAMS] = {0};
unsigned int size;
caddr_t data, memp;
/*
*/
int ktrace_root_set_owner_allowed = 0;
-void
-ktrace_reset(uint32_t reset_mask)
+static void
+ktrace_reset_internal(uint32_t reset_mask)
{
- lck_mtx_assert(ktrace_lock, LCK_MTX_ASSERT_OWNED);
- assert(reset_mask != 0);
-
- if (ktrace_active_mask == 0) {
- if (!ktrace_keep_ownership_on_reset) {
- assert(ktrace_state == KTRACE_STATE_OFF);
- }
- return;
- }
-
if (!ktrace_keep_ownership_on_reset) {
ktrace_active_mask &= ~reset_mask;
}
}
}
+void
+ktrace_reset(uint32_t reset_mask)
+{
+ lck_mtx_assert(ktrace_lock, LCK_MTX_ASSERT_OWNED);
+
+ if (ktrace_active_mask == 0) {
+ if (!ktrace_keep_ownership_on_reset) {
+ assert(ktrace_state == KTRACE_STATE_OFF);
+ }
+ return;
+ }
+
+ ktrace_reset_internal(reset_mask);
+}
+
static void
ktrace_promote_background(void)
{
{
if (ktrace_keep_ownership_on_reset) {
ktrace_keep_ownership_on_reset = FALSE;
- ktrace_reset(ktrace_active_mask);
+ ktrace_reset_internal(ktrace_active_mask);
}
}
unsigned int memorystatus_suspended_count = 0;
unsigned int memorystatus_policy_more_free_offset_pages = 0;
+#if CONFIG_JETSAM
+#if DEVELOPMENT || DEBUG
+SYSCTL_UINT(_kern, OID_AUTO, memorystatus_available_pages, CTLFLAG_RD | CTLFLAG_LOCKED, &memorystatus_available_pages, 0, "");
+#else
+SYSCTL_UINT(_kern, OID_AUTO, memorystatus_available_pages, CTLFLAG_RD| CTLFLAG_MASKED | CTLFLAG_LOCKED, &memorystatus_available_pages, 0, "");
+#endif /* DEVELOPMENT || DEBUG */
+#endif /* CONFIG_JETSAM */
+
/*
* We use this flag to signal if we have any HWM offenders
* on the system. This way we can reduce the number of wakeups
SYSCTL_INT(_kern, OID_AUTO, memorystatus_idle_snapshot, CTLFLAG_RW|CTLFLAG_LOCKED, &memorystatus_idle_snapshot, 0, "");
-SYSCTL_UINT(_kern, OID_AUTO, memorystatus_available_pages, CTLFLAG_RD|CTLFLAG_LOCKED, &memorystatus_available_pages, 0, "");
SYSCTL_UINT(_kern, OID_AUTO, memorystatus_available_pages_critical, CTLFLAG_RD|CTLFLAG_LOCKED, &memorystatus_available_pages_critical, 0, "");
SYSCTL_UINT(_kern, OID_AUTO, memorystatus_available_pages_critical_base, CTLFLAG_RW|CTLFLAG_LOCKED, &memorystatus_available_pages_critical_base, 0, "");
SYSCTL_UINT(_kern, OID_AUTO, memorystatus_available_pages_critical_idle_offset, CTLFLAG_RW|CTLFLAG_LOCKED, &memorystatus_available_pages_critical_idle_offset, 0, "");
bzero(ref, sizeof(*ref));
p = kernproc;
- ref->ctx = vfs_context_create(vfs_context_kernel());
+ ref->ctx = vfs_context_kernel();
fmode = (create_file) ? (O_CREAT | FWRITE) : FWRITE;
cmode = S_IRUSR | S_IWUSR;
VATTR_SET(&va, va_mode, cmode);
VATTR_SET(&va, va_dataprotect_flags, VA_DP_RAWENCRYPTED);
VATTR_SET(&va, va_dataprotect_class, PROTECTION_CLASS_D);
- if ((error = vn_open_auth(&nd, &fmode, &va))) goto out;
+ if ((error = vn_open_auth(&nd, &fmode, &va))) {
+ kprintf("vn_open_auth(fmode: %d, cmode: %d) failed with error: %d\n", fmode, cmode, error);
+ goto out;
+ }
ref->vp = nd.ni_vp;
if (ref->vp->v_type == VREG)
if (write_file_addr && write_file_len)
{
- if ((error = kern_write_file(ref, write_file_offset, write_file_addr, write_file_len, 0))) goto out;
+ if ((error = kern_write_file(ref, write_file_offset, write_file_addr, write_file_len, IO_SKIP_ENCRYPTION))) {
+ kprintf("kern_write_file() failed with error: %d\n", error);
+ goto out;
+ }
}
VATTR_INIT(&va);
{
vnode_close(ref->vp, FWRITE, ref->ctx);
ref->vp = NULLVP;
- vfs_context_rele(ref->ctx);
ref->ctx = NULL;
}
out:
printf("kern_open_file_for_direct_io(%p, %d)\n", ref, error);
+
if (error && locked)
{
p1 = &device;
vnode_close(ref->vp, FWRITE, ref->ctx);
ref->vp = NULLVP;
}
- vfs_context_rele(ref->ctx);
+ ref->ctx = NULL;
kfree(ref, sizeof(struct kern_direct_file_io_ref_t));
ref = NULL;
}
if (addr && write_length)
{
- (void) kern_write_file(ref, write_offset, addr, write_length, 0);
+ (void) kern_write_file(ref, write_offset, addr, write_length, IO_SKIP_ENCRYPTION);
}
error = vnode_close(ref->vp, FWRITE, ref->ctx);
ref->vp = NULLVP;
kprintf("vnode_close(%d)\n", error);
+
}
- if (ref->ctx)
- {
- vfs_context_rele(ref->ctx);
- ref->ctx = NULL;
- }
+
+ ref->ctx = NULL;
+
kfree(ref, sizeof(struct kern_direct_file_io_ref_t));
}
struct fileglob **rp = (struct fileglob **)(cm + 1);
int *fds = (int *)(cm + 1);
struct fileproc *fp;
- struct fileglob **fgl;
+ struct fileproc **fileproc_l;
int newfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int);
int f, error = 0;
- MALLOC(fgl, struct fileglob **, newfds * sizeof (struct fileglob *),
- M_TEMP, M_WAITOK);
- if (fgl == NULL) {
+ MALLOC(fileproc_l, struct fileproc **,
+ newfds * sizeof (struct fileproc *), M_TEMP, M_WAITOK);
+ if (fileproc_l == NULL) {
error = ENOMEM;
goto discard;
}
panic("unp_externalize: MALLOC_ZONE");
fp->f_iocount = 0;
fp->f_fglob = rp[i];
- if (fg_removeuipc_mark(rp[i]))
- fgl[i] = rp[i];
- else
- fgl[i] = NULL;
+ if (fg_removeuipc_mark(rp[i])) {
+
+ /*
+ * Take an iocount on the fp for completing the
+ * removal from the global msg queue
+ */
+ fp->f_iocount++;
+ fileproc_l[i] = fp;
+ } else {
+ fileproc_l[i] = NULL;
+ }
procfdtbl_releasefd(p, f, fp);
fds[i] = f;
}
proc_fdunlock(p);
for (i = 0; i < newfds; i++) {
- if (fgl[i] != NULL) {
- VERIFY(fgl[i]->fg_lflags & FG_RMMSGQ);
- fg_removeuipc(fgl[i]);
+ if (fileproc_l[i] != NULL) {
+ VERIFY(fileproc_l[i]->f_fglob != NULL &&
+ (fileproc_l[i]->f_fglob->fg_lflags & FG_RMMSGQ));
+ VERIFY(fds[i] > 0);
+ fg_removeuipc(fileproc_l[i]->f_fglob);
+
+ /* Drop the iocount */
+ fp_drop(p, fds[i], fileproc_l[i], 0);
+ fileproc_l[i] = NULL;
}
- if (fds[i])
+ if (fds[i] != 0)
(void) OSAddAtomic(-1, &unp_rights);
}
discard:
- if (fgl)
- FREE(fgl, M_TEMP);
+ if (fileproc_l != NULL)
+ FREE(fileproc_l, M_TEMP);
if (error) {
for (i = 0; i < newfds; i++) {
unp_discard(*rp, p);
extern u_quad_t strtouq(const char *, char **, int);
extern char *strsep(char **, const char *);
extern void *memchr(const void *, int, size_t);
+extern void url_decode(char *str);
int snprintf(char *, size_t, const char *, ...) __printflike(3,4);
--- /dev/null
+/*
+ * Copyright (c) 2016 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 <libkern/libkern.h>
+
+static int
+hex2int(int c)
+{
+ if (c >= '0' && c <= '9') {
+ return c - '0';
+ } else if (c >= 'A' && c <= 'F') {
+ return c - 'A' + 10;
+ } else if (c >= 'a' && c <= 'f') {
+ return c - 'a' + 10;
+ }
+ return 0;
+}
+
+static bool
+isprint(int ch)
+{
+ return ch >= 0x20 && ch <= 0x7e;
+}
+
+/*
+ * In-place decode of URL percent-encoded str
+ */
+void
+url_decode(char *str)
+{
+ if (!str) {
+ return;
+ }
+
+ while (*str) {
+ if (*str == '%') {
+ char c = 0;
+ char *esc = str++; /* remember the start of the escape sequence */
+
+ if (*str) {
+ c += hex2int(*str++);
+ }
+ if (*str) {
+ c = (c << 4) + hex2int(*str++);
+ }
+
+ if (isprint(c)) {
+ /* overwrite the '%' with the new char, and bump the rest of the
+ * string down a few characters */
+ *esc++ = c;
+ str = memmove(esc, str, strlen(str)+1);
+ } else {
+ str++;
+ }
+
+ } else {
+ str++;
+ }
+ }
+}
/*
- * Copyright (c) 2014, 2016 Apple Inc. All rights reserved.
+ * Copyright (c) 2014, 2016, 2017 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
data_size = register_netagent->netagent_data_size;
if (data_size < 0 || data_size > NETAGENT_MAX_DATA_SIZE) {
- NETAGENTLOG(LOG_ERR, "Register message size could not be read, data_size %d",
- data_size);
+ NETAGENTLOG(LOG_ERR, "Register message size could not be read, data_size %d", data_size);
response_error = EINVAL;
goto done;
}
+ if (payload_length != (sizeof(struct netagent) + data_size)) {
+ NETAGENTLOG(LOG_ERR, "Mismatch between data size and payload length (%u != %u)", (sizeof(struct netagent) + data_size), payload_length);
+ response_error = EINVAL;
+ goto done;
+ }
+
MALLOC(new_wrapper, struct netagent_wrapper *, sizeof(*new_wrapper) + data_size, M_NETAGENT, M_WAITOK);
if (new_wrapper == NULL) {
NETAGENTLOG0(LOG_ERR, "Failed to allocate agent");
goto done;
}
+ if (payload_length != (sizeof(struct netagent) + data_size)) {
+ NETAGENTLOG(LOG_ERR, "Mismatch between data size and payload length (%u != %u)", (sizeof(struct netagent) + data_size), payload_length);
+ response_error = EINVAL;
+ goto done;
+ }
+
MALLOC(new_wrapper, struct netagent_wrapper *, sizeof(*new_wrapper) + data_size, M_NETAGENT, M_WAITOK);
if (new_wrapper == NULL) {
NETAGENTLOG0(LOG_ERR, "Failed to allocate agent");
senderr(EINVAL);
ifscope = rtm->rtm_index;
}
+ /*
+ * Block changes on INTCOPROC interfaces.
+ */
+ if (ifscope) {
+ unsigned int intcoproc_scope = 0;
+ ifnet_head_lock_shared();
+ TAILQ_FOREACH(ifp, &ifnet_head, if_link) {
+ if (IFNET_IS_INTCOPROC(ifp)) {
+ intcoproc_scope = ifp->if_index;
+ break;
+ }
+ }
+ ifnet_head_done();
+ if (intcoproc_scope == ifscope && current_proc()->p_pid != 0)
+ senderr(EINVAL);
+ }
/*
* RTF_PROXY can only be set internally from within the kernel.
return (0);
}
+/*
+ * When the address is being configured we should clear out certain flags
+ * coming in from the caller.
+ */
+#define IN6_IFF_CLR_ADDR_FLAG_MASK (~(IN6_IFF_DEPRECATED | IN6_IFF_DETACHED | IN6_IFF_DUPLICATED))
+
static int
in6_ifaupdate_aux(struct in6_ifaddr *ia, struct ifnet *ifp, int ifaupflags)
{
ia->ia6_flags,
ifaupflags));
+ /*
+ * Just to be safe, always clear certain flags when address
+ * is being configured
+ */
+ ia->ia6_flags &= IN6_IFF_CLR_ADDR_FLAG_MASK;
+
/*
* Mark the address as tentative before joining multicast addresses,
* so that corresponding MLD responses would not have a tentative
* source address.
*/
- ia->ia6_flags &= ~IN6_IFF_DUPLICATED; /* safety */
- if (in6if_do_dad(ifp))
+ if (in6if_do_dad(ifp)) {
in6_ifaddr_set_dadprogress(ia);
-
- /*
- * Do not delay sending neighbor solicitations when using optimistic
- * duplicate address detection, c.f. RFC 4429.
- */
- if (ia->ia6_flags & IN6_IFF_OPTIMISTIC)
- ifaupflags &= ~IN6_IFAUPDATE_DADDELAY;
- else
- ifaupflags |= IN6_IFAUPDATE_DADDELAY;
+ /*
+ * Do not delay sending neighbor solicitations when using optimistic
+ * duplicate address detection, c.f. RFC 4429.
+ */
+ if (ia->ia6_flags & IN6_IFF_OPTIMISTIC)
+ ifaupflags &= ~IN6_IFAUPDATE_DADDELAY;
+ else
+ ifaupflags |= IN6_IFAUPDATE_DADDELAY;
+ } else {
+ /*
+ * If the interface has been marked to not perform
+ * DAD, make sure to reset DAD in progress flags
+ * that may come in from the caller.
+ */
+ ia->ia6_flags &= ~IN6_IFF_DADPROGRESS;
+ }
/* Join necessary multicast groups */
if ((ifp->if_flags & IFF_MULTICAST) != 0) {
if (optdad) {
if ((optdad & ND6_OPTIMISTIC_DAD_LINKLOCAL) &&
- IN6_IS_ADDR_LINKLOCAL(&ia->ia_addr.sin6_addr))
+ IN6_IS_ADDR_LINKLOCAL(&ia->ia_addr.sin6_addr))
flags = IN6_IFF_OPTIMISTIC;
else if ((optdad & ND6_OPTIMISTIC_DAD_AUTOCONF) &&
- (ia->ia6_flags & IN6_IFF_AUTOCONF)) {
+ (ia->ia6_flags & IN6_IFF_AUTOCONF)) {
if (ia->ia6_flags & IN6_IFF_TEMPORARY) {
if (optdad & ND6_OPTIMISTIC_DAD_TEMPORARY)
flags = IN6_IFF_OPTIMISTIC;
flags = IN6_IFF_OPTIMISTIC;
}
} else if ((optdad & ND6_OPTIMISTIC_DAD_DYNAMIC) &&
- (ia->ia6_flags & IN6_IFF_DYNAMIC)) {
+ (ia->ia6_flags & IN6_IFF_DYNAMIC)) {
if (ia->ia6_flags & IN6_IFF_TEMPORARY) {
if (optdad & ND6_OPTIMISTIC_DAD_TEMPORARY)
flags = IN6_IFF_OPTIMISTIC;
flags = IN6_IFF_OPTIMISTIC;
}
} else if ((optdad & ND6_OPTIMISTIC_DAD_MANUAL) &&
- (ia->ia6_flags & IN6_IFF_OPTIMISTIC)) {
+ (ia->ia6_flags & IN6_IFF_OPTIMISTIC)) {
/*
* rdar://17483438
* Bypass tentative for address assignments
* not covered above (e.g. manual) upon request
*/
if (!IN6_IS_ADDR_LINKLOCAL(&ia->ia_addr.sin6_addr) &&
- !(ia->ia6_flags & IN6_IFF_AUTOCONF) &&
- !(ia->ia6_flags & IN6_IFF_DYNAMIC))
+ !(ia->ia6_flags & IN6_IFF_AUTOCONF) &&
+ !(ia->ia6_flags & IN6_IFF_DYNAMIC))
flags = IN6_IFF_OPTIMISTIC;
}
}
audit_arg_sockaddr(struct kaudit_record *ar, struct vnode *cwd_vp,
struct sockaddr *sa)
{
+ char path[SOCK_MAXADDRLEN - offsetof(struct sockaddr_un, sun_path) + 1] = "";
struct sockaddr_un *sun;
- char path[SOCK_MAXADDRLEN - offsetof(struct sockaddr_un, sun_path) + 1];
+ ssize_t namelen;
KASSERT(sa != NULL, ("audit_arg_sockaddr: sa == NULL"));
case AF_UNIX:
sun = (struct sockaddr_un *)sa;
- if (sun->sun_len > offsetof(struct sockaddr_un, sun_path)) {
+ namelen = sun->sun_len - offsetof(struct sockaddr_un, sun_path);
+ if (namelen > 0 && (size_t)namelen < sizeof(path)) {
/*
- * Make sure the path is NULL-terminated
+ * Make sure the path is NUL-terminated
*/
- strlcpy(path, sun->sun_path, sizeof(path));
+ bcopy(sun->sun_path, path, namelen);
+ path[namelen] = 0;
audit_arg_upath(ar, cwd_vp, path, ARG_UPATH1);
}
ARG_SET_VALID(ar, ARG_SADDRUNIX);
goto out;
}
+#if DEVELOPMENT || DEBUG
+ /*
+ * XXX VSWAP: Check for entitlements or special flag here
+ * so we can restrict access appropriately.
+ */
+#else /* DEVELOPMENT || DEBUG */
+
+ if (vnode_isswap(vp) && (ctx != vfs_context_kernel())) {
+ error = EPERM;
+ goto out;
+ }
+#endif /* DEVELOPMENT || DEBUG */
+
#if NAMEDSTREAMS
/* For streams, va_data_size is the only setable attribute. */
if ((vp->v_flag & VISNAMEDSTREAM) && (vap->va_active != VNODE_ATTR_va_data_size)) {
goto out;
}
+#if DEVELOPMENT || DEBUG
+ /*
+ * XXX VSWAP: Check for entitlements or special flag here
+ * so we can restrict access appropriately.
+ */
+#else /* DEVELOPMENT || DEBUG */
+
+ if (vnode_isswap(vp) && (ctx != vfs_context_kernel())) {
+ error = EPERM;
+ goto out;
+ }
+#endif /* DEVELOPMENT || DEBUG */
+
VFS_DEBUG(ctx, vp, "%p ATTRLIST - %s set common %08x vol %08x file %08x dir %08x fork %08x %sfollow on '%s'",
vp, p->p_comm, al.commonattr, al.volattr, al.fileattr, al.dirattr, al.forkattr,
(uap->options & FSOPT_NOFOLLOW) ? "no":"", vp->v_name);
pageout_flags |= UPL_NOCOMMIT;
if (cbp_head) {
- buf_t last_cbp;
+ buf_t prev_cbp;
+ int bytes_in_last_page;
/*
* first we have to wait for the the current outstanding I/Os
* to complete... EOT hasn't been set yet on this transaction
- * so the pages won't be released just because all of the current
- * I/O linked to this transaction has completed...
+ * so the pages won't be released
*/
cluster_wait_IO(cbp_head, (flags & CL_ASYNC));
- /*
- * we've got a transcation that
- * includes the page we're about to push out through vnode_pageout...
- * find the last bp in the list which will be the one that
- * includes the head of this page and round it's iosize down
- * to a page boundary...
- */
- for (last_cbp = cbp = cbp_head; cbp->b_trans_next; cbp = cbp->b_trans_next)
- last_cbp = cbp;
-
- cbp->b_bcount &= ~PAGE_MASK;
-
- if (cbp->b_bcount == 0) {
- /*
- * this buf no longer has any I/O associated with it
+ bytes_in_last_page = cbp_head->b_uploffset & PAGE_MASK;
+ for (cbp = cbp_head; cbp; cbp = cbp->b_trans_next)
+ bytes_in_last_page += cbp->b_bcount;
+ bytes_in_last_page &= PAGE_MASK;
+
+ while (bytes_in_last_page) {
+ /*
+ * we've got a transcation that
+ * includes the page we're about to push out through vnode_pageout...
+ * find the bp's in the list which intersect this page and either
+ * remove them entirely from the transaction (there could be multiple bp's), or
+ * round it's iosize down to the page boundary (there can only be one)...
+ *
+ * find the last bp in the list and act on it
*/
- free_io_buf(cbp);
+ for (prev_cbp = cbp = cbp_head; cbp->b_trans_next; cbp = cbp->b_trans_next)
+ prev_cbp = cbp;
- if (cbp == cbp_head) {
- /*
- * the buf we just freed was the only buf in
- * this transaction... so there's no I/O to do
+ if (bytes_in_last_page >= cbp->b_bcount) {
+ /*
+ * this buf no longer has any I/O associated with it
*/
- cbp_head = NULL;
+ bytes_in_last_page -= cbp->b_bcount;
+ cbp->b_bcount = 0;
+
+ free_io_buf(cbp);
+
+ if (cbp == cbp_head) {
+ assert(bytes_in_last_page == 0);
+ /*
+ * the buf we just freed was the only buf in
+ * this transaction... so there's no I/O to do
+ */
+ cbp_head = NULL;
+ cbp_tail = NULL;
+ } else {
+ /*
+ * remove the buf we just freed from
+ * the transaction list
+ */
+ prev_cbp->b_trans_next = NULL;
+ cbp_tail = prev_cbp;
+ }
} else {
- /*
- * remove the buf we just freed from
- * the transaction list
+ /*
+ * this is the last bp that has I/O
+ * intersecting the page of interest
+ * only some of the I/O is in the intersection
+ * so clip the size but keep it in the transaction list
*/
- last_cbp->b_trans_next = NULL;
- cbp_tail = last_cbp;
+ cbp->b_bcount -= bytes_in_last_page;
+ cbp_tail = cbp;
+ bytes_in_last_page = 0;
}
}
if (cbp_head) {
fp->f_fglob->fg_flag |= FHASLOCK;
}
+#if DEVELOPMENT || DEBUG
+ /*
+ * XXX VSWAP: Check for entitlements or special flag here
+ * so we can restrict access appropriately.
+ */
+#else /* DEVELOPMENT || DEBUG */
+
+ if (vnode_isswap(vp) && (flags & (FWRITE | O_TRUNC)) && (ctx != vfs_context_kernel())) {
+ /* block attempt to write/truncate swapfile */
+ error = EPERM;
+ goto bad;
+ }
+#endif /* DEVELOPMENT || DEBUG */
+
/* try to truncate by setting the size attribute */
if ((flags & O_TRUNC) && ((error = vnode_setsize(vp, (off_t)0, 0, ctx)) != 0))
goto bad;
error = EBUSY;
}
+#if DEVELOPMENT || DEBUG
+ /*
+ * XXX VSWAP: Check for entitlements or special flag here
+ * so we can restrict access appropriately.
+ */
+#else /* DEVELOPMENT || DEBUG */
+
+ if (vnode_isswap(vp) && (ctx != vfs_context_kernel())) {
+ error = EPERM;
+ goto out;
+ }
+#endif /* DEVELOPMENT || DEBUG */
+
if (!batched) {
error = vn_authorize_unlink(dvp, vp, cnp, ctx, NULL);
if (error) {
tvp = tond->ni_vp;
}
+#if DEVELOPMENT || DEBUG
+ /*
+ * XXX VSWAP: Check for entitlements or special flag here
+ * so we can restrict access appropriately.
+ */
+#else /* DEVELOPMENT || DEBUG */
+
+ if (fromnd->ni_vp && vnode_isswap(fromnd->ni_vp) && (ctx != vfs_context_kernel())) {
+ error = EPERM;
+ goto out1;
+ }
+
+ if (tond->ni_vp && vnode_isswap(tond->ni_vp) && (ctx != vfs_context_kernel())) {
+ error = EPERM;
+ goto out1;
+ }
+#endif /* DEVELOPMENT || DEBUG */
+
if (!tvp && ISSET(flags, VFS_RENAME_SWAP)) {
error = ENOENT;
goto out1;
goto out;
}
+#if DEVELOPMENT || DEBUG
+ /*
+ * XXX VSWAP: Check for entitlements or special flag here
+ * so we can restrict access appropriately.
+ */
+#else /* DEVELOPMENT || DEBUG */
+
+ if (vnode_isswap(vp) && (ctx != vfs_context_kernel())) {
+ error = EPERM;
+ goto out;
+ }
+#endif /* DEVELOPMENT || DEBUG */
+
/*
* Removed a check here; we used to abort if vp's vid
* was not the same as what we'd seen the last time around.
/* Round up to MAXPATHLEN regardless of user input */
size = MAXPATHLEN;
}
+ else if (vp->v_tag == VT_CIFS) {
+ /*
+ * XXX Until fsctl's length encoding can be
+ * XXX fixed properly.
+ */
+ if (IOCBASECMD(cmd) == _IOWR('z', 19, 0) && size < 1432) {
+ size = 1432; /* sizeof(struct UniqueSMBShareID) */
+ } else if (IOCBASECMD(cmd) == _IOWR('z', 28, 0) && size < 308) {
+ size = 308; /* sizeof(struct smbDebugTestPB) */
+ }
+ }
if (size > sizeof (stkbuf)) {
if ((memp = (caddr_t)kalloc(size)) == 0) return ENOMEM;
panic("Haven't cleaned up adequately in vn_open_auth()");
}
+#if DEVELOPMENT || DEBUG
+ /*
+ * XXX VSWAP: Check for entitlements or special flag here
+ * so we can restrict access appropriately.
+ */
+#else /* DEVELOPMENT || DEBUG */
+
+ if (vnode_isswap(vp) && (fmode & (FWRITE | O_TRUNC)) && (ctx != vfs_context_kernel())) {
+ error = EPERM;
+ goto bad;
+ }
+#endif /* DEVELOPMENT || DEBUG */
+
/*
* Expect to use this code for filesystems without compound VNOPs, for the root
* of a filesystem, which can't be "looked up" in the sense of VNOP_LOOKUP(),
error = VNOP_READ(vp, auio, ioflg, &context);
}
} else {
+
+#if DEVELOPMENT || DEBUG
+ /*
+ * XXX VSWAP: Check for entitlements or special flag here
+ * so we can restrict access appropriately.
+ */
error = VNOP_WRITE(vp, auio, ioflg, &context);
+#else /* DEVELOPMENT || DEBUG */
+
+ if (vnode_isswap(vp) && ((ioflg & (IO_SWAP_DISPATCH | IO_SKIP_ENCRYPTION)) == 0)) {
+ error = EPERM;
+ } else {
+ error = VNOP_WRITE(vp, auio, ioflg, &context);
+ }
+#endif /* DEVELOPMENT || DEBUG */
}
}
count = uio_resid(uio);
if (vnode_isswap(vp) && !(IO_SKIP_ENCRYPTION & ioflag)) {
+
/* special case for swap files */
error = vn_read_swapfile(vp, uio);
} else {
error = VNOP_READ(vp, uio, ioflag, ctx);
}
+
if ((flags & FOF_OFFSET) == 0) {
fp->f_fglob->fg_offset += count - uio_resid(uio);
if (offset_locked) {
return(error);
}
+#if DEVELOPMENT || DEBUG
+ /*
+ * XXX VSWAP: Check for entitlements or special flag here
+ * so we can restrict access appropriately.
+ */
+#else /* DEVELOPMENT || DEBUG */
+
+ if (vnode_isswap(vp)) {
+ (void)vnode_put(vp);
+ error = EPERM;
+ return (error);
+ }
+#endif /* DEVELOPMENT || DEBUG */
+
+
#if CONFIG_MACF
error = mac_vnode_check_write(ctx, vfs_context_ucred(ctx), vp);
if (error) {
vm_swapfile_open(const char *path, vnode_t *vp)
{
int error = 0;
- vfs_context_t ctx = vfs_context_current();
+ vfs_context_t ctx = vfs_context_kernel();
if ((error = vnode_open(path, (O_CREAT | O_TRUNC | FREAD | FWRITE), S_IRUSR | S_IWUSR, 0, vp, ctx))) {
printf("Failed to open swap file %d\n", error);
void
vm_swapfile_close(uint64_t path_addr, vnode_t vp)
{
- vfs_context_t context = vfs_context_current();
+ vfs_context_t context = vfs_context_kernel();
int error;
vnode_getwithref(vp);
vfs_context_t ctx = NULL;
- ctx = vfs_context_current();
+ ctx = vfs_context_kernel();
error = vnode_setsize(vp, *size, IO_NOZEROFILL, ctx);
-16.5.0
+16.6.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.
uint32_t * hibernateMode,
uint32_t * hibernateFreeRatio,
uint32_t * hibernateFreeTime );
+ bool mustHibernate( void );
#endif
void takeStackshot(bool restart, bool isOSXWatchdog, bool isSpinDump);
void sleepWakeDebugTrig(bool restart);
HIBLOG("IOHibernatePollerOpen, ml_get_interrupts_enabled %d\n",
ml_get_interrupts_enabled());
- err = IOPolledFilePollersOpen(vars->fileVars, kIOPolledBeforeSleepState, true);
+ err = IOPolledFilePollersOpen(vars->fileVars, kIOPolledBeforeSleepState,
+ // abortable if not low battery
+ !IOService::getPMRootDomain()->mustHibernate());
HIBLOG("IOHibernatePollerOpen(%x)\n", err);
pollerOpen = (kIOReturnSuccess == err);
if (!pollerOpen)
data = OSDynamicCast(OSData, prop);
if (data != 0) {
bytes = data->getBytesNoCopy();
- if (bytes != 0) {
+ if ((bytes != 0) && (data->getLength() <= kIODTNVRAMImageSize)) {
bcopy(bytes, _nvramImage, data->getLength());
initNVRAMImage();
_isProxied = true;
return true;
}
+//******************************************************************************
+// mustHibernate
+//******************************************************************************
+
+#if HIBERNATION
+
+bool IOPMrootDomain::mustHibernate( void )
+{
+ return (lowBatteryCondition || thermalWarningState);
+}
+
+#endif /* HIBERNATION */
+
//******************************************************************************
// adjustPowerState
//
#define UNIQUEID(name) L ## name
+/* COMMPAGE_JMP(target,from,start)
+ *
+ * This macro perform a jump to another commpage routine.
+ * Used to return from the PFZ by jumping via a return outside the PFZ.
+ */
+#define COMMPAGE_JMP(target,from,start) \
+ jmp L ## start - from + target
+
#else /* __ASSEMBLER__ */
/* Each potential commpage routine is described by one of these.
_commpage_32_routines:
COMMPAGE_DESCRIPTOR_REFERENCE(preempt)
COMMPAGE_DESCRIPTOR_REFERENCE(backoff)
+ COMMPAGE_DESCRIPTOR_REFERENCE(ret)
COMMPAGE_DESCRIPTOR_REFERENCE(pfz_enqueue)
COMMPAGE_DESCRIPTOR_REFERENCE(pfz_dequeue)
.quad 0
_commpage_64_routines:
COMMPAGE_DESCRIPTOR_REFERENCE(preempt_64)
COMMPAGE_DESCRIPTOR_REFERENCE(backoff_64)
+ COMMPAGE_DESCRIPTOR_REFERENCE(ret_64)
COMMPAGE_DESCRIPTOR_REFERENCE(pfz_enqueue_64)
COMMPAGE_DESCRIPTOR_REFERENCE(pfz_dequeue_64)
.quad 0
COMMPAGE_CALL(_COMM_PAGE_BACKOFF,_COMM_PAGE_PFZ_ENQUEUE,pfz_enqueue)
jmp 1b // loop to try again
2:
- movl 4(%edi),%ecx // get ptr to last element in q
- testl %ecx,%ecx // q null?
+ movl 4(%edi),%eax // get ptr to last element in q
+ testl %eax,%eax // q null?
jnz 3f // no
movl %esi,(%edi) // q empty so this is first element
jmp 4f
3:
- movl %esi,(%edx,%ecx) // point to new element from last
+ movl %esi,(%edx,%eax) // point to new element from last
4:
movl %esi,4(%edi) // new element becomes last in q
movl $0,8(%edi) // unlock spinlock
- ret
+ COMMPAGE_JMP(_COMM_PAGE_RET,_COMM_PAGE_PFZ_ENQUEUE,pfz_enqueue)
COMMPAGE_DESCRIPTOR(pfz_enqueue,_COMM_PAGE_PFZ_ENQUEUE)
movl %esi,(%edi) // update "first" field of q head
4:
movl $0,8(%edi) // unlock spinlock
- ret
+ COMMPAGE_JMP(_COMM_PAGE_RET,_COMM_PAGE_PFZ_DEQUEUE,pfz_dequeue)
COMMPAGE_DESCRIPTOR(pfz_dequeue,_COMM_PAGE_PFZ_DEQUEUE)
+COMMPAGE_FUNCTION_START(ret, 32, 4)
+ ret
+COMMPAGE_DESCRIPTOR(ret,_COMM_PAGE_RET)
+
/************************* x86_64 versions follow **************************/
COMMPAGE_CALL(_COMM_PAGE_BACKOFF,_COMM_PAGE_PFZ_ENQUEUE,pfz_enqueue_64)
jmp 1b // loop to try again
2:
- movq 8(%rdi),%rcx // get ptr to last element in q
- testq %rcx,%rcx // q null?
+ movq 8(%rdi),%rax // get ptr to last element in q
+ testq %rax,%rax // q null?
jnz 3f // no
movq %rsi,(%rdi) // q empty so this is first element
jmp 4f
3:
- movq %rsi,(%rdx,%rcx) // point to new element from last
+ movq %rsi,(%rdx,%rax) // point to new element from last
4:
movq %rsi,8(%rdi) // new element becomes last in q
movl $0,16(%rdi) // unlock spinlock
- ret
+ COMMPAGE_JMP(_COMM_PAGE_RET,_COMM_PAGE_PFZ_ENQUEUE,pfz_enqueue_64)
COMMPAGE_DESCRIPTOR(pfz_enqueue_64,_COMM_PAGE_PFZ_ENQUEUE)
movq %rsi,(%rdi) // update "first" field of q head
4:
movl $0,16(%rdi) // unlock spinlock
- ret
+ COMMPAGE_JMP(_COMM_PAGE_RET,_COMM_PAGE_PFZ_DEQUEUE,pfz_dequeue_64)
COMMPAGE_DESCRIPTOR(pfz_dequeue_64,_COMM_PAGE_PFZ_DEQUEUE)
+
+COMMPAGE_FUNCTION_START(ret_64, 64, 4)
+ ret
+COMMPAGE_DESCRIPTOR(ret_64,_COMM_PAGE_RET)
#define _COMM_TEXT_PREEMPT_OFFSET (0x5a0) /* called from withing pfz */
#define _COMM_TEXT_BACKOFF_OFFSET (0x600) /* called from PFZ */
+#define _COMM_TEXT_RET_OFFSET (0x680) /* called from PFZ */
#define _COMM_TEXT_PFZ_START_OFFSET (0xc00) /* offset for Preemption Free Zone */
#define _COMM_TEXT_PFZ_ENQUEUE_OFFSET (0xc00) /* internal FIFO enqueue */
#define _COMM_TEXT_PFZ_DEQUEUE_OFFSET (0xc80) /* internal FIFO dequeue */
-#define _COMM_TEXT_UNUSED_OFFSET (0xd80) /* end of routines in text page */
-#define _COMM_TEXT_PFZ_END_OFFSET (0xfff) /* offset for end of PFZ */
+#define _COMM_TEXT_UNUSED_OFFSET (0xd00) /* end of routines in text page */
+#define _COMM_TEXT_PFZ_END_OFFSET (0xd00) /* offset for end of PFZ */
#define _COMM_PAGE_PREEMPT (_COMM_PAGE_TEXT_START+_COMM_TEXT_PREEMPT_OFFSET)
#define _COMM_PAGE_BACKOFF (_COMM_PAGE_TEXT_START+_COMM_TEXT_BACKOFF_OFFSET)
+#define _COMM_PAGE_RET (_COMM_PAGE_TEXT_START+_COMM_TEXT_RET_OFFSET)
#define _COMM_PAGE_PFZ_START (_COMM_PAGE_TEXT_START+_COMM_PAGE_PFZ_START_OFFSET)
* Allocate and initialize the per-processor descriptor tables.
*/
-struct fake_descriptor ldt_desc_pattern = {
- (unsigned int) 0,
- LDTSZ_MIN * sizeof(struct fake_descriptor) - 1,
- 0,
- ACC_P|ACC_PL_K|ACC_LDT
-};
-
-struct fake_descriptor tss_desc_pattern = {
- (unsigned int) 0,
- sizeof(struct i386_tss) - 1,
- 0,
- ACC_P|ACC_PL_K|ACC_TSS
-};
-
-struct fake_descriptor cpudata_desc_pattern = {
- (unsigned int) 0,
- sizeof(cpu_data_t)-1,
- SZ_32,
- ACC_P|ACC_PL_K|ACC_DATA_W
-};
-
-#if NCOPY_WINDOWS > 0
-struct fake_descriptor userwindow_desc_pattern = {
- (unsigned int) 0,
- ((NBPDE * NCOPY_WINDOWS) / PAGE_SIZE) - 1,
- SZ_32 | SZ_G,
- ACC_P|ACC_PL_U|ACC_DATA_W
-};
-#endif
-
-struct fake_descriptor physwindow_desc_pattern = {
- (unsigned int) 0,
- PAGE_SIZE - 1,
- SZ_32,
- ACC_P|ACC_PL_K|ACC_DATA_W
-};
-
/*
* This is the expanded, 64-bit variant of the kernel LDT descriptor.
* When switching to 64-bit mode this replaces KERNEL_LDT entry
else if (sel.index < GDTSZ && sel.rpl == USER_PRIV) {
if ((gdt_desc_p(selector)->access & ACC_PL_U) == ACC_PL_U)
return (TRUE);
+ /* Explicitly validate the system code selectors
+ * even if not instantaneously privileged,
+ * since they are dynamically re-privileged
+ * at context switch
+ */
+ if ((selector == USER_CS) || (selector == USER64_CS))
+ return (TRUE);
}
return (FALSE);
* Enable the 64-bit user code segment, USER64_CS.
* Disable the 32-bit user code segment, USER_CS.
*/
- ldt_desc_p(USER64_CS)->access |= ACC_PL_U;
- ldt_desc_p(USER_CS)->access &= ~ACC_PL_U;
+ gdt_desc_p(USER64_CS)->access |= ACC_PL_U;
+ gdt_desc_p(USER_CS)->access &= ~ACC_PL_U;
/*
* Switch user's GS base if necessary
* in the event it was altered in user space.
*/
if ((pcb->cthread_self != 0) || (new->task != kernel_task)) {
- if ((cdp->cpu_uber.cu_user_gs_base != pcb->cthread_self) || (pcb->cthread_self != rdmsr64(MSR_IA32_KERNEL_GS_BASE))) {
+ if ((cdp->cpu_uber.cu_user_gs_base != pcb->cthread_self) ||
+ (pcb->cthread_self != rdmsr64(MSR_IA32_KERNEL_GS_BASE))) {
cdp->cpu_uber.cu_user_gs_base = pcb->cthread_self;
wrmsr64(MSR_IA32_KERNEL_GS_BASE, pcb->cthread_self);
}
* Disable USER64_CS
* Enable USER_CS
*/
- ldt_desc_p(USER64_CS)->access &= ~ACC_PL_U;
- ldt_desc_p(USER_CS)->access |= ACC_PL_U;
+
+ /* It's possible that writing to the GDT areas
+ * is expensive, if the processor intercepts those
+ * writes to invalidate its internal segment caches
+ * TODO: perhaps only do this if switching bitness
+ */
+ gdt_desc_p(USER64_CS)->access &= ~ACC_PL_U;
+ gdt_desc_p(USER_CS)->access |= ACC_PL_U;
/*
* Set the thread`s cthread (a.k.a pthread)
}
/*
- * Assure that the synthesized 32-bit state including
+ * Ensure that the synthesized 32-bit state including
* the 64-bit interrupt state can be acommodated in the
* 64-bit state we allocate for both 32-bit and 64-bit threads.
*/
__asm__ volatile("leaq 1f(%%rip), %%rax; mov %%rax, %0\n1:" : "=m" (iks->k_rip)::"rax");
}
}
+
+#if DEBUG
+extern void thread_exception_return_internal(void) __dead2;
+
+void thread_exception_return(void) {
+ thread_t thread = current_thread();
+ ml_set_interrupts_enabled(FALSE);
+ if (thread_is_64bit(thread) != task_has_64BitAddr(thread->task)) {
+ panic("Task/thread bitness mismatch %p %p, task: %d, thread: %d", thread, thread->task, thread_is_64bit(thread), task_has_64BitAddr(thread->task));
+ }
+
+ if (thread_is_64bit(thread)) {
+ if ((gdt_desc_p(USER64_CS)->access & ACC_PL_U) == 0) {
+ panic("64-GDT mismatch %p, descriptor: %p", thread, gdt_desc_p(USER64_CS));
+ }
+ } else {
+ if ((gdt_desc_p(USER_CS)->access & ACC_PL_U) == 0) {
+ panic("32-GDT mismatch %p, descriptor: %p", thread, gdt_desc_p(USER_CS));
+
+ }
+ }
+ thread_exception_return_internal();
+}
+#endif
{
mach_msg_port_descriptor_t *user_dsc = (typeof(user_dsc))dest_dsc;
user_dsc--; // point to the start of this port descriptor
+ bzero((void *)user_dsc, sizeof(*user_dsc));
user_dsc->name = CAST_MACH_NAME_TO_PORT(name);
user_dsc->disposition = disp;
user_dsc->type = MACH_MSG_PORT_DESCRIPTOR;
} else {
mach_msg_legacy_port_descriptor_t *user_dsc = (typeof(user_dsc))dest_dsc;
user_dsc--; // point to the start of this port descriptor
+ bzero((void *)user_dsc, sizeof(*user_dsc));
user_dsc->name = CAST_MACH_PORT_TO_NAME(name);
user_dsc->disposition = disp;
user_dsc->type = MACH_MSG_PORT_DESCRIPTOR;
{
mach_msg_ool_descriptor_t *user_ool_dsc = (typeof(user_ool_dsc))user_dsc;
user_ool_dsc--;
+ bzero((void *)user_ool_dsc, sizeof(*user_ool_dsc));
user_ool_dsc->address = (void *)(uintptr_t)rcv_addr;
user_ool_dsc->deallocate = (copy_options == MACH_MSG_VIRTUAL_COPY) ?
} else if (is_64bit) {
mach_msg_ool_descriptor64_t *user_ool_dsc = (typeof(user_ool_dsc))user_dsc;
user_ool_dsc--;
+ bzero((void *)user_ool_dsc, sizeof(*user_ool_dsc));
user_ool_dsc->address = rcv_addr;
user_ool_dsc->deallocate = (copy_options == MACH_MSG_VIRTUAL_COPY) ?
} else {
mach_msg_ool_descriptor32_t *user_ool_dsc = (typeof(user_ool_dsc))user_dsc;
user_ool_dsc--;
+ bzero((void *)user_ool_dsc, sizeof(*user_ool_dsc));
user_ool_dsc->address = CAST_DOWN_EXPLICIT(uint32_t, rcv_addr);
user_ool_dsc->size = (mach_msg_size_t)size;
if(current_task() == kernel_task) {
mach_msg_ool_ports_descriptor_t *user_ool_dsc = (typeof(user_ool_dsc))user_dsc;
user_ool_dsc--;
+ bzero((void *)user_ool_dsc, sizeof(*user_ool_dsc));
user_ool_dsc->address = (void *)(uintptr_t)rcv_addr;
user_ool_dsc->deallocate = (copy_options == MACH_MSG_VIRTUAL_COPY) ?
} if (is_64bit) {
mach_msg_ool_ports_descriptor64_t *user_ool_dsc = (typeof(user_ool_dsc))user_dsc;
user_ool_dsc--;
+ bzero((void *)user_ool_dsc, sizeof(*user_ool_dsc));
user_ool_dsc->address = rcv_addr;
user_ool_dsc->deallocate = (copy_options == MACH_MSG_VIRTUAL_COPY) ?
} else {
mach_msg_ool_ports_descriptor32_t *user_ool_dsc = (typeof(user_ool_dsc))user_dsc;
user_ool_dsc--;
+ bzero((void *)user_ool_dsc, sizeof(*user_ool_dsc));
user_ool_dsc->address = CAST_DOWN_EXPLICIT(uint32_t, rcv_addr);
user_ool_dsc->count = count;
* Returns:
* KERN_SUCCESS Object returned locked.
* KERN_INVALID_TASK The space is dead.
- * KERN_INVALID_NAME The name doesn't denote a right.
- * KERN_INVALID_RIGHT Name doesn't denote the correct right.
+ * KERN_INVALID_NAME The name doesn't denote a right
+ * KERN_INVALID_RIGHT Name doesn't denote the correct right
*/
-
kern_return_t
ipc_object_translate(
ipc_space_t space,
union {
ipc_kobject_t kobject;
ipc_importance_task_t imp_task;
- uintptr_t alias;
} kdata;
struct ipc_port *ip_nsrequest;
#define ip_kobject kdata.kobject
#define ip_imp_task kdata.imp_task
-#define ip_alias kdata.alias
#define IP_NULL IPC_PORT_NULL
#define IP_DEAD IPC_PORT_DEAD
#include <mach/port.h>
#include <mach/message.h>
#include <kern/assert.h>
+#include <kern/ipc_kobject.h>
#include <kern/misc_protos.h>
#include <ipc/port.h>
#include <ipc/ipc_entry.h>
case MACH_MSG_TYPE_MOVE_RECEIVE:
if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
return FALSE;
+ if (io_kotype(entry->ie_object) != IKOT_NONE)
+ return FALSE;
break;
case MACH_MSG_TYPE_COPY_SEND:
if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
goto invalid_right;
+ /*
+ * Disallow moving receive-right kobjects, e.g. mk_timer ports
+ * The ipc_port structure uses the kdata union of kobject and
+ * imp_task exclusively. Thus, general use of a kobject port as
+ * a receive right can cause type confusion in the importance
+ * code.
+ */
+ if (io_kotype(entry->ie_object) != IKOT_NONE) {
+ /*
+ * Distinguish an invalid right, e.g., trying to move
+ * a send right as a receive right, from this
+ * situation which is, "This is a valid receive right,
+ * but it's also a kobject and you can't move it."
+ */
+ return KERN_INVALID_CAPABILITY;
+ }
+
port = (ipc_port_t) entry->ie_object;
assert(port != IP_NULL);
return kr;
/* port is locked and active */
+ /* you cannot register for port death notifications on a kobject */
+ if (ip_kotype(port) != IKOT_NONE) {
+ ip_unlock(port);
+ return KERN_INVALID_RIGHT;
+ }
+
ipc_port_pdrequest(port, notify, &previous);
/* port is unlocked */
{
boolean_t dispatch_p = ((trace_flags & STACKSHOT_GET_DQ) != 0);
boolean_t active_kthreads_only_p = ((trace_flags & STACKSHOT_ACTIVE_KERNEL_THREADS_ONLY) != 0);
- boolean_t trace_fp_p = ((trace_flags & STACKSHOT_TAILSPIN) == 0);
+ boolean_t trace_fp_p = false;
boolean_t collect_delta_stackshot = ((trace_flags & STACKSHOT_COLLECT_DELTA_SNAPSHOT) != 0);
boolean_t collect_iostats = !collect_delta_stackshot && !(trace_flags & STACKSHOT_TAILSPIN) && !(trace_flags & STACKSHOT_NO_IO_STATS);
return (MACH_PORT_NULL);
result = mach_port_allocate_qos(myspace, MACH_PORT_RIGHT_RECEIVE,
- &mk_timer_qos, &name);
+ &mk_timer_qos, &name);
if (result == KERN_SUCCESS)
result = ipc_port_translate_receive(myspace, name, &port);
* state with respect to its task's 64-bitness.
*/
-#if defined(__i386__) || defined(__x86_64__) || defined(__arm64__)
+#if defined(__x86_64__) || defined(__arm64__)
queue_iterate(&task->threads, thread, thread_t, task_threads) {
thread_mtx_lock(thread);
machine_thread_switch_addrmode(thread);
splx(spl);
}
}
-#endif /* defined(__i386__) || defined(__x86_64__) || defined(__arm64__) */
+#endif /* defined(__x86_64__) || defined(__arm64__) */
out:
task_unlock(task);
};
/*
- * Protects num_zones, zone_array and zone_array_index
+ * Protects num_zones and zone_array
*/
decl_simple_lock_data(, all_zones_lock)
unsigned int num_zones;
#define MAX_ZONES 256
struct zone zone_array[MAX_ZONES];
-static int zone_array_index = 0;
#define MULTIPAGE_METADATA_MAGIC (0xff)
zone_t z;
simple_lock(&all_zones_lock);
- z = &(zone_array[zone_array_index]);
- zone_array_index++;
- assert(zone_array_index != MAX_ZONES);
+ assert(num_zones < MAX_ZONES);
+ z = &(zone_array[num_zones]);
+ z->index = num_zones;
+ num_zones++;
simple_unlock(&all_zones_lock);
/* Zone elements must fit both a next pointer and a backup pointer */
lock_zone_init(z);
- /*
- * Add the zone to the all-zones list.
- */
- simple_lock(&all_zones_lock);
- z->index = num_zones;
- num_zones++;
- simple_unlock(&all_zones_lock);
-
/*
* Check for and set up zone leak detection if requested via boot-args. We recognized two
* boot-args:
*/
mov %r15, %rsp /* Set the PCB as the stack */
swapgs
+
+ xor %r8, %r8
+ xor %r9, %r9
+ xor %r10, %r10
+ xor %r11, %r11
+ xor %r12, %r12
+ xor %r13, %r13
+ xor %r14, %r14
+ xor %r15, %r15
+
EXT(ret32_set_ds):
movl R32_DS(%rsp), %ds
EXT(ret32_set_es):
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
-
+#include <debug.h>
#include <mach_rt.h>
#include <mach_kdp.h>
#include <mach_assert.h>
movl $1, %eax
ret
+#if DEBUG
+.globl EXT(thread_exception_return_internal)
+#else
.globl EXT(thread_exception_return)
+#endif
.globl EXT(thread_bootstrap_return)
LEXT(thread_bootstrap_return)
#if CONFIG_DTRACE
call EXT(dtrace_thread_bootstrap)
#endif
+#if DEBUG
+LEXT(thread_exception_return_internal)
+#else
LEXT(thread_exception_return)
+#endif
cli
xorl %ecx, %ecx /* don't check if we're in the PFZ */
jmp EXT(return_from_trap)
--- /dev/null
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <mach/mach.h>
+#include <mach/mk_timer.h>
+
+#include <darwintest.h>
+
+T_DECL(mktimer_kobject, "mktimer_kobject()", T_META_ALL_VALID_ARCHS(true))
+{
+ mach_port_t timer_port = MACH_PORT_NULL;
+ mach_port_t notify_port = MACH_PORT_NULL;
+
+ kern_return_t kr = KERN_SUCCESS;
+
+ // timer port
+ // This is a receive right which is also a kobject
+ timer_port = mk_timer_create();
+ T_ASSERT_NE(timer_port, (mach_port_t)MACH_PORT_NULL, "mk_timer_create: %s", mach_error_string(kr));
+
+ mach_port_set_context(mach_task_self(), timer_port, (mach_port_context_t) 0x1);
+ T_ASSERT_EQ(kr, KERN_SUCCESS, "mach_port_set_context(timer_port): %s", mach_error_string(kr));
+
+ // notification port for the mk_timer port to come back on
+ kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, ¬ify_port);
+ T_ASSERT_EQ(kr, KERN_SUCCESS, "mach_port_allocate(notify_port): %s", mach_error_string(kr));
+
+ kr = mach_port_set_context(mach_task_self(), notify_port, (mach_port_context_t) 0x2);
+ T_ASSERT_EQ(kr, KERN_SUCCESS, "mach_port_set_context(notify_port): %s", mach_error_string(kr));
+
+ T_LOG("timer: 0x%x, notify: 0x%x", timer_port, notify_port);
+
+ mach_port_t previous = MACH_PORT_NULL;
+
+ // request a port-destroyed notification on the timer port
+ kr = mach_port_request_notification(mach_task_self(), timer_port, MACH_NOTIFY_PORT_DESTROYED,
+ 0, notify_port, MACH_MSG_TYPE_MAKE_SEND_ONCE, &previous);
+ // this should fail!
+ T_ASSERT_NE(kr, KERN_SUCCESS, "notifications should NOT work on mk_timer ports!");
+
+ // destroy the timer port to send the notification
+ mach_port_mod_refs(mach_task_self(), timer_port, MACH_PORT_RIGHT_RECEIVE, -1);
+
+ // destroy the notification port
+ mach_port_mod_refs(mach_task_self(), notify_port, MACH_PORT_RIGHT_RECEIVE, -1);
+
+ T_LOG("done");
+}
+