X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/b226f5e54a60dc81db17b1260381d7dbfea3cdf1..0a7de7458d150b5d4dffc935ba399be265ef0a1a:/bsd/kern/sys_work_interval.c diff --git a/bsd/kern/sys_work_interval.c b/bsd/kern/sys_work_interval.c index bbfdd5e61..203086a1b 100644 --- a/bsd/kern/sys_work_interval.c +++ b/bsd/kern/sys_work_interval.c @@ -40,7 +40,7 @@ int work_interval_ctl(__unused proc_t p, struct work_interval_ctl_args *uap, - __unused int32_t *retval) + __unused int32_t *retval) { uint32_t operation = uap->operation; int error = 0; @@ -51,117 +51,128 @@ work_interval_ctl(__unused proc_t p, struct work_interval_ctl_args *uap, struct kern_work_interval_create_args create_args; switch (operation) { - case WORK_INTERVAL_OPERATION_CREATE: - return ENOTSUP; - case WORK_INTERVAL_OPERATION_CREATE2: - if (uap->arg == USER_ADDR_NULL || uap->work_interval_id != 0) - return EINVAL; - if (uap->len < sizeof(create_params)) - return EINVAL; - - if ((error = copyin(uap->arg, &create_params, sizeof(create_params)))) - return error; - - if ((error = priv_check_cred(kauth_cred_get(), PRIV_WORK_INTERVAL, 0)) != 0) { - return error; - } - - create_args = (struct kern_work_interval_create_args) { - .wica_id = create_params.wicp_id, - .wica_port = create_params.wicp_port, - .wica_create_flags = create_params.wicp_create_flags, - }; - - kret = kern_work_interval_create(current_thread(), &create_args); - - /* thread already has a work interval */ - if (kret == KERN_FAILURE) - return EALREADY; - - /* port copyout failed */ - if (kret == KERN_RESOURCE_SHORTAGE) - return ENOMEM; - - /* some other failure */ - if (kret != KERN_SUCCESS) - return EINVAL; - - create_params = (struct work_interval_create_params) { - .wicp_id = create_args.wica_id, - .wicp_port = create_args.wica_port, - .wicp_create_flags = create_args.wica_create_flags, - }; - - if ((error = copyout(&create_params, uap->arg, sizeof(create_params)))) { - kern_work_interval_destroy(current_thread(), create_args.wica_id); - return error; - } - break; - case WORK_INTERVAL_OPERATION_DESTROY: - if (uap->arg != USER_ADDR_NULL || uap->work_interval_id == 0) { - return EINVAL; - } - - /* - * No privilege check, we assume a previous WORK_INTERVAL_OPERATION_CREATE - * operation would have allocated a work interval ID for the current - * thread, which the scheduler will validate. - */ - kret = kern_work_interval_destroy(current_thread(), uap->work_interval_id); - if (kret != KERN_SUCCESS) - return EINVAL; - - break; - case WORK_INTERVAL_OPERATION_NOTIFY: - if (uap->arg == USER_ADDR_NULL || uap->work_interval_id == 0) - return EINVAL; - - if (uap->len < sizeof(notification)) - return EINVAL; - - /* - * No privilege check, we assume a previous WORK_INTERVAL_OPERATION_CREATE - * operation would have allocated a work interval ID for the current - * thread, which the scheduler will validate. - */ - if ((error = copyin(uap->arg, ¬ification, sizeof(notification)))) - return error; - - struct kern_work_interval_args kwi_args = { - .work_interval_id = uap->work_interval_id, - .start = notification.start, - .finish = notification.finish, - .deadline = notification.deadline, - .next_start = notification.next_start, - .notify_flags = notification.notify_flags, - .create_flags = notification.create_flags, - }; - - kret = kern_work_interval_notify(current_thread(), &kwi_args); - if (kret != KERN_SUCCESS) - return EINVAL; - - break; - case WORK_INTERVAL_OPERATION_JOIN: - if (uap->arg != USER_ADDR_NULL) { - return EINVAL; - } - - /* - * No privilege check, because the work interval port - * is a capability. - */ - kret = kern_work_interval_join(current_thread(), - (mach_port_name_t)uap->work_interval_id); - if (kret != KERN_SUCCESS) - return EINVAL; - - break; - - default: - return ENOTSUP; + case WORK_INTERVAL_OPERATION_CREATE: + return ENOTSUP; + case WORK_INTERVAL_OPERATION_CREATE2: + if (uap->arg == USER_ADDR_NULL || uap->work_interval_id != 0) { + return EINVAL; + } + if (uap->len < sizeof(create_params)) { + return EINVAL; + } + + if ((error = copyin(uap->arg, &create_params, sizeof(create_params)))) { + return error; + } + + if ((error = priv_check_cred(kauth_cred_get(), PRIV_WORK_INTERVAL, 0)) != 0) { + return error; + } + + create_args = (struct kern_work_interval_create_args) { + .wica_id = create_params.wicp_id, + .wica_port = create_params.wicp_port, + .wica_create_flags = create_params.wicp_create_flags, + }; + + kret = kern_work_interval_create(current_thread(), &create_args); + + /* thread already has a work interval */ + if (kret == KERN_FAILURE) { + return EALREADY; + } + + /* port copyout failed */ + if (kret == KERN_RESOURCE_SHORTAGE) { + return ENOMEM; + } + + /* some other failure */ + if (kret != KERN_SUCCESS) { + return EINVAL; + } + + create_params = (struct work_interval_create_params) { + .wicp_id = create_args.wica_id, + .wicp_port = create_args.wica_port, + .wicp_create_flags = create_args.wica_create_flags, + }; + + if ((error = copyout(&create_params, uap->arg, sizeof(create_params)))) { + kern_work_interval_destroy(current_thread(), create_args.wica_id); + return error; + } + break; + case WORK_INTERVAL_OPERATION_DESTROY: + if (uap->arg != USER_ADDR_NULL || uap->work_interval_id == 0) { + return EINVAL; + } + + /* + * No privilege check, we assume a previous WORK_INTERVAL_OPERATION_CREATE + * operation would have allocated a work interval ID for the current + * thread, which the scheduler will validate. + */ + kret = kern_work_interval_destroy(current_thread(), uap->work_interval_id); + if (kret != KERN_SUCCESS) { + return EINVAL; + } + + break; + case WORK_INTERVAL_OPERATION_NOTIFY: + if (uap->arg == USER_ADDR_NULL || uap->work_interval_id == 0) { + return EINVAL; + } + + if (uap->len < sizeof(notification)) { + return EINVAL; + } + + /* + * No privilege check, we assume a previous WORK_INTERVAL_OPERATION_CREATE + * operation would have allocated a work interval ID for the current + * thread, which the scheduler will validate. + */ + if ((error = copyin(uap->arg, ¬ification, sizeof(notification)))) { + return error; + } + + struct kern_work_interval_args kwi_args = { + .work_interval_id = uap->work_interval_id, + .start = notification.start, + .finish = notification.finish, + .deadline = notification.deadline, + .next_start = notification.next_start, + .notify_flags = notification.notify_flags, + .create_flags = notification.create_flags, + }; + + kret = kern_work_interval_notify(current_thread(), &kwi_args); + if (kret != KERN_SUCCESS) { + return EINVAL; + } + + break; + case WORK_INTERVAL_OPERATION_JOIN: + if (uap->arg != USER_ADDR_NULL) { + return EINVAL; + } + + /* + * No privilege check, because the work interval port + * is a capability. + */ + kret = kern_work_interval_join(current_thread(), + (mach_port_name_t)uap->work_interval_id); + if (kret != KERN_SUCCESS) { + return EINVAL; + } + + break; + + default: + return ENOTSUP; } - return (error); + return error; } -