- int error, s;
- extern simple_lock_data_t tz_slock;
-
- if (error = suser(p->p_ucred, &p->p_acflag))
- return (error);
- /* Verify all parameters before changing time. */
- if (uap->tv && (error = copyin((caddr_t)uap->tv,
- (caddr_t)&atv, sizeof(atv))))
- return (error);
- if (uap->tzp && (error = copyin((caddr_t)uap->tzp,
- (caddr_t)&atz, sizeof(atz))))
- return (error);
- if (uap->tv)
+ int error;
+
+ bzero(&atv, sizeof(atv));
+
+ /* Check that this task is entitled to set the time or it is root */
+ if (!IOTaskHasEntitlement(current_task(), SETTIME_ENTITLEMENT)) {
+#if CONFIG_MACF
+ error = mac_system_check_settime(kauth_cred_get());
+ if (error) {
+ return error;
+ }
+#endif
+#if defined(XNU_TARGET_OS_OSX)
+ if ((error = suser(kauth_cred_get(), &p->p_acflag))) {
+ return error;
+ }
+#endif
+ }
+
+ /* Verify all parameters before changing time */
+ if (uap->tv) {
+ if (IS_64BIT_PROCESS(p)) {
+ struct user64_timeval user_atv;
+ error = copyin(uap->tv, &user_atv, sizeof(user_atv));
+ atv.tv_sec = (__darwin_time_t)user_atv.tv_sec;
+ atv.tv_usec = user_atv.tv_usec;
+ } else {
+ struct user32_timeval user_atv;
+ error = copyin(uap->tv, &user_atv, sizeof(user_atv));
+ atv.tv_sec = user_atv.tv_sec;
+ atv.tv_usec = user_atv.tv_usec;
+ }
+ if (error) {
+ return error;
+ }
+ }
+ if (uap->tzp && (error = copyin(uap->tzp, (caddr_t)&atz, sizeof(atz)))) {
+ return error;
+ }
+ if (uap->tv) {
+ /* only positive values of sec/usec are accepted */
+ if (atv.tv_sec < 0 || atv.tv_usec < 0) {
+ return EPERM;
+ }
+ if (!timeval_fixusec(&atv)) {
+ return EPERM;
+ }