History

ucounts: Fix signal ucount refcounting

In commit fda31c50292a ("signal: avoid double atomic counter increments for user accounting") Linus made a clever optimization to how rlimits and the struct user_struct. Unfortunately that optimization does not work in the obvious way when moved to nested rlimits. The problem is that the last decrement of the per user namespace per user sigpending counter might also be the last decrement of the sigpending counter in the parent user namespace as well. Which means that simply freeing the leaf ucount in __free_sigqueue is not enough. Maintain the optimization and handle the tricky cases by introducing inc_rlimit_get_ucounts and dec_rlimit_put_ucounts. By moving the entire optimization into functions that perform all of the work it becomes possible to ensure that every level is handled properly. The new function inc_rlimit_get_ucounts returns 0 on failure to increment the ucount. This is different than inc_rlimit_ucounts which increments the ucounts and returns LONG_MAX if the ucount counter has exceeded it's maximum or it wrapped (to indicate the counter needs to decremented). I wish we had a single user to account all pending signals to across all of the threads of a process so this complexity was not necessary

Eric W. Biederman committed 5 years ago

Commit 15bc01e1 parent 7d2a07b3 files · +57 −19Browse files

Unified · Split

3 files
  1. include/linux/user_namespace.h +2 −0
  2. kernel/signal.c +6 −19
  3. kernel/ucount.c +49 −0
