Skip to content

Commit d646969

Browse files
legionusebiederm
authored andcommitted
Reimplement RLIMIT_SIGPENDING on top of ucounts
The rlimit counter is tied to uid in the user_namespace. This allows rlimit values to be specified in userns even if they are already globally exceeded by the user. However, the value of the previous user_namespaces cannot be exceeded. Changelog v11: * Revert most of changes to fix performance issues. v10: * Fix memory leak on get_ucounts failure. Signed-off-by: Alexey Gladkov <[email protected]> Link: https://lkml.kernel.org/r/df9d7764dddd50f28616b7840de74ec0f81711a8.1619094428.git.legion@kernel.org Signed-off-by: Eric W. Biederman <[email protected]>
1 parent 6e52a9f commit d646969

File tree

9 files changed

+21
-16
lines changed

9 files changed

+21
-16
lines changed

fs/proc/array.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ static inline void task_sig(struct seq_file *m, struct task_struct *p)
284284
collect_sigign_sigcatch(p, &ignored, &caught);
285285
num_threads = get_nr_threads(p);
286286
rcu_read_lock(); /* FIXME: is this correct? */
287-
qsize = atomic_read(&__task_cred(p)->user->sigpending);
287+
qsize = get_ucounts_value(task_ucounts(p), UCOUNT_RLIMIT_SIGPENDING);
288288
rcu_read_unlock();
289289
qlim = task_rlimit(p, RLIMIT_SIGPENDING);
290290
unlock_task_sighand(p, &flags);

include/linux/sched/user.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
*/
1313
struct user_struct {
1414
refcount_t __count; /* reference count */
15-
atomic_t sigpending; /* How many pending signals does this user have? */
1615
#ifdef CONFIG_FANOTIFY
1716
atomic_t fanotify_listeners;
1817
#endif

include/linux/signal_types.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ typedef struct kernel_siginfo {
1313
__SIGINFO;
1414
} kernel_siginfo_t;
1515

16+
struct ucounts;
17+
1618
/*
1719
* Real Time signals may be queued.
1820
*/
@@ -21,7 +23,7 @@ struct sigqueue {
2123
struct list_head list;
2224
int flags;
2325
kernel_siginfo_t info;
24-
struct user_struct *user;
26+
struct ucounts *ucounts;
2527
};
2628

2729
/* flags values. */

include/linux/user_namespace.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ enum ucount_type {
5252
#endif
5353
UCOUNT_RLIMIT_NPROC,
5454
UCOUNT_RLIMIT_MSGQUEUE,
55+
UCOUNT_RLIMIT_SIGPENDING,
5556
UCOUNT_COUNTS,
5657
};
5758

kernel/fork.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,7 @@ void __init fork_init(void)
824824

825825
init_user_ns.ucount_max[UCOUNT_RLIMIT_NPROC] = task_rlimit(&init_task, RLIMIT_NPROC);
826826
init_user_ns.ucount_max[UCOUNT_RLIMIT_MSGQUEUE] = task_rlimit(&init_task, RLIMIT_MSGQUEUE);
827+
init_user_ns.ucount_max[UCOUNT_RLIMIT_SIGPENDING] = task_rlimit(&init_task, RLIMIT_SIGPENDING);
827828

828829
#ifdef CONFIG_VMAP_STACK
829830
cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "fork:vm_stack_cache",

kernel/signal.c

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -413,8 +413,8 @@ static struct sigqueue *
413413
__sigqueue_alloc(int sig, struct task_struct *t, gfp_t flags, int override_rlimit)
414414
{
415415
struct sigqueue *q = NULL;
416-
struct user_struct *user;
417-
int sigpending;
416+
struct ucounts *ucounts = NULL;
417+
long sigpending;
418418

419419
/*
420420
* Protect access to @t credentials. This can go away when all
@@ -425,36 +425,37 @@ __sigqueue_alloc(int sig, struct task_struct *t, gfp_t flags, int override_rlimi
425425
* changes from/to zero.
426426
*/
427427
rcu_read_lock();
428-
user = __task_cred(t)->user;
429-
sigpending = atomic_inc_return(&user->sigpending);
428+
ucounts = task_ucounts(t);
429+
sigpending = inc_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_SIGPENDING, 1);
430430
if (sigpending == 1)
431-
get_uid(user);
431+
ucounts = get_ucounts(ucounts);
432432
rcu_read_unlock();
433433

434-
if (override_rlimit || likely(sigpending <= task_rlimit(t, RLIMIT_SIGPENDING))) {
434+
if (override_rlimit || (sigpending < LONG_MAX && sigpending <= task_rlimit(t, RLIMIT_SIGPENDING))) {
435435
q = kmem_cache_alloc(sigqueue_cachep, flags);
436436
} else {
437437
print_dropped_signal(sig);
438438
}
439439

440440
if (unlikely(q == NULL)) {
441-
if (atomic_dec_and_test(&user->sigpending))
442-
free_uid(user);
441+
if (ucounts && dec_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_SIGPENDING, 1))
442+
put_ucounts(ucounts);
443443
} else {
444444
INIT_LIST_HEAD(&q->list);
445445
q->flags = 0;
446-
q->user = user;
446+
q->ucounts = ucounts;
447447
}
448-
449448
return q;
450449
}
451450

452451
static void __sigqueue_free(struct sigqueue *q)
453452
{
454453
if (q->flags & SIGQUEUE_PREALLOC)
455454
return;
456-
if (atomic_dec_and_test(&q->user->sigpending))
457-
free_uid(q->user);
455+
if (q->ucounts && dec_rlimit_ucounts(q->ucounts, UCOUNT_RLIMIT_SIGPENDING, 1)) {
456+
put_ucounts(q->ucounts);
457+
q->ucounts = NULL;
458+
}
458459
kmem_cache_free(sigqueue_cachep, q);
459460
}
460461

kernel/ucount.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ static struct ctl_table user_table[] = {
8080
UCOUNT_ENTRY("max_inotify_instances"),
8181
UCOUNT_ENTRY("max_inotify_watches"),
8282
#endif
83+
{ },
8384
{ },
8485
{ },
8586
{ }

kernel/user.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,6 @@ static DEFINE_SPINLOCK(uidhash_lock);
9898
/* root_user.__count is 1, for init task cred */
9999
struct user_struct root_user = {
100100
.__count = REFCOUNT_INIT(1),
101-
.sigpending = ATOMIC_INIT(0),
102101
.locked_shm = 0,
103102
.uid = GLOBAL_ROOT_UID,
104103
.ratelimit = RATELIMIT_STATE_INIT(root_user.ratelimit, 0, 0),

kernel/user_namespace.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ int create_user_ns(struct cred *new)
124124
}
125125
ns->ucount_max[UCOUNT_RLIMIT_NPROC] = rlimit(RLIMIT_NPROC);
126126
ns->ucount_max[UCOUNT_RLIMIT_MSGQUEUE] = rlimit(RLIMIT_MSGQUEUE);
127+
ns->ucount_max[UCOUNT_RLIMIT_SIGPENDING] = rlimit(RLIMIT_SIGPENDING);
127128
ns->ucounts = ucounts;
128129

129130
/* Inherit USERNS_SETGROUPS_ALLOWED from our parent */

0 commit comments

Comments
 (0)