History

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace

Pull user namespace rlimit handling update from Eric Biederman: "This is the work mainly by Alexey Gladkov to limit rlimits to the rlimits of the user that created a user namespace, and to allow users to have stricter limits on the resources created within a user namespace." * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace: cred: add missing return error code when set_cred_ucounts() failed ucounts: Silence warning in dec_rlimit_ucounts ucounts: Set ucount_max to the largest positive value the type can hold kselftests: Add test to check for rlimit changes in different user namespaces Reimplement RLIMIT_MEMLOCK on top of ucounts Reimplement RLIMIT_SIGPENDING on top of ucounts Reimplement RLIMIT_MSGQUEUE on top of ucounts Reimplement RLIMIT_NPROC on top of ucounts Use atomic_t for ucounts reference counting Add a reference to ucounts for each cred Increase size of ucounts to atomic_long_t

Linus Torvalds committed 5 years ago

Commit c54b2452 parents e17c120 5e6b8a529 files · +468 −127Browse files

Showing the changes to kernel (8 of 29 files). Show all

Unified · Split

8 files
  1. kernel/cred.c +46 −5
  2. kernel/exit.c +1 −1
  3. kernel/fork.c +14 −4
  4. kernel/signal.c +13 −12
  5. kernel/sys.c +13 −1
  6. kernel/ucount.c +91 −25
  7. kernel/user.c +0 −3
  8. kernel/user_namespace.c +8 −1
