X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/ecc0ceb4089d506a0b8d16686a95817b331af9cb..a39ff7e25e19b3a8c3020042a3872ca9ec9659f1:/bsd/kern/sys_generic.c?ds=sidebyside diff --git a/bsd/kern/sys_generic.c b/bsd/kern/sys_generic.c index 41e3d8b69..9cfbe7e91 100644 --- a/bsd/kern/sys_generic.c +++ b/bsd/kern/sys_generic.c @@ -97,6 +97,7 @@ #include #include +#include #include #include #include @@ -140,13 +141,16 @@ #include #include +#if CONFIG_MACF +#include +#endif + /* XXX should be in a header file somewhere */ void evsofree(struct socket *); void evpipefree(struct pipe *); void postpipeevent(struct pipe *, int); void postevent(struct socket *, struct sockbuf *, int); extern kern_return_t IOBSDGetPlatformUUID(__darwin_uuid_t uuid, mach_timespec_t timeoutp); -extern void delay(int); int rd_uio(struct proc *p, int fdes, uio_t uio, user_ssize_t *retval); int wr_uio(struct proc *p, struct fileproc *fp, uio_t uio, user_ssize_t *retval); @@ -160,7 +164,6 @@ __private_extern__ int dofilewrite(vfs_context_t ctx, struct fileproc *fp, __private_extern__ int preparefileread(struct proc *p, struct fileproc **fp_ret, int fd, int check_for_vnode); __private_extern__ void donefileread(struct proc *p, struct fileproc *fp_ret, int fd); - /* Conflict wait queue for when selects collide (opaque type) */ struct waitq select_conflict_queue; @@ -171,7 +174,7 @@ void select_waitq_init(void); void select_waitq_init(void) { - waitq_init(&select_conflict_queue, SYNC_POLICY_FIFO | SYNC_POLICY_DISABLE_IRQ); + waitq_init(&select_conflict_queue, SYNC_POLICY_FIFO); } #define f_flag f_fglob->fg_flag @@ -771,7 +774,7 @@ ioctl(struct proc *p, struct ioctl_args *uap, __unused int32_t *retval) boolean_t is64bit = FALSE; int tmp = 0; #define STK_PARAMS 128 - char stkbuf[STK_PARAMS]; + char stkbuf[STK_PARAMS] = {}; int fd = uap->fd; u_long com = uap->com; struct vfs_context context = *vfs_context_current(); @@ -1204,12 +1207,12 @@ select_internal(struct proc *p, struct select_nocancel_args *uap, uint64_t timeo panic("can't allocate %ld bytes for wqstate buffer", uth->uu_wqstate_sz); waitq_set_init(uth->uu_wqset, - SYNC_POLICY_FIFO|SYNC_POLICY_PREPOST|SYNC_POLICY_DISABLE_IRQ, NULL); + SYNC_POLICY_FIFO|SYNC_POLICY_PREPOST, NULL, NULL); } if (!waitq_set_is_valid(uth->uu_wqset)) waitq_set_init(uth->uu_wqset, - SYNC_POLICY_FIFO|SYNC_POLICY_PREPOST|SYNC_POLICY_DISABLE_IRQ, NULL); + SYNC_POLICY_FIFO|SYNC_POLICY_PREPOST, NULL, NULL); /* the last chunk of our buffer is an array of waitq pointers */ seldata->wqp = (uint64_t *)((char *)(uth->uu_wqset) + ALIGN(sizeof(struct waitq_set))); @@ -1691,7 +1694,7 @@ poll_nocancel(struct proc *p, struct poll_nocancel_args *uap, int32_t *retval) (nfds > p->p_rlimit[RLIMIT_NOFILE].rlim_cur && (proc_suser(p) || nfds > FD_SETSIZE))) return (EINVAL); - kq = kqueue_alloc(p); + kq = kqueue_alloc(p, 0); if (kq == NULL) return (EAGAIN); @@ -1728,7 +1731,6 @@ poll_nocancel(struct proc *p, struct poll_nocancel_args *uap, int32_t *retval) OSBitOrAtomic(P_SELECT, &p->p_flag); for (i = 0; i < nfds; i++) { short events = fds[i].events; - int kerror = 0; /* per spec, ignore fd values below zero */ if (fds[i].fd < 0) { @@ -1747,19 +1749,19 @@ poll_nocancel(struct proc *p, struct poll_nocancel_args *uap, int32_t *retval) kev.filter = EVFILT_READ; if (events & ( POLLPRI | POLLRDBAND )) kev.flags |= EV_OOBAND; - kerror = kevent_register(kq, &kev, p); + kevent_register(kq, &kev, p); } /* Handle output events */ - if (kerror == 0 && - events & ( POLLOUT | POLLWRNORM | POLLWRBAND )) { + if ((kev.flags & EV_ERROR) == 0 && + (events & ( POLLOUT | POLLWRNORM | POLLWRBAND ))) { kev.filter = EVFILT_WRITE; - kerror = kevent_register(kq, &kev, p); + kevent_register(kq, &kev, p); } /* Handle BSD extension vnode events */ - if (kerror == 0 && - events & ( POLLEXTEND | POLLATTRIB | POLLNLINK | POLLWRITE )) { + if ((kev.flags & EV_ERROR) == 0 && + (events & ( POLLEXTEND | POLLATTRIB | POLLNLINK | POLLWRITE ))) { kev.filter = EVFILT_VNODE; kev.fflags = 0; if (events & POLLEXTEND) @@ -1770,25 +1772,40 @@ poll_nocancel(struct proc *p, struct poll_nocancel_args *uap, int32_t *retval) kev.fflags |= NOTE_LINK; if (events & POLLWRITE) kev.fflags |= NOTE_WRITE; - kerror = kevent_register(kq, &kev, p); + kevent_register(kq, &kev, p); } - if (kerror != 0) { + if (kev.flags & EV_ERROR) { fds[i].revents = POLLNVAL; rfds++; } else fds[i].revents = 0; } - /* Did we have any trouble registering? */ - if (rfds > 0) + /* + * Did we have any trouble registering? + * If user space passed 0 FDs, then respect any timeout value passed. + * This is an extremely inefficient sleep. If user space passed one or + * more FDs, and we had trouble registering _all_ of them, then bail + * out. If a subset of the provided FDs failed to register, then we + * will still call the kqueue_scan function. + */ + if (nfds && (rfds == nfds)) goto done; + /* + * 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. + */ + if (rfds) + getmicrouptime(&atv); + /* 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, &atv, p); + error = kqueue_scan(kq, poll_callback, NULL, cont, NULL, &atv, p); rfds = cont->pca_rfds; done: @@ -2104,7 +2121,7 @@ selrecord(__unused struct proc *selector, struct selinfo *sip, void *s_data) return; if ((sip->si_flags & SI_INITED) == 0) { - waitq_init(&sip->si_waitq, SYNC_POLICY_FIFO | SYNC_POLICY_DISABLE_IRQ); + waitq_init(&sip->si_waitq, SYNC_POLICY_FIFO); sip->si_flags |= SI_INITED; sip->si_flags &= ~SI_CLEAR; } @@ -3098,6 +3115,14 @@ gethostuuid(struct proc *p, struct gethostuuid_args *uap, __unused int32_t *retv __darwin_uuid_t uuid_kern; /* for IOKit call */ if (!uap->spi) { +#if CONFIG_EMBEDDED +#if CONFIG_MACF + if ((error = mac_system_check_info(kauth_cred_get(), "hw.uuid")) != 0) { + /* EPERM invokes userspace upcall if present */ + return (error); + } +#endif +#endif } /* Convert the 32/64 bit timespec into a mach_timespec_t */ @@ -3159,9 +3184,11 @@ ledger(struct proc *p, struct ledger_args *args, __unused int32_t *retval) error = copyin(args->arg3, (char *)&len, sizeof (len)); else if (args->cmd == LEDGER_TEMPLATE_INFO) error = copyin(args->arg2, (char *)&len, sizeof (len)); -#ifdef LEDGER_DEBUG else if (args->cmd == LEDGER_LIMIT) +#ifdef LEDGER_DEBUG error = copyin(args->arg2, (char *)&lla, sizeof (lla)); +#else + return (EINVAL); #endif else if ((args->cmd < 0) || (args->cmd > LEDGER_MAX_CMD)) return (EINVAL); @@ -3216,7 +3243,7 @@ ledger(struct proc *p, struct ledger_args *args, __unused int32_t *retval) rval = ledger_get_task_entry_info_multiple(task, &buf, &len); proc_rele(proc); - if ((rval == 0) && (len > 0)) { + if ((rval == 0) && (len >= 0)) { sz = len * sizeof (struct ledger_entry_info); rval = copyout(buf, args->arg2, sz); kfree(buf, sz); @@ -3231,7 +3258,7 @@ ledger(struct proc *p, struct ledger_args *args, __unused int32_t *retval) int sz; rval = ledger_template_info(&buf, &len); - if ((rval == 0) && (len > 0)) { + if ((rval == 0) && (len >= 0)) { sz = len * sizeof (struct ledger_template_info); rval = copyout(buf, args->arg1, sz); kfree(buf, sz); @@ -3274,7 +3301,7 @@ telemetry(__unused struct proc *p, struct telemetry_args *args, __unused int32_t return (error); } -#if defined(DEVELOPMENT) || defined(DEBUG) +#if DEVELOPMENT || DEBUG #if CONFIG_WAITQ_DEBUG static uint64_t g_wqset_num = 0; struct g_wqset { @@ -3303,7 +3330,7 @@ static inline struct waitq_set *sysctl_get_wqset(int idx) gwqs = (struct g_wqset *)kalloc(sizeof(*gwqs)); assert(gwqs != NULL); - gwqs->wqset = waitq_set_alloc(SYNC_POLICY_FIFO|SYNC_POLICY_PREPOST|SYNC_POLICY_DISABLE_IRQ); + gwqs->wqset = waitq_set_alloc(SYNC_POLICY_FIFO|SYNC_POLICY_PREPOST, NULL); enqueue_tail(&g_wqset_list, &gwqs->link); printf("[WQ]: created new waitq set 0x%llx\n", wqset_id(gwqs->wqset)); @@ -3322,7 +3349,7 @@ static inline struct waitq *global_test_waitq(int idx) if (!g_wq_init) { g_wq_init = 1; for (int i = 0; i < MAX_GLOBAL_TEST_QUEUES; i++) - waitq_init(&g_wq[i], SYNC_POLICY_FIFO|SYNC_POLICY_DISABLE_IRQ); + waitq_init(&g_wq[i], SYNC_POLICY_FIFO); } return &g_wq[idx % MAX_GLOBAL_TEST_QUEUES]; @@ -3654,4 +3681,6 @@ SYSCTL_PROC(_kern, OID_AUTO, wqset_clear_preposts, CTLTYPE_QUAD | CTLFLAG_RW | C 0, 0, sysctl_wqset_clear_preposts, "Q", "clear preposts on given waitq set"); #endif /* CONFIG_WAITQ_DEBUG */ -#endif /* defined(DEVELOPMENT) || defined(DEBUG) */ +#endif /* DEVELOPMENT || DEBUG */ + +