| @@ -19,6 +19,7 @@ · 18 unmodified lines |
| 19 | #include <linux/nospec.h> | 19 | #include <linux/nospec.h> |
| 20 | #include <linux/posix-clock.h> | 20 | #include <linux/posix-clock.h> |
| 21 | #include <linux/posix-timers.h> | 21 | #include <linux/posix-timers.h> |
| | 22 | #include <linux/prctl.h> |
| 22 | #include <linux/sched/task.h> | 23 | #include <linux/sched/task.h> |
| 23 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
| 24 | #include <linux/syscalls.h> | 25 | #include <linux/syscalls.h> |
| @@ -57,6 +58,8 @@ static const struct k_clock * const posix_clocks[]; · 32 unmodified lines |
| 57 | static const struct k_clock *clockid_to_kclock(const clockid_t id); | 58 | static const struct k_clock *clockid_to_kclock(const clockid_t id); |
| 58 | static const struct k_clock clock_realtime, clock_monotonic; | 59 | static const struct k_clock clock_realtime, clock_monotonic; |
| 59 | | 60 | |
| | 61 | #define TIMER_ANY_ID INT_MIN |
| | 62 | |
| 60 | /* SIGEV_THREAD_ID cannot share a bit with the other SIGEV values. */ | 63 | /* SIGEV_THREAD_ID cannot share a bit with the other SIGEV values. */ |
| 61 | #if SIGEV_THREAD_ID != (SIGEV_THREAD_ID & \ | 64 | #if SIGEV_THREAD_ID != (SIGEV_THREAD_ID & \ |
| 62 | ~(SIGEV_SIGNAL | SIGEV_NONE | SIGEV_THREAD)) | 65 | ~(SIGEV_SIGNAL | SIGEV_NONE | SIGEV_THREAD)) |
| @@ -128,38 +131,60 @@ static bool posix_timer_hashed(struct timer_hash_bucket *bucket, struct signal_s · 65 unmodified lines |
| 128 | return false; | 131 | return false; |
| 129 | } | 132 | } |
| 130 | | 133 | |
| 131 | static int posix_timer_add(struct k_itimer *timer) | 134 | static bool posix_timer_add_at(struct k_itimer *timer, struct signal_struct *sig, unsigned int id) |
| | 135 | { |
| | 136 | struct timer_hash_bucket *bucket = hash_bucket(sig, id); |
| | 137 | |
| | 138 | scoped_guard (spinlock, &bucket->lock) { |
| | 139 | /* |
| | 140 | * Validate under the lock as this could have raced against |
| | 141 | * another thread ending up with the same ID, which is |
| | 142 | * highly unlikely, but possible. |
| | 143 | */ |
| | 144 | if (!posix_timer_hashed(bucket, sig, id)) { |
| | 145 | /* |
| | 146 | * Set the timer ID and the signal pointer to make |
| | 147 | * it identifiable in the hash table. The signal |
| | 148 | * pointer has bit 0 set to indicate that it is not |
| | 149 | * yet fully initialized. posix_timer_hashed() |
| | 150 | * masks this bit out, but the syscall lookup fails |
| | 151 | * to match due to it being set. This guarantees |
| | 152 | * that there can't be duplicate timer IDs handed |
| | 153 | * out. |
| | 154 | */ |
| | 155 | timer->it_id = (timer_t)id; |
| | 156 | timer->it_signal = (struct signal_struct *)((unsigned long)sig | 1UL); |
| | 157 | hlist_add_head_rcu(&timer->t_hash, &bucket->head); |
| | 158 | return true; |
| | 159 | } |
| | 160 | } |
| | 161 | return false; |
| | 162 | } |
| | 163 | |
| | 164 | static int posix_timer_add(struct k_itimer *timer, int req_id) |
| 132 | { | 165 | { |
| 133 | struct signal_struct *sig = current->signal; | 166 | struct signal_struct *sig = current->signal; |
| 134 | | 167 | |
| | 168 | if (unlikely(req_id != TIMER_ANY_ID)) { |
| | 169 | if (!posix_timer_add_at(timer, sig, req_id)) |
| | 170 | return -EBUSY; |
| | 171 | |
| | 172 | /* |
| | 173 | * Move the ID counter past the requested ID, so that after |
| | 174 | * switching back to normal mode the IDs are outside of the |
| | 175 | * exact allocated region. That avoids ID collisions on the |
| | 176 | * next regular timer_create() invocations. |
| | 177 | */ |
| | 178 | atomic_set(&sig->next_posix_timer_id, req_id + 1); |
| | 179 | return req_id; |
| | 180 | } |
| | 181 | |
| 135 | for (unsigned int cnt = 0; cnt <= INT_MAX; cnt++) { | 182 | for (unsigned int cnt = 0; cnt <= INT_MAX; cnt++) { |
| 136 | /* Get the next timer ID and clamp it to positive space */ | 183 | /* Get the next timer ID and clamp it to positive space */ |
| 137 | unsigned int id = atomic_fetch_inc(&sig->next_posix_timer_id) & INT_MAX; | 184 | unsigned int id = atomic_fetch_inc(&sig->next_posix_timer_id) & INT_MAX; |
| 138 | struct timer_hash_bucket *bucket = hash_bucket(sig, id); | | |
| 139 | | 185 | |
| 140 | scoped_guard (spinlock, &bucket->lock) { | 186 | if (posix_timer_add_at(timer, sig, id)) |
| 141 | /* | 187 | return id; |
| 142 | * Validate under the lock as this could have raced | | |
| 143 | * against another thread ending up with the same | | |
| 144 | * ID, which is highly unlikely, but possible. | | |
| 145 | */ | | |
| 146 | if (!posix_timer_hashed(bucket, sig, id)) { | | |
| 147 | /* | | |
| 148 | * Set the timer ID and the signal pointer to make | | |
| 149 | * it identifiable in the hash table. The signal | | |
| 150 | * pointer has bit 0 set to indicate that it is not | | |
| 151 | * yet fully initialized. posix_timer_hashed() | | |
| 152 | * masks this bit out, but the syscall lookup fails | | |
| 153 | * to match due to it being set. This guarantees | | |
| 154 | * that there can't be duplicate timer IDs handed | | |
| 155 | * out. | | |
| 156 | */ | | |
| 157 | timer->it_id = (timer_t)id; | | |
| 158 | timer->it_signal = (struct signal_struct *)((unsigned long)sig | 1UL); | | |
| 159 | hlist_add_head_rcu(&timer->t_hash, &bucket->head); | | |
| 160 | return id; | | |
| 161 | } | | |
| 162 | } | | |
| 163 | cond_resched(); | 188 | cond_resched(); |
| 164 | } | 189 | } |
| 165 | /* POSIX return code when no timer ID could be allocated */ | 190 | /* POSIX return code when no timer ID could be allocated */ |
| @@ -364,6 +389,21 @@ static enum hrtimer_restart posix_timer_fn(struct hrtimer *timer) · 198 unmodified lines |
| 364 | return HRTIMER_NORESTART; | 389 | return HRTIMER_NORESTART; |
| 365 | } | 390 | } |
| 366 | | 391 | |
| | 392 | long posixtimer_create_prctl(unsigned long ctrl) |
| | 393 | { |
| | 394 | switch (ctrl) { |
| | 395 | case PR_TIMER_CREATE_RESTORE_IDS_OFF: |
| | 396 | current->signal->timer_create_restore_ids = 0; |
| | 397 | return 0; |
| | 398 | case PR_TIMER_CREATE_RESTORE_IDS_ON: |
| | 399 | current->signal->timer_create_restore_ids = 1; |
| | 400 | return 0; |
| | 401 | case PR_TIMER_CREATE_RESTORE_IDS_GET: |
| | 402 | return current->signal->timer_create_restore_ids; |
| | 403 | } |
| | 404 | return -EINVAL; |
| | 405 | } |
| | 406 | |
| 367 | static struct pid *good_sigevent(sigevent_t * event) | 407 | static struct pid *good_sigevent(sigevent_t * event) |
| 368 | { | 408 | { |
| 369 | struct pid *pid = task_tgid(current); | 409 | struct pid *pid = task_tgid(current); |
| @@ -435,6 +475,7 @@ static int do_timer_create(clockid_t which_clock, struct sigevent *event, · 65 unmodified lines |
| 435 | timer_t __user *created_timer_id) | 475 | timer_t __user *created_timer_id) |
| 436 | { | 476 | { |
| 437 | const struct k_clock *kc = clockid_to_kclock(which_clock); | 477 | const struct k_clock *kc = clockid_to_kclock(which_clock); |
| | 478 | timer_t req_id = TIMER_ANY_ID; |
| 438 | struct k_itimer *new_timer; | 479 | struct k_itimer *new_timer; |
| 439 | int error, new_timer_id; | 480 | int error, new_timer_id; |
| 440 | | 481 | |
| @@ -449,11 +490,20 @@ static int do_timer_create(clockid_t which_clock, struct sigevent *event, · 8 unmodified lines |
| 449 | | 490 | |
| 450 | spin_lock_init(&new_timer->it_lock); | 491 | spin_lock_init(&new_timer->it_lock); |
| 451 | | 492 | |
| | 493 | /* Special case for CRIU to restore timers with a given timer ID. */ |
| | 494 | if (unlikely(current->signal->timer_create_restore_ids)) { |
| | 495 | if (copy_from_user(&req_id, created_timer_id, sizeof(req_id))) |
| | 496 | return -EFAULT; |
| | 497 | /* Valid IDs are 0..INT_MAX */ |
| | 498 | if ((unsigned int)req_id > INT_MAX) |
| | 499 | return -EINVAL; |
| | 500 | } |
| | 501 | |
| 452 | /* | 502 | /* |
| 453 | * Add the timer to the hash table. The timer is not yet valid | 503 | * Add the timer to the hash table. The timer is not yet valid |
| 454 | * after insertion, but has a unique ID allocated. | 504 | * after insertion, but has a unique ID allocated. |
| 455 | */ | 505 | */ |
| 456 | new_timer_id = posix_timer_add(new_timer); | 506 | new_timer_id = posix_timer_add(new_timer, req_id); |
| 457 | if (new_timer_id < 0) { | 507 | if (new_timer_id < 0) { |
| 458 | posixtimer_free_timer(new_timer); | 508 | posixtimer_free_timer(new_timer); |
| 459 | return new_timer_id; | 509 | return new_timer_id; |
| @@ -1041,6 +1091,9 @@ void exit_itimers(struct task_struct *tsk) · 581 unmodified lines |
| 1041 | struct hlist_node *next; | 1091 | struct hlist_node *next; |
| 1042 | struct k_itimer *timer; | 1092 | struct k_itimer *timer; |
| 1043 | | 1093 | |
| | 1094 | /* Clear restore mode for exec() */ |
| | 1095 | tsk->signal->timer_create_restore_ids = 0; |
| | 1096 | |
| 1044 | if (hlist_empty(&tsk->signal->posix_timers)) | 1097 | if (hlist_empty(&tsk->signal->posix_timers)) |
| 1045 | return; | 1098 | return; |
| 1046 | | 1099 | |