kernel/cred.c+46−5
@@ -60,6 +60,7 @@ struct cred init_cred = { · 59 unmodified lines
60 .user = INIT_USER,60 .user = INIT_USER,
61 .user_ns = &init_user_ns,61 .user_ns = &init_user_ns,
62 .group_info = &init_groups,62 .group_info = &init_groups,
63 .ucounts = &init_ucounts,
63};64};
64 65
65static inline void set_cred_subscribers(struct cred *cred, int n)66static inline void set_cred_subscribers(struct cred *cred, int n)
@@ -119,6 +120,8 @@ static void put_cred_rcu(struct rcu_head *rcu) · 53 unmodified lines
119 if (cred->group_info)120 if (cred->group_info)
120 put_group_info(cred->group_info);121 put_group_info(cred->group_info);
121 free_uid(cred->user);122 free_uid(cred->user);
123 if (cred->ucounts)
124 put_ucounts(cred->ucounts);
122 put_user_ns(cred->user_ns);125 put_user_ns(cred->user_ns);
123 kmem_cache_free(cred_jar, cred);126 kmem_cache_free(cred_jar, cred);
124}127}
@@ -222,6 +225,7 @@ struct cred *cred_alloc_blank(void) · 97 unmodified lines
222#ifdef CONFIG_DEBUG_CREDENTIALS225#ifdef CONFIG_DEBUG_CREDENTIALS
223 new->magic = CRED_MAGIC;226 new->magic = CRED_MAGIC;
224#endif227#endif
228 new->ucounts = get_ucounts(&init_ucounts);
225 229
226 if (security_cred_alloc_blank(new, GFP_KERNEL_ACCOUNT) < 0)230 if (security_cred_alloc_blank(new, GFP_KERNEL_ACCOUNT) < 0)
227 goto error;231 goto error;
@@ -284,6 +288,11 @@ struct cred *prepare_creds(void) · 56 unmodified lines
284 288
285 if (security_prepare_creds(new, old, GFP_KERNEL_ACCOUNT) < 0)289 if (security_prepare_creds(new, old, GFP_KERNEL_ACCOUNT) < 0)
286 goto error;290 goto error;
291
292 new->ucounts = get_ucounts(new->ucounts);
293 if (!new->ucounts)
294 goto error;
295
287 validate_creds(new);296 validate_creds(new);
288 return new;297 return new;
289 298
@@ -351,7 +360,7 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) · 61 unmodified lines
351 kdebug("share_creds(%p{%d,%d})",360 kdebug("share_creds(%p{%d,%d})",
352 p->cred, atomic_read(&p->cred->usage),361 p->cred, atomic_read(&p->cred->usage),
353 read_cred_subscribers(p->cred));362 read_cred_subscribers(p->cred));
354 atomic_inc(&p->cred->user->processes);363 inc_rlimit_ucounts(task_ucounts(p), UCOUNT_RLIMIT_NPROC, 1);
355 return 0;364 return 0;
356 }365 }
357 366
@@ -363,6 +372,9 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) · 5 unmodified lines
363 ret = create_user_ns(new);372 ret = create_user_ns(new);
364 if (ret < 0)373 if (ret < 0)
365 goto error_put;374 goto error_put;
375 ret = set_cred_ucounts(new);
376 if (ret < 0)
377 goto error_put;
366 }378 }
367 379
368#ifdef CONFIG_KEYS380#ifdef CONFIG_KEYS
@@ -384,8 +396,8 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) · 15 unmodified lines
384 }396 }
385#endif397#endif
386 398
387 atomic_inc(&new->user->processes);
388 p->cred = p->real_cred = get_cred(new);399 p->cred = p->real_cred = get_cred(new);
400 inc_rlimit_ucounts(task_ucounts(p), UCOUNT_RLIMIT_NPROC, 1);
389 alter_cred_subscribers(new, 2);401 alter_cred_subscribers(new, 2);
390 validate_creds(new);402 validate_creds(new);
391 return 0;403 return 0;
@@ -485,12 +497,12 @@ int commit_creds(struct cred *new) · 93 unmodified lines
485 * in set_user().497 * in set_user().
486 */498 */
487 alter_cred_subscribers(new, 2);499 alter_cred_subscribers(new, 2);
488 if (new->user != old->user)500 if (new->user != old->user || new->user_ns != old->user_ns)
489 atomic_inc(&new->user->processes);501 inc_rlimit_ucounts(new->ucounts, UCOUNT_RLIMIT_NPROC, 1);
490 rcu_assign_pointer(task->real_cred, new);502 rcu_assign_pointer(task->real_cred, new);
491 rcu_assign_pointer(task->cred, new);503 rcu_assign_pointer(task->cred, new);
492 if (new->user != old->user)504 if (new->user != old->user)
493 atomic_dec(&old->user->processes);505 dec_rlimit_ucounts(old->ucounts, UCOUNT_RLIMIT_NPROC, 1);
494 alter_cred_subscribers(old, -2);506 alter_cred_subscribers(old, -2);
495 507
496 /* send notifications */508 /* send notifications */
@@ -653,6 +665,31 @@ int cred_fscmp(const struct cred *a, const struct cred *b) · 156 unmodified lines
653}665}
654EXPORT_SYMBOL(cred_fscmp);666EXPORT_SYMBOL(cred_fscmp);
655 667
668int set_cred_ucounts(struct cred *new)
669{
670 struct task_struct *task = current;
671 const struct cred *old = task->real_cred;
672 struct ucounts *old_ucounts = new->ucounts;
673
674 if (new->user == old->user && new->user_ns == old->user_ns)
675 return 0;
676
677 /*
678 * This optimization is needed because alloc_ucounts() uses locks
679 * for table lookups.
680 */
681 if (old_ucounts && old_ucounts->ns == new->user_ns && uid_eq(old_ucounts->uid, new->euid))
682 return 0;
683
684 if (!(new->ucounts = alloc_ucounts(new->user_ns, new->euid)))
685 return -EAGAIN;
686
687 if (old_ucounts)
688 put_ucounts(old_ucounts);
689
690 return 0;
691}
692
656/*693/*
657 * initialise the credentials stuff694 * initialise the credentials stuff
658 */695 */
@@ -719,6 +756,10 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon) · 60 unmodified lines
719 if (security_prepare_creds(new, old, GFP_KERNEL_ACCOUNT) < 0)756 if (security_prepare_creds(new, old, GFP_KERNEL_ACCOUNT) < 0)
720 goto error;757 goto error;
721 758
759 new->ucounts = get_ucounts(new->ucounts);
760 if (!new->ucounts)
761 goto error;
762
722 put_cred(old);763 put_cred(old);
723 validate_creds(new);764 validate_creds(new);
724 return new;765 return new;
kernel/exit.c+1−1
@@ -188,7 +188,7 @@ repeat: · 187 unmodified lines
188 /* don't need to get the RCU readlock here - the process is dead and188 /* don't need to get the RCU readlock here - the process is dead and
189 * can't be modifying its own credentials. But shut RCU-lockdep up */189 * can't be modifying its own credentials. But shut RCU-lockdep up */
190 rcu_read_lock();190 rcu_read_lock();
191 atomic_dec(&__task_cred(p)->user->processes);191 dec_rlimit_ucounts(task_ucounts(p), UCOUNT_RLIMIT_NPROC, 1);
192 rcu_read_unlock();192 rcu_read_unlock();
193 193
194 cgroup_release(p);194 cgroup_release(p);
kernel/fork.c+14−4
@@ -825,9 +825,14 @@ void __init fork_init(void) · 824 unmodified lines
825 init_task.signal->rlim[RLIMIT_SIGPENDING] =825 init_task.signal->rlim[RLIMIT_SIGPENDING] =
826 init_task.signal->rlim[RLIMIT_NPROC];826 init_task.signal->rlim[RLIMIT_NPROC];
827 827
828 for (i = 0; i < UCOUNT_COUNTS; i++)828 for (i = 0; i < MAX_PER_NAMESPACE_UCOUNTS; i++)
829 init_user_ns.ucount_max[i] = max_threads/2;829 init_user_ns.ucount_max[i] = max_threads/2;
830 830
831 set_rlimit_ucount_max(&init_user_ns, UCOUNT_RLIMIT_NPROC, task_rlimit(&init_task, RLIMIT_NPROC));
832 set_rlimit_ucount_max(&init_user_ns, UCOUNT_RLIMIT_MSGQUEUE, task_rlimit(&init_task, RLIMIT_MSGQUEUE));
833 set_rlimit_ucount_max(&init_user_ns, UCOUNT_RLIMIT_SIGPENDING, task_rlimit(&init_task, RLIMIT_SIGPENDING));
834 set_rlimit_ucount_max(&init_user_ns, UCOUNT_RLIMIT_MEMLOCK, task_rlimit(&init_task, RLIMIT_MEMLOCK));
835
831#ifdef CONFIG_VMAP_STACK836#ifdef CONFIG_VMAP_STACK
832 cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "fork:vm_stack_cache",837 cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "fork:vm_stack_cache",
833 NULL, free_vm_stack_cache);838 NULL, free_vm_stack_cache);
@@ -1978,8 +1983,7 @@ static __latent_entropy struct task_struct *copy_process( · 1144 unmodified lines
1978 DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled);1983 DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled);
1979#endif1984#endif
1980 retval = -EAGAIN;1985 retval = -EAGAIN;
1981 if (atomic_read(&p->real_cred->user->processes) >=1986 if (is_ucounts_overlimit(task_ucounts(p), UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC))) {
1982 task_rlimit(p, RLIMIT_NPROC)) {
1983 if (p->real_cred->user != INIT_USER &&1987 if (p->real_cred->user != INIT_USER &&
1984 !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN))1988 !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN))
1985 goto bad_fork_free;1989 goto bad_fork_free;
@@ -2388,7 +2392,7 @@ bad_fork_cleanup_threadgroup_lock: · 402 unmodified lines
2388#endif2392#endif
2389 delayacct_tsk_free(p);2393 delayacct_tsk_free(p);
2390bad_fork_cleanup_count:2394bad_fork_cleanup_count:
2391 atomic_dec(&p->cred->user->processes);2395 dec_rlimit_ucounts(task_ucounts(p), UCOUNT_RLIMIT_NPROC, 1);
2392 exit_creds(p);2396 exit_creds(p);
2393bad_fork_free:2397bad_fork_free:
2394 WRITE_ONCE(p->__state, TASK_DEAD);2398 WRITE_ONCE(p->__state, TASK_DEAD);
@@ -3001,6 +3005,12 @@ int ksys_unshare(unsigned long unshare_flags) · 606 unmodified lines
3001 if (err)3005 if (err)
3002 goto bad_unshare_cleanup_cred;3006 goto bad_unshare_cleanup_cred;
3003 3007
3008 if (new_cred) {
3009 err = set_cred_ucounts(new_cred);
3010 if (err)
3011 goto bad_unshare_cleanup_cred;
3012 }
3013
3004 if (new_fs || new_fd || do_sysvsem || new_cred || new_nsproxy) {3014 if (new_fs || new_fd || do_sysvsem || new_cred || new_nsproxy) {
3005 if (do_sysvsem) {3015 if (do_sysvsem) {
3006 /*3016 /*
kernel/signal.c+13−12
@@ -412,8 +412,8 @@ __sigqueue_alloc(int sig, struct task_struct *t, gfp_t gfp_flags, · 411 unmodified lines
412 int override_rlimit, const unsigned int sigqueue_flags)412 int override_rlimit, const unsigned int sigqueue_flags)
413{413{
414 struct sigqueue *q = NULL;414 struct sigqueue *q = NULL;
415 struct user_struct *user;415 struct ucounts *ucounts = NULL;
416 int sigpending;416 long sigpending;
417 417
418 /*418 /*
419 * Protect access to @t credentials. This can go away when all419 * Protect access to @t credentials. This can go away when all
@@ -424,27 +424,26 @@ __sigqueue_alloc(int sig, struct task_struct *t, gfp_t gfp_flags, · 4 unmodified lines
424 * changes from/to zero.424 * changes from/to zero.
425 */425 */
426 rcu_read_lock();426 rcu_read_lock();
427 user = __task_cred(t)->user;427 ucounts = task_ucounts(t);
428 sigpending = atomic_inc_return(&user->sigpending);428 sigpending = inc_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_SIGPENDING, 1);
429 if (sigpending == 1)429 if (sigpending == 1)
430 get_uid(user);430 ucounts = get_ucounts(ucounts);
431 rcu_read_unlock();431 rcu_read_unlock();
432 432
433 if (override_rlimit || likely(sigpending <= task_rlimit(t, RLIMIT_SIGPENDING))) {433 if (override_rlimit || (sigpending < LONG_MAX && sigpending <= task_rlimit(t, RLIMIT_SIGPENDING))) {
434 q = kmem_cache_alloc(sigqueue_cachep, gfp_flags);434 q = kmem_cache_alloc(sigqueue_cachep, gfp_flags);
435 } else {435 } else {
436 print_dropped_signal(sig);436 print_dropped_signal(sig);
437 }437 }
438 438
439 if (unlikely(q == NULL)) {439 if (unlikely(q == NULL)) {
440 if (atomic_dec_and_test(&user->sigpending))440 if (ucounts && dec_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_SIGPENDING, 1))
441 free_uid(user);441 put_ucounts(ucounts);
442 } else {442 } else {
443 INIT_LIST_HEAD(&q->list);443 INIT_LIST_HEAD(&q->list);
444 q->flags = sigqueue_flags;444 q->flags = sigqueue_flags;
445 q->user = user;445 q->ucounts = ucounts;
446 }446 }
447
448 return q;447 return q;
449}448}
450 449
@@ -452,8 +451,10 @@ static void __sigqueue_free(struct sigqueue *q) · 1 unmodified line
452{451{
453 if (q->flags & SIGQUEUE_PREALLOC)452 if (q->flags & SIGQUEUE_PREALLOC)
454 return;453 return;
455 if (atomic_dec_and_test(&q->user->sigpending))454 if (q->ucounts && dec_rlimit_ucounts(q->ucounts, UCOUNT_RLIMIT_SIGPENDING, 1)) {
456 free_uid(q->user);455 put_ucounts(q->ucounts);
456 q->ucounts = NULL;
457 }
457 kmem_cache_free(sigqueue_cachep, q);458 kmem_cache_free(sigqueue_cachep, q);
458}459}
459 460
kernel/sys.c+13−1
@@ -479,7 +479,7 @@ static int set_user(struct cred *new) · 478 unmodified lines
479 * for programs doing set*uid()+execve() by harmlessly deferring the479 * for programs doing set*uid()+execve() by harmlessly deferring the
480 * failure to the execve() stage.480 * failure to the execve() stage.
481 */481 */
482 if (atomic_read(&new_user->processes) >= rlimit(RLIMIT_NPROC) &&482 if (is_ucounts_overlimit(new->ucounts, UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC)) &&
483 new_user != INIT_USER)483 new_user != INIT_USER)
484 current->flags |= PF_NPROC_EXCEEDED;484 current->flags |= PF_NPROC_EXCEEDED;
485 else485 else
@@ -558,6 +558,10 @@ long __sys_setreuid(uid_t ruid, uid_t euid) · 72 unmodified lines
558 if (retval < 0)558 if (retval < 0)
559 goto error;559 goto error;
560 560
561 retval = set_cred_ucounts(new);
562 if (retval < 0)
563 goto error;
564
561 return commit_creds(new);565 return commit_creds(new);
562 566
563error:567error:
@@ -616,6 +620,10 @@ long __sys_setuid(uid_t uid) · 52 unmodified lines
616 if (retval < 0)620 if (retval < 0)
617 goto error;621 goto error;
618 622
623 retval = set_cred_ucounts(new);
624 if (retval < 0)
625 goto error;
626
619 return commit_creds(new);627 return commit_creds(new);
620 628
621error:629error:
@@ -691,6 +699,10 @@ long __sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) · 69 unmodified lines
691 if (retval < 0)699 if (retval < 0)
692 goto error;700 goto error;
693 701
702 retval = set_cred_ucounts(new);
703 if (retval < 0)
704 goto error;
705
694 return commit_creds(new);706 return commit_creds(new);
695 707
696error:708error:
kernel/ucount.c+91−25
@@ -8,6 +8,12 @@ · 7 unmodified lines
8#include <linux/kmemleak.h>8#include <linux/kmemleak.h>
9#include <linux/user_namespace.h>9#include <linux/user_namespace.h>
10 10
11struct ucounts init_ucounts = {
12 .ns = &init_user_ns,
13 .uid = GLOBAL_ROOT_UID,
14 .count = ATOMIC_INIT(1),
15};
16
11#define UCOUNTS_HASHTABLE_BITS 1017#define UCOUNTS_HASHTABLE_BITS 10
12static struct hlist_head ucounts_hashtable[(1 << UCOUNTS_HASHTABLE_BITS)];18static struct hlist_head ucounts_hashtable[(1 << UCOUNTS_HASHTABLE_BITS)];
13static DEFINE_SPINLOCK(ucounts_lock);19static DEFINE_SPINLOCK(ucounts_lock);
@@ -78,6 +84,10 @@ static struct ctl_table user_table[] = { · 64 unmodified lines
78 UCOUNT_ENTRY("max_fanotify_groups"),84 UCOUNT_ENTRY("max_fanotify_groups"),
79 UCOUNT_ENTRY("max_fanotify_marks"),85 UCOUNT_ENTRY("max_fanotify_marks"),
80#endif86#endif
87 { },
88 { },
89 { },
90 { },
81 { }91 { }
82};92};
83#endif /* CONFIG_SYSCTL */93#endif /* CONFIG_SYSCTL */
@@ -129,7 +139,24 @@ static struct ucounts *find_ucounts(struct user_namespace *ns, kuid_t uid, struc · 45 unmodified lines
129 return NULL;139 return NULL;
130}140}
131 141
132static struct ucounts *get_ucounts(struct user_namespace *ns, kuid_t uid)142static void hlist_add_ucounts(struct ucounts *ucounts)
143{
144 struct hlist_head *hashent = ucounts_hashentry(ucounts->ns, ucounts->uid);
145 spin_lock_irq(&ucounts_lock);
146 hlist_add_head(&ucounts->node, hashent);
147 spin_unlock_irq(&ucounts_lock);
148}
149
150struct ucounts *get_ucounts(struct ucounts *ucounts)
151{
152 if (ucounts && atomic_add_negative(1, &ucounts->count)) {
153 put_ucounts(ucounts);
154 ucounts = NULL;
155 }
156 return ucounts;
157}
158
159struct ucounts *alloc_ucounts(struct user_namespace *ns, kuid_t uid)
133{160{
134 struct hlist_head *hashent = ucounts_hashentry(ns, uid);161 struct hlist_head *hashent = ucounts_hashentry(ns, uid);
135 struct ucounts *ucounts, *new;162 struct ucounts *ucounts, *new;
@@ -145,7 +172,7 @@ static struct ucounts *get_ucounts(struct user_namespace *ns, kuid_t uid) · 9 unmodified lines
145 172
146 new->ns = ns;173 new->ns = ns;
147 new->uid = uid;174 new->uid = uid;
148 new->count = 0;175 atomic_set(&new->count, 1);
149 176
150 spin_lock_irq(&ucounts_lock);177 spin_lock_irq(&ucounts_lock);
151 ucounts = find_ucounts(ns, uid, hashent);178 ucounts = find_ucounts(ns, uid, hashent);
@@ -153,40 +180,35 @@ static struct ucounts *get_ucounts(struct user_namespace *ns, kuid_t uid) · 1 unmodified line
153 kfree(new);180 kfree(new);
154 } else {181 } else {
155 hlist_add_head(&new->node, hashent);182 hlist_add_head(&new->node, hashent);
156 ucounts = new;183 spin_unlock_irq(&ucounts_lock);
184 return new;
157 }185 }
158 }186 }
159 if (ucounts->count == INT_MAX)
160 ucounts = NULL;
161 else
162 ucounts->count += 1;
163 spin_unlock_irq(&ucounts_lock);187 spin_unlock_irq(&ucounts_lock);
188 ucounts = get_ucounts(ucounts);
164 return ucounts;189 return ucounts;
165}190}
166 191
167static void put_ucounts(struct ucounts *ucounts)192void put_ucounts(struct ucounts *ucounts)
168{193{
169 unsigned long flags;194 unsigned long flags;
170 195
171 spin_lock_irqsave(&ucounts_lock, flags);196 if (atomic_dec_and_test(&ucounts->count)) {
172 ucounts->count -= 1;197 spin_lock_irqsave(&ucounts_lock, flags);
173 if (!ucounts->count)
174 hlist_del_init(&ucounts->node);198 hlist_del_init(&ucounts->node);
175 else199 spin_unlock_irqrestore(&ucounts_lock, flags);
176 ucounts = NULL;200 kfree(ucounts);
177 spin_unlock_irqrestore(&ucounts_lock, flags);201 }
178
179 kfree(ucounts);
180}202}
181 203
182static inline bool atomic_inc_below(atomic_t *v, int u)204static inline bool atomic_long_inc_below(atomic_long_t *v, int u)
183{205{
184 int c, old;206 long c, old;
185 c = atomic_read(v);207 c = atomic_long_read(v);
186 for (;;) {208 for (;;) {
187 if (unlikely(c >= u))209 if (unlikely(c >= u))
188 return false;210 return false;
189 old = atomic_cmpxchg(v, c, c+1);211 old = atomic_long_cmpxchg(v, c, c+1);
190 if (likely(old == c))212 if (likely(old == c))
191 return true;213 return true;
192 c = old;214 c = old;
@@ -198,19 +220,19 @@ struct ucounts *inc_ucount(struct user_namespace *ns, kuid_t uid, · 5 unmodified lines
198{220{
199 struct ucounts *ucounts, *iter, *bad;221 struct ucounts *ucounts, *iter, *bad;
200 struct user_namespace *tns;222 struct user_namespace *tns;
201 ucounts = get_ucounts(ns, uid);223 ucounts = alloc_ucounts(ns, uid);
202 for (iter = ucounts; iter; iter = tns->ucounts) {224 for (iter = ucounts; iter; iter = tns->ucounts) {
203 int max;225 long max;
204 tns = iter->ns;226 tns = iter->ns;
205 max = READ_ONCE(tns->ucount_max[type]);227 max = READ_ONCE(tns->ucount_max[type]);
206 if (!atomic_inc_below(&iter->ucount[type], max))228 if (!atomic_long_inc_below(&iter->ucount[type], max))
207 goto fail;229 goto fail;
208 }230 }
209 return ucounts;231 return ucounts;
210fail:232fail:
211 bad = iter;233 bad = iter;
212 for (iter = ucounts; iter != bad; iter = iter->ns->ucounts)234 for (iter = ucounts; iter != bad; iter = iter->ns->ucounts)
213 atomic_dec(&iter->ucount[type]);235 atomic_long_dec(&iter->ucount[type]);
214 236
215 put_ucounts(ucounts);237 put_ucounts(ucounts);
216 return NULL;238 return NULL;
@@ -220,12 +242,54 @@ void dec_ucount(struct ucounts *ucounts, enum ucount_type type) · 3 unmodified lines
220{242{
221 struct ucounts *iter;243 struct ucounts *iter;
222 for (iter = ucounts; iter; iter = iter->ns->ucounts) {244 for (iter = ucounts; iter; iter = iter->ns->ucounts) {
223 int dec = atomic_dec_if_positive(&iter->ucount[type]);245 long dec = atomic_long_dec_if_positive(&iter->ucount[type]);
224 WARN_ON_ONCE(dec < 0);246 WARN_ON_ONCE(dec < 0);
225 }247 }
226 put_ucounts(ucounts);248 put_ucounts(ucounts);
227}249}
228 250
251long inc_rlimit_ucounts(struct ucounts *ucounts, enum ucount_type type, long v)
252{
253 struct ucounts *iter;
254 long ret = 0;
255
256 for (iter = ucounts; iter; iter = iter->ns->ucounts) {
257 long max = READ_ONCE(iter->ns->ucount_max[type]);
258 long new = atomic_long_add_return(v, &iter->ucount[type]);
259 if (new < 0 || new > max)
260 ret = LONG_MAX;
261 else if (iter == ucounts)
262 ret = new;
263 }
264 return ret;
265}
266
267bool dec_rlimit_ucounts(struct ucounts *ucounts, enum ucount_type type, long v)
268{
269 struct ucounts *iter;
270 long new = -1; /* Silence compiler warning */
271 for (iter = ucounts; iter; iter = iter->ns->ucounts) {
272 long dec = atomic_long_add_return(-v, &iter->ucount[type]);
273 WARN_ON_ONCE(dec < 0);
274 if (iter == ucounts)
275 new = dec;
276 }
277 return (new == 0);
278}
279
280bool is_ucounts_overlimit(struct ucounts *ucounts, enum ucount_type type, unsigned long max)
281{
282 struct ucounts *iter;
283 if (get_ucounts_value(ucounts, type) > max)
284 return true;
285 for (iter = ucounts; iter; iter = iter->ns->ucounts) {
286 max = READ_ONCE(iter->ns->ucount_max[type]);
287 if (get_ucounts_value(iter, type) > max)
288 return true;
289 }
290 return false;
291}
292
229static __init int user_namespace_sysctl_init(void)293static __init int user_namespace_sysctl_init(void)
230{294{
231#ifdef CONFIG_SYSCTL295#ifdef CONFIG_SYSCTL
@@ -241,6 +305,8 @@ static __init int user_namespace_sysctl_init(void) · 9 unmodified lines
241 BUG_ON(!user_header);305 BUG_ON(!user_header);
242 BUG_ON(!setup_userns_sysctls(&init_user_ns));306 BUG_ON(!setup_userns_sysctls(&init_user_ns));
243#endif307#endif
308 hlist_add_ucounts(&init_ucounts);
309 inc_rlimit_ucounts(&init_ucounts, UCOUNT_RLIMIT_NPROC, 1);
244 return 0;310 return 0;
245}311}
246subsys_initcall(user_namespace_sysctl_init);312subsys_initcall(user_namespace_sysctl_init);
kernel/user.c+0−3
@@ -98,9 +98,6 @@ static DEFINE_SPINLOCK(uidhash_lock); · 97 unmodified lines
98/* root_user.__count is 1, for init task cred */98/* root_user.__count is 1, for init task cred */
99struct user_struct root_user = {99struct user_struct root_user = {
100 .__count = REFCOUNT_INIT(1),100 .__count = REFCOUNT_INIT(1),
101 .processes = ATOMIC_INIT(1),
102 .sigpending = ATOMIC_INIT(0),
103 .locked_shm = 0,
104 .uid = GLOBAL_ROOT_UID,101 .uid = GLOBAL_ROOT_UID,
105 .ratelimit = RATELIMIT_STATE_INIT(root_user.ratelimit, 0, 0),102 .ratelimit = RATELIMIT_STATE_INIT(root_user.ratelimit, 0, 0),
106};103};
kernel/user_namespace.c+8−1
@@ -119,9 +119,13 @@ int create_user_ns(struct cred *new) · 118 unmodified lines
119 ns->owner = owner;119 ns->owner = owner;
120 ns->group = group;120 ns->group = group;
121 INIT_WORK(&ns->work, free_user_ns);121 INIT_WORK(&ns->work, free_user_ns);
122 for (i = 0; i < UCOUNT_COUNTS; i++) {122 for (i = 0; i < MAX_PER_NAMESPACE_UCOUNTS; i++) {
123 ns->ucount_max[i] = INT_MAX;123 ns->ucount_max[i] = INT_MAX;
124 }124 }
125 set_rlimit_ucount_max(ns, UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC));
126 set_rlimit_ucount_max(ns, UCOUNT_RLIMIT_MSGQUEUE, rlimit(RLIMIT_MSGQUEUE));
127 set_rlimit_ucount_max(ns, UCOUNT_RLIMIT_SIGPENDING, rlimit(RLIMIT_SIGPENDING));
128 set_rlimit_ucount_max(ns, UCOUNT_RLIMIT_MEMLOCK, rlimit(RLIMIT_MEMLOCK));
125 ns->ucounts = ucounts;129 ns->ucounts = ucounts;
126 130
127 /* Inherit USERNS_SETGROUPS_ALLOWED from our parent */131 /* Inherit USERNS_SETGROUPS_ALLOWED from our parent */
@@ -1340,6 +1344,9 @@ static int userns_install(struct nsset *nsset, struct ns_common *ns) · 1212 unmodified lines
1340 put_user_ns(cred->user_ns);1344 put_user_ns(cred->user_ns);
1341 set_cred_user_ns(cred, get_user_ns(user_ns));1345 set_cred_user_ns(cred, get_user_ns(user_ns));
1342 1346
1347 if (set_cred_ucounts(cred) < 0)
1348 return -EINVAL;
1349
1343 return 0;1350 return 0;
1344}1351}
1345 1352

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t