include/linux/user_namespace.h+2−0
@@ -127,6 +127,8 @@ static inline long get_ucounts_value(struct ucounts *ucounts, enum ucount_type t · 126 unmodified lines
127 127
128long inc_rlimit_ucounts(struct ucounts *ucounts, enum ucount_type type, long v);128long inc_rlimit_ucounts(struct ucounts *ucounts, enum ucount_type type, long v);
129bool dec_rlimit_ucounts(struct ucounts *ucounts, enum ucount_type type, long v);129bool dec_rlimit_ucounts(struct ucounts *ucounts, enum ucount_type type, long v);
130long inc_rlimit_get_ucounts(struct ucounts *ucounts, enum ucount_type type);
131void dec_rlimit_put_ucounts(struct ucounts *ucounts, enum ucount_type type);
130bool is_ucounts_overlimit(struct ucounts *ucounts, enum ucount_type type, unsigned long max);132bool is_ucounts_overlimit(struct ucounts *ucounts, enum ucount_type type, unsigned long max);
131 133
132static inline void set_rlimit_ucount_max(struct user_namespace *ns,134static inline void set_rlimit_ucount_max(struct user_namespace *ns,
kernel/signal.c+6−19
@@ -425,22 +425,10 @@ __sigqueue_alloc(int sig, struct task_struct *t, gfp_t gfp_flags, · 424 unmodified lines
425 */425 */
426 rcu_read_lock();426 rcu_read_lock();
427 ucounts = task_ucounts(t);427 ucounts = task_ucounts(t);
428 sigpending = inc_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_SIGPENDING, 1);428 sigpending = inc_rlimit_get_ucounts(ucounts, UCOUNT_RLIMIT_SIGPENDING);
429 switch (sigpending) {
430 case 1:
431 if (likely(get_ucounts(ucounts)))
432 break;
433 fallthrough;
434 case LONG_MAX:
435 /*
436 * we need to decrease the ucount in the userns tree on any
437 * failure to avoid counts leaking.
438 */
439 dec_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_SIGPENDING, 1);
440 rcu_read_unlock();
441 return NULL;
442 }
443 rcu_read_unlock();429 rcu_read_unlock();
430 if (!sigpending)
431 return NULL;
444 432
445 if (override_rlimit || likely(sigpending <= task_rlimit(t, RLIMIT_SIGPENDING))) {433 if (override_rlimit || likely(sigpending <= task_rlimit(t, RLIMIT_SIGPENDING))) {
446 q = kmem_cache_alloc(sigqueue_cachep, gfp_flags);434 q = kmem_cache_alloc(sigqueue_cachep, gfp_flags);
@@ -449,8 +437,7 @@ __sigqueue_alloc(int sig, struct task_struct *t, gfp_t gfp_flags, · 2 unmodified lines
449 }437 }
450 438
451 if (unlikely(q == NULL)) {439 if (unlikely(q == NULL)) {
452 if (dec_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_SIGPENDING, 1))440 dec_rlimit_put_ucounts(ucounts, UCOUNT_RLIMIT_SIGPENDING);
453 put_ucounts(ucounts);
454 } else {441 } else {
455 INIT_LIST_HEAD(&q->list);442 INIT_LIST_HEAD(&q->list);
456 q->flags = sigqueue_flags;443 q->flags = sigqueue_flags;
@@ -463,8 +450,8 @@ static void __sigqueue_free(struct sigqueue *q) · 6 unmodified lines
463{450{
464 if (q->flags & SIGQUEUE_PREALLOC)451 if (q->flags & SIGQUEUE_PREALLOC)
465 return;452 return;
466 if (q->ucounts && dec_rlimit_ucounts(q->ucounts, UCOUNT_RLIMIT_SIGPENDING, 1)) {453 if (q->ucounts) {
467 put_ucounts(q->ucounts);454 dec_rlimit_put_ucounts(q->ucounts, UCOUNT_RLIMIT_SIGPENDING);
468 q->ucounts = NULL;455 q->ucounts = NULL;
469 }456 }
470 kmem_cache_free(sigqueue_cachep, q);457 kmem_cache_free(sigqueue_cachep, q);
kernel/ucount.c+49−0
@@ -284,6 +284,55 @@ bool dec_rlimit_ucounts(struct ucounts *ucounts, enum ucount_type type, long v) · 283 unmodified lines
284 return (new == 0);284 return (new == 0);
285}285}
286 286
287static void do_dec_rlimit_put_ucounts(struct ucounts *ucounts,
288 struct ucounts *last, enum ucount_type type)
289{
290 struct ucounts *iter, *next;
291 for (iter = ucounts; iter != last; iter = next) {
292 long dec = atomic_long_add_return(-1, &iter->ucount[type]);
293 WARN_ON_ONCE(dec < 0);
294 next = iter->ns->ucounts;
295 if (dec == 0)
296 put_ucounts(iter);
297 }
298}
299
300void dec_rlimit_put_ucounts(struct ucounts *ucounts, enum ucount_type type)
301{
302 do_dec_rlimit_put_ucounts(ucounts, NULL, type);
303}
304
305long inc_rlimit_get_ucounts(struct ucounts *ucounts, enum ucount_type type)
306{
307 /* Caller must hold a reference to ucounts */
308 struct ucounts *iter;
309 long dec, ret = 0;
310
311 for (iter = ucounts; iter; iter = iter->ns->ucounts) {
312 long max = READ_ONCE(iter->ns->ucount_max[type]);
313 long new = atomic_long_add_return(1, &iter->ucount[type]);
314 if (new < 0 || new > max)
315 goto unwind;
316 if (iter == ucounts)
317 ret = new;
318 /*
319 * Grab an extra ucount reference for the caller when
320 * the rlimit count was previously 0.
321 */
322 if (new != 1)
323 continue;
324 if (!get_ucounts(iter))
325 goto dec_unwind;
326 }
327 return ret;
328dec_unwind:
329 dec = atomic_long_add_return(-1, &iter->ucount[type]);
330 WARN_ON_ONCE(dec < 0);
331unwind:
332 do_dec_rlimit_put_ucounts(ucounts, iter, type);
333 return 0;
334}
335
287bool is_ucounts_overlimit(struct ucounts *ucounts, enum ucount_type type, unsigned long max)336bool is_ucounts_overlimit(struct ucounts *ucounts, enum ucount_type type, unsigned long max)
288{337{
289 struct ucounts *iter;338 struct ucounts *iter;