X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/0a7de7458d150b5d4dffc935ba399be265ef0a1a..bca245acd4c03fd752d1a45f011ad495e60fe53d:/bsd/kern/sys_generic.c?ds=inline diff --git a/bsd/kern/sys_generic.c b/bsd/kern/sys_generic.c index ec07b11fc..bd2d1ad52 100644 --- a/bsd/kern/sys_generic.c +++ b/bsd/kern/sys_generic.c @@ -109,6 +109,7 @@ #include #include #include +#include #include #include @@ -142,11 +143,16 @@ #include /* for remote time api*/ #include +#include +#include #if CONFIG_MACF #include #endif +/* for entitlement check */ +#include + /* XXX should be in a header file somewhere */ void evsofree(struct socket *); void evpipefree(struct pipe *); @@ -353,7 +359,7 @@ dofileread(vfs_context_t ctx, struct fileproc *fp, { uio_t auio; user_ssize_t bytecnt; - long error = 0; + int error = 0; char uio_buf[UIO_SIZEOF(1)]; if (nbyte > INT_MAX) { @@ -367,7 +373,10 @@ dofileread(vfs_context_t ctx, struct fileproc *fp, auio = uio_createwithbuffer(1, offset, UIO_USERSPACE32, UIO_READ, &uio_buf[0], sizeof(uio_buf)); } - uio_addiov(auio, bufp, nbyte); + if (uio_addiov(auio, bufp, nbyte) != 0) { + *retval = 0; + return EINVAL; + } bytecnt = nbyte; @@ -590,7 +599,7 @@ dofilewrite(vfs_context_t ctx, struct fileproc *fp, user_ssize_t *retval) { uio_t auio; - long error = 0; + int error = 0; user_ssize_t bytecnt; char uio_buf[UIO_SIZEOF(1)]; @@ -606,7 +615,10 @@ dofilewrite(vfs_context_t ctx, struct fileproc *fp, auio = uio_createwithbuffer(1, offset, UIO_USERSPACE32, UIO_WRITE, &uio_buf[0], sizeof(uio_buf)); } - uio_addiov(auio, bufp, nbyte); + if (uio_addiov(auio, bufp, nbyte) != 0) { + *retval = 0; + return EINVAL; + } bytecnt = nbyte; if ((error = fo_write(fp, auio, flags, ctx))) { @@ -911,7 +923,7 @@ ioctl(struct proc *p, struct ioctl_args *uap, __unused int32_t *retval) break; } if (fp->f_type == DTYPE_PIPE) { - error = fo_ioctl(fp, (int)TIOCSPGRP, (caddr_t)&tmp, &context); + error = fo_ioctl(fp, TIOCSPGRP, (caddr_t)&tmp, &context); break; } if (tmp <= 0) { @@ -925,7 +937,7 @@ ioctl(struct proc *p, struct ioctl_args *uap, __unused int32_t *retval) tmp = p1->p_pgrpid; proc_rele(p1); } - error = fo_ioctl(fp, (int)TIOCSPGRP, (caddr_t)&tmp, &context); + error = fo_ioctl(fp, TIOCSPGRP, (caddr_t)&tmp, &context); break; case FIOGETOWN: @@ -1623,7 +1635,7 @@ selscan(struct proc *p, struct _select *sel, struct _select_data * seldata, bits = iptr[i / NFDBITS]; while ((j = ffs(bits)) && (fd = i + --j) < nfd) { - bits &= ~(1 << j); + bits &= ~(1U << j); if (fd < fdp->fd_nfiles) { fp = fdp->fd_ofiles[fd]; @@ -1667,7 +1679,7 @@ selscan(struct proc *p, struct _select *sel, struct _select_data * seldata, /* The select; set the bit, if true */ if (fp->f_ops && fp->f_type && fo_select(fp, flag[msk], rl_ptr, &context)) { - optr[fd / NFDBITS] |= (1 << (fd % NFDBITS)); + optr[fd / NFDBITS] |= (1U << (fd % NFDBITS)); n++; } if (sel_pass == SEL_FIRSTPASS) { @@ -1699,13 +1711,7 @@ selscan(struct proc *p, struct _select *sel, struct _select_data * seldata, return 0; } -int poll_callback(struct kqueue *, struct kevent_internal_s *, void *); - -struct poll_continue_args { - user_addr_t pca_fds; - u_int pca_nfds; - u_int pca_rfds; -}; +static int poll_callback(struct kevent_qos_s *, kevent_ctx_t); int poll(struct proc *p, struct poll_args *uap, int32_t *retval) @@ -1718,15 +1724,11 @@ poll(struct proc *p, struct poll_args *uap, int32_t *retval) int poll_nocancel(struct proc *p, struct poll_nocancel_args *uap, int32_t *retval) { - struct poll_continue_args *cont; - struct pollfd *fds; - struct kqueue *kq; - struct timeval atv; + struct pollfd *fds = NULL; + struct kqueue *kq = NULL; int ncoll, error = 0; u_int nfds = uap->nfds; u_int rfds = 0; - u_int i; - size_t ni; /* * This is kinda bogus. We have fd limits, but that is not @@ -1740,46 +1742,30 @@ poll_nocancel(struct proc *p, struct poll_nocancel_args *uap, int32_t *retval) return EINVAL; } - kq = kqueue_alloc(p, 0); + kq = kqueue_alloc(p); if (kq == NULL) { return EAGAIN; } - ni = nfds * sizeof(struct pollfd) + sizeof(struct poll_continue_args); - MALLOC(cont, struct poll_continue_args *, ni, M_TEMP, M_WAITOK); - if (NULL == cont) { - error = EAGAIN; - goto out; - } - - fds = (struct pollfd *)&cont[1]; - error = copyin(uap->fds, fds, nfds * sizeof(struct pollfd)); - if (error) { - goto out; - } - - if (uap->timeout != -1) { - struct timeval rtv; + if (nfds) { + size_t ni = nfds * sizeof(struct pollfd); + MALLOC(fds, struct pollfd *, ni, M_TEMP, M_WAITOK); + if (NULL == fds) { + error = EAGAIN; + goto out; + } - atv.tv_sec = uap->timeout / 1000; - atv.tv_usec = (uap->timeout % 1000) * 1000; - if (itimerfix(&atv)) { - error = EINVAL; + error = copyin(uap->fds, fds, nfds * sizeof(struct pollfd)); + if (error) { goto out; } - getmicrouptime(&rtv); - timevaladd(&atv, &rtv); - } else { - atv.tv_sec = 0; - atv.tv_usec = 0; } /* JMM - all this P_SELECT stuff is bogus */ ncoll = nselcoll; OSBitOrAtomic(P_SELECT, &p->p_flag); - for (i = 0; i < nfds; i++) { + for (u_int i = 0; i < nfds; i++) { short events = fds[i].events; - KNOTE_LOCK_CTX(knlc); __assert_only int rc; /* per spec, ignore fd values below zero */ @@ -1789,7 +1775,7 @@ poll_nocancel(struct proc *p, struct poll_nocancel_args *uap, int32_t *retval) } /* convert the poll event into a kqueue kevent */ - struct kevent_internal_s kev = { + struct kevent_qos_s kev = { .ident = fds[i].fd, .flags = EV_ADD | EV_ONESHOT | EV_POLL, .udata = CAST_USER_ADDR_T(&fds[i]) @@ -1801,7 +1787,7 @@ poll_nocancel(struct proc *p, struct poll_nocancel_args *uap, int32_t *retval) if (events & (POLLPRI | POLLRDBAND)) { kev.flags |= EV_OOBAND; } - rc = kevent_register(kq, &kev, &knlc); + rc = kevent_register(kq, &kev, NULL); assert((rc & FILTER_REGISTER_WAIT) == 0); } @@ -1809,7 +1795,7 @@ poll_nocancel(struct proc *p, struct poll_nocancel_args *uap, int32_t *retval) if ((kev.flags & EV_ERROR) == 0 && (events & (POLLOUT | POLLWRNORM | POLLWRBAND))) { kev.filter = EVFILT_WRITE; - rc = kevent_register(kq, &kev, &knlc); + rc = kevent_register(kq, &kev, NULL); assert((rc & FILTER_REGISTER_WAIT) == 0); } @@ -1830,7 +1816,7 @@ poll_nocancel(struct proc *p, struct poll_nocancel_args *uap, int32_t *retval) if (events & POLLWRITE) { kev.fflags |= NOTE_WRITE; } - rc = kevent_register(kq, &kev, &knlc); + rc = kevent_register(kq, &kev, NULL); assert((rc & FILTER_REGISTER_WAIT) == 0); } @@ -1854,21 +1840,27 @@ poll_nocancel(struct proc *p, struct poll_nocancel_args *uap, int32_t *retval) goto done; } + /* scan for, and possibly wait for, the kevents to trigger */ + kevent_ctx_t kectx = kevent_get_context(current_thread()); + *kectx = (struct kevent_ctx_s){ + .kec_process_noutputs = rfds, + .kec_process_flags = KEVENT_FLAG_POLL, + .kec_deadline = 0, /* wait forever */ + }; + /* * If any events have trouble registering, an event has fired and we - * shouldn't wait for events in kqueue_scan -- use the current time as - * the deadline. + * shouldn't wait for events in kqueue_scan. */ if (rfds) { - getmicrouptime(&atv); + kectx->kec_process_flags |= KEVENT_FLAG_IMMEDIATE; + } else if (uap->timeout != -1) { + clock_interval_to_deadline(uap->timeout, NSEC_PER_MSEC, + &kectx->kec_deadline); } - /* scan for, and possibly wait for, the kevents to trigger */ - cont->pca_fds = uap->fds; - cont->pca_nfds = nfds; - cont->pca_rfds = rfds; - error = kqueue_scan(kq, poll_callback, NULL, cont, NULL, &atv, p); - rfds = cont->pca_rfds; + error = kqueue_scan(kq, kectx->kec_process_flags, kectx, poll_callback); + rfds = kectx->kec_process_noutputs; done: OSBitAndAtomic(~((uint32_t)P_SELECT), &p->p_flag); @@ -1876,27 +1868,23 @@ done: if (error == ERESTART) { error = EINTR; } - if (error == EWOULDBLOCK) { - error = 0; - } if (error == 0) { error = copyout(fds, uap->fds, nfds * sizeof(struct pollfd)); *retval = rfds; } out: - if (NULL != cont) { - FREE(cont, M_TEMP); + if (NULL != fds) { + FREE(fds, M_TEMP); } kqueue_dealloc(kq); return error; } -int -poll_callback(__unused struct kqueue *kq, struct kevent_internal_s *kevp, void *data) +static int +poll_callback(struct kevent_qos_s *kevp, kevent_ctx_t kectx) { - struct poll_continue_args *cont = (struct poll_continue_args *)data; struct pollfd *fds = CAST_DOWN(struct pollfd *, kevp->udata); short prev_revents = fds->revents; short mask = 0; @@ -1945,7 +1933,7 @@ poll_callback(__unused struct kqueue *kq, struct kevent_internal_s *kevp, void * } if (fds->revents != 0 && prev_revents == 0) { - cont->pca_rfds++; + kectx->kec_process_noutputs++; } return 0; @@ -2011,7 +1999,7 @@ selcount(struct proc *p, u_int32_t *ibits, int nfd, int *countp) for (i = 0; i < nfd; i += NFDBITS) { bits = iptr[i / NFDBITS]; while ((j = ffs(bits)) && (fd = i + --j) < nfd) { - bits &= ~(1 << j); + bits &= ~(1U << j); if (fd < fdp->fd_nfiles) { fp = fdp->fd_ofiles[fd]; @@ -2025,7 +2013,7 @@ selcount(struct proc *p, u_int32_t *ibits, int nfd, int *countp) error = EBADF; goto bad; } - fp->f_iocount++; + os_ref_retain_locked(&fp->f_iocount); n++; } } @@ -2111,7 +2099,7 @@ seldrop_locked(struct proc *p, u_int32_t *ibits, int nfd, int lim, int *need_wak for (i = 0; i < nfd; i += NFDBITS) { bits = iptr[i / NFDBITS]; while ((j = ffs(bits)) && (fd = i + --j) < nfd) { - bits &= ~(1 << j); + bits &= ~(1U << j); fp = fdp->fd_ofiles[fd]; /* * If we've already dropped as many as were @@ -2138,12 +2126,12 @@ seldrop_locked(struct proc *p, u_int32_t *ibits, int nfd, int lim, int *need_wak continue; } - fp->f_iocount--; - if (fp->f_iocount < 0) { + const os_ref_count_t refc = os_ref_release_locked(&fp->f_iocount); + if (0 == refc) { panic("f_iocount overdecrement!"); } - if (fp->f_iocount == 0) { + if (1 == refc) { /* * The last iocount is responsible for clearing * selconfict flag - even if we didn't set it - @@ -3184,7 +3172,6 @@ waitevent_close(struct proc *p, struct fileproc *fp) * * Parameters: uuid_buf Pointer to buffer to receive UUID * timeout Timespec for timout - * spi SPI, skip sandbox check (temporary) * * Returns: 0 Success * EWOULDBLOCK Timeout is too short @@ -3202,7 +3189,8 @@ gethostuuid(struct proc *p, struct gethostuuid_args *uap, __unused int32_t *retv mach_timespec_t mach_ts; /* for IOKit call */ __darwin_uuid_t uuid_kern = {}; /* for IOKit call */ - if (!uap->spi) { + /* Check entitlement */ + if (!IOTaskHasEntitlement(current_task(), "com.apple.private.getprivatesysid")) { #if CONFIG_EMBEDDED #if CONFIG_MACF if ((error = mac_system_check_info(kauth_cred_get(), "hw.uuid")) != 0) { @@ -3403,6 +3391,86 @@ telemetry(__unused struct proc *p, struct telemetry_args *args, __unused int32_t return error; } +/* + * Logging + * + * Description: syscall to access kernel logging from userspace + * + * Args: + * tag - used for syncing with userspace on the version. + * flags - flags used by the syscall. + * buffer - userspace address of string to copy. + * size - size of buffer. + */ +int +log_data(__unused struct proc *p, struct log_data_args *args, int *retval) +{ + unsigned int tag = args->tag; + unsigned int flags = args->flags; + user_addr_t buffer = args->buffer; + unsigned int size = args->size; + int ret = 0; + char *log_msg = NULL; + int error; + *retval = 0; + + /* + * Tag synchronize the syscall version with userspace. + * Tag == 0 => flags == OS_LOG_TYPE + */ + if (tag != 0) { + return EINVAL; + } + + /* + * OS_LOG_TYPE are defined in libkern/os/log.h + * In userspace they are defined in libtrace/os/log.h + */ + if (flags != OS_LOG_TYPE_DEFAULT && + flags != OS_LOG_TYPE_INFO && + flags != OS_LOG_TYPE_DEBUG && + flags != OS_LOG_TYPE_ERROR && + flags != OS_LOG_TYPE_FAULT) { + return EINVAL; + } + + if (size == 0) { + return EINVAL; + } + + /* truncate to OS_LOG_DATA_MAX_SIZE */ + if (size > OS_LOG_DATA_MAX_SIZE) { + printf("%s: WARNING msg is going to be truncated from %u to %u\n", __func__, size, OS_LOG_DATA_MAX_SIZE); + size = OS_LOG_DATA_MAX_SIZE; + } + + log_msg = kalloc(size); + if (!log_msg) { + return ENOMEM; + } + + error = copyin(buffer, log_msg, size); + if (error) { + ret = EFAULT; + goto out; + } + log_msg[size - 1] = '\0'; + + /* + * This will log to dmesg and logd. + * The call will fail if the current + * process is not a driverKit process. + */ + os_log_driverKit(&ret, OS_LOG_DEFAULT, flags, "%s", log_msg); + +out: + if (log_msg != NULL) { + kfree(log_msg, size); + } + + return ret; +} + #if DEVELOPMENT || DEBUG #if CONFIG_WAITQ_DEBUG static uint64_t g_wqset_num = 0; @@ -3835,6 +3903,30 @@ SYSCTL_PROC(_kern, OID_AUTO, n_ltable_entries, CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0, sysctl_waitq_set_nelem, "I", "ltable elementis currently used"); +static int +sysctl_mpsc_test_pingpong SYSCTL_HANDLER_ARGS +{ +#pragma unused(oidp, arg1, arg2) + uint64_t value = 0; + int error; + + error = SYSCTL_IN(req, &value, sizeof(value)); + if (error) { + return error; + } + + if (error == 0 && req->newptr) { + error = mpsc_test_pingpong(value, &value); + if (error == 0) { + error = SYSCTL_OUT(req, &value, sizeof(value)); + } + } + + return error; +} +SYSCTL_PROC(_kern, OID_AUTO, mpsc_test_pingpong, CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_LOCKED, + 0, 0, sysctl_mpsc_test_pingpong, "Q", "MPSC tests: pingpong"); + #endif /* DEVELOPMENT || DEBUG */ /*Remote Time api*/ @@ -3858,7 +3950,7 @@ static int sysctl_mach_bridge_timer_enable SYSCTL_HANDLER_ARGS req->oldidx = sizeof(value); return 0; } - if (bt_init_flag) { + if (os_atomic_load(&bt_init_flag, acquire)) { if (req->newptr) { int new_value = 0; error = SYSCTL_IN(req, &new_value, sizeof(new_value)); @@ -3931,6 +4023,111 @@ SYSCTL_PROC(_machdep_remotetime, OID_AUTO, conversion_params, #endif /* CONFIG_MACH_BRIDGE_RECV_TIME */ +#if DEVELOPMENT || DEBUG +#if __AMP__ +#include +extern int32_t sysctl_get_bound_cpuid(void); +extern void sysctl_thread_bind_cpuid(int32_t cpuid); +static int +sysctl_kern_sched_thread_bind_cpu SYSCTL_HANDLER_ARGS +{ +#pragma unused(oidp, arg1, arg2) + + if (!PE_parse_boot_argn("enable_skstb", NULL, 0)) { + return ENOENT; + } + + int32_t cpuid = sysctl_get_bound_cpuid(); + + int32_t new_value; + int changed; + int error = sysctl_io_number(req, cpuid, sizeof cpuid, &new_value, &changed); + if (error) { + return error; + } + + if (changed) { + sysctl_thread_bind_cpuid(new_value); + } + + return error; +} + +SYSCTL_PROC(_kern, OID_AUTO, sched_thread_bind_cpu, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, + 0, 0, sysctl_kern_sched_thread_bind_cpu, "I", ""); + +extern char sysctl_get_bound_cluster_type(void); +extern void sysctl_thread_bind_cluster_type(char cluster_type); +static int +sysctl_kern_sched_thread_bind_cluster_type SYSCTL_HANDLER_ARGS +{ +#pragma unused(oidp, arg1, arg2) + char buff[4]; + + if (!PE_parse_boot_argn("enable_skstb", NULL, 0)) { + return ENOENT; + } + + int error = SYSCTL_IN(req, buff, 1); + if (error) { + return error; + } + char cluster_type = buff[0]; + + if (!req->newptr) { + goto out; + } + + sysctl_thread_bind_cluster_type(cluster_type); +out: + cluster_type = sysctl_get_bound_cluster_type(); + buff[0] = cluster_type; + + return SYSCTL_OUT(req, buff, 1); +} + +SYSCTL_PROC(_kern, OID_AUTO, sched_thread_bind_cluster_type, CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_LOCKED, + 0, 0, sysctl_kern_sched_thread_bind_cluster_type, "A", ""); + +extern char sysctl_get_task_cluster_type(void); +extern void sysctl_task_set_cluster_type(char cluster_type); +static int +sysctl_kern_sched_task_set_cluster_type SYSCTL_HANDLER_ARGS +{ +#pragma unused(oidp, arg1, arg2) + char buff[4]; + + if (!PE_parse_boot_argn("enable_skstsct", NULL, 0)) { + return ENOENT; + } + + int error = SYSCTL_IN(req, buff, 1); + if (error) { + return error; + } + char cluster_type = buff[0]; + + if (!req->newptr) { + goto out; + } + + sysctl_task_set_cluster_type(cluster_type); +out: + cluster_type = sysctl_get_task_cluster_type(); + buff[0] = cluster_type; + + return SYSCTL_OUT(req, buff, 1); +} + +SYSCTL_PROC(_kern, OID_AUTO, sched_task_set_cluster_type, CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_LOCKED, + 0, 0, sysctl_kern_sched_task_set_cluster_type, "A", ""); +#endif /* __AMP__ */ +#endif /* DEVELOPMENT || DEBUG */ + +extern uint32_t task_exc_guard_default; + +SYSCTL_INT(_kern, OID_AUTO, task_exc_guard_default, + CTLFLAG_RD | CTLFLAG_LOCKED, &task_exc_guard_default, 0, ""); static int @@ -4022,4 +4219,4 @@ sysctl_kern_sched_thread_set_no_smt(__unused struct sysctl_oid *oidp, __unused v SYSCTL_PROC(_kern, OID_AUTO, sched_thread_set_no_smt, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED | CTLFLAG_ANYBODY, 0, 0, sysctl_kern_sched_thread_set_no_smt, "I", ""); -#endif +#endif /* DEVELOPMENT || DEBUG */