Skip to content

Commit de39923

Browse files
legionusebiederm
authored andcommitted
ucounts: Split rlimit and ucount values and max values
Since the semantics of maximum rlimit values are different, it would be better not to mix ucount and rlimit values. This will prevent the error of using inc_count/dec_ucount for rlimit parameters. This patch also renames the functions to emphasize the lack of connection between rlimit and ucount. v3: - Fix BUG:KASAN:use-after-free_in_dec_ucount. v2: - Fix the array-index-out-of-bounds that was found by the lkp project. Reported-by: kernel test robot <oliver.sang@intel.com> Signed-off-by: Alexey Gladkov <legion@kernel.org> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Link: https://lkml.kernel.org/r/20220518171730.l65lmnnjtnxnftpq@example.org Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
1 parent 3123109 commit de39923

File tree

7 files changed

+51
-46
lines changed

7 files changed

+51
-46
lines changed

fs/exec.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1880,7 +1880,7 @@ static int do_execveat_common(int fd, struct filename *filename,
18801880
* whether NPROC limit is still exceeded.
18811881
*/
18821882
if ((current->flags & PF_NPROC_EXCEEDED) &&
1883-
is_ucounts_overlimit(current_ucounts(), UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC))) {
1883+
is_rlimit_overlimit(current_ucounts(), UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC))) {
18841884
retval = -EAGAIN;
18851885
goto out_ret;
18861886
}

fs/proc/array.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ static inline void task_sig(struct seq_file *m, struct task_struct *p)
276276
collect_sigign_sigcatch(p, &ignored, &caught);
277277
num_threads = get_nr_threads(p);
278278
rcu_read_lock(); /* FIXME: is this correct? */
279-
qsize = get_ucounts_value(task_ucounts(p), UCOUNT_RLIMIT_SIGPENDING);
279+
qsize = get_rlimit_value(task_ucounts(p), UCOUNT_RLIMIT_SIGPENDING);
280280
rcu_read_unlock();
281281
qlim = task_rlimit(p, RLIMIT_SIGPENDING);
282282
unlock_task_sighand(p, &flags);

include/linux/user_namespace.h

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,17 @@ enum ucount_type {
5454
UCOUNT_FANOTIFY_GROUPS,
5555
UCOUNT_FANOTIFY_MARKS,
5656
#endif
57+
UCOUNT_COUNTS,
58+
};
59+
60+
enum rlimit_type {
5761
UCOUNT_RLIMIT_NPROC,
5862
UCOUNT_RLIMIT_MSGQUEUE,
5963
UCOUNT_RLIMIT_SIGPENDING,
6064
UCOUNT_RLIMIT_MEMLOCK,
61-
UCOUNT_COUNTS,
65+
UCOUNT_RLIMIT_COUNTS,
6266
};
6367

64-
#define MAX_PER_NAMESPACE_UCOUNTS UCOUNT_RLIMIT_NPROC
65-
6668
struct user_namespace {
6769
struct uid_gid_map uid_map;
6870
struct uid_gid_map gid_map;
@@ -99,6 +101,7 @@ struct user_namespace {
99101
#endif
100102
struct ucounts *ucounts;
101103
long ucount_max[UCOUNT_COUNTS];
104+
long rlimit_max[UCOUNT_RLIMIT_COUNTS];
102105
} __randomize_layout;
103106

104107
struct ucounts {
@@ -107,6 +110,7 @@ struct ucounts {
107110
kuid_t uid;
108111
atomic_t count;
109112
atomic_long_t ucount[UCOUNT_COUNTS];
113+
atomic_long_t rlimit[UCOUNT_RLIMIT_COUNTS];
110114
};
111115

112116
extern struct user_namespace init_user_ns;
@@ -120,21 +124,26 @@ struct ucounts *alloc_ucounts(struct user_namespace *ns, kuid_t uid);
120124
struct ucounts * __must_check get_ucounts(struct ucounts *ucounts);
121125
void put_ucounts(struct ucounts *ucounts);
122126

123-
static inline long get_ucounts_value(struct ucounts *ucounts, enum ucount_type type)
127+
static inline long get_rlimit_value(struct ucounts *ucounts, enum rlimit_type type)
124128
{
125-
return atomic_long_read(&ucounts->ucount[type]);
129+
return atomic_long_read(&ucounts->rlimit[type]);
126130
}
127131

128-
long inc_rlimit_ucounts(struct ucounts *ucounts, enum ucount_type type, long v);
129-
bool dec_rlimit_ucounts(struct ucounts *ucounts, enum ucount_type type, long v);
130-
long inc_rlimit_get_ucounts(struct ucounts *ucounts, enum ucount_type type);
131-
void dec_rlimit_put_ucounts(struct ucounts *ucounts, enum ucount_type type);
132-
bool is_ucounts_overlimit(struct ucounts *ucounts, enum ucount_type type, unsigned long max);
132+
long inc_rlimit_ucounts(struct ucounts *ucounts, enum rlimit_type type, long v);
133+
bool dec_rlimit_ucounts(struct ucounts *ucounts, enum rlimit_type type, long v);
134+
long inc_rlimit_get_ucounts(struct ucounts *ucounts, enum rlimit_type type);
135+
void dec_rlimit_put_ucounts(struct ucounts *ucounts, enum rlimit_type type);
136+
bool is_rlimit_overlimit(struct ucounts *ucounts, enum rlimit_type type, unsigned long max);
137+
138+
static inline long get_userns_rlimit_max(struct user_namespace *ns, enum rlimit_type type)
139+
{
140+
return READ_ONCE(ns->rlimit_max[type]);
141+
}
133142

134-
static inline void set_rlimit_ucount_max(struct user_namespace *ns,
135-
enum ucount_type type, unsigned long max)
143+
static inline void set_userns_rlimit_max(struct user_namespace *ns,
144+
enum rlimit_type type, unsigned long max)
136145
{
137-
ns->ucount_max[type] = max <= LONG_MAX ? max : LONG_MAX;
146+
ns->rlimit_max[type] = max <= LONG_MAX ? max : LONG_MAX;
138147
}
139148

140149
#ifdef CONFIG_USER_NS

kernel/fork.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -926,13 +926,13 @@ void __init fork_init(void)
926926
init_task.signal->rlim[RLIMIT_SIGPENDING] =
927927
init_task.signal->rlim[RLIMIT_NPROC];
928928

929-
for (i = 0; i < MAX_PER_NAMESPACE_UCOUNTS; i++)
929+
for (i = 0; i < UCOUNT_COUNTS; i++)
930930
init_user_ns.ucount_max[i] = max_threads/2;
931931

932-
set_rlimit_ucount_max(&init_user_ns, UCOUNT_RLIMIT_NPROC, RLIM_INFINITY);
933-
set_rlimit_ucount_max(&init_user_ns, UCOUNT_RLIMIT_MSGQUEUE, RLIM_INFINITY);
934-
set_rlimit_ucount_max(&init_user_ns, UCOUNT_RLIMIT_SIGPENDING, RLIM_INFINITY);
935-
set_rlimit_ucount_max(&init_user_ns, UCOUNT_RLIMIT_MEMLOCK, RLIM_INFINITY);
932+
set_userns_rlimit_max(&init_user_ns, UCOUNT_RLIMIT_NPROC, RLIM_INFINITY);
933+
set_userns_rlimit_max(&init_user_ns, UCOUNT_RLIMIT_MSGQUEUE, RLIM_INFINITY);
934+
set_userns_rlimit_max(&init_user_ns, UCOUNT_RLIMIT_SIGPENDING, RLIM_INFINITY);
935+
set_userns_rlimit_max(&init_user_ns, UCOUNT_RLIMIT_MEMLOCK, RLIM_INFINITY);
936936

937937
#ifdef CONFIG_VMAP_STACK
938938
cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "fork:vm_stack_cache",
@@ -2096,7 +2096,7 @@ static __latent_entropy struct task_struct *copy_process(
20962096
goto bad_fork_free;
20972097

20982098
retval = -EAGAIN;
2099-
if (is_ucounts_overlimit(task_ucounts(p), UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC))) {
2099+
if (is_rlimit_overlimit(task_ucounts(p), UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC))) {
21002100
if (p->real_cred->user != INIT_USER &&
21012101
!capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN))
21022102
goto bad_fork_cleanup_count;

kernel/sys.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,7 @@ static void flag_nproc_exceeded(struct cred *new)
490490
* for programs doing set*uid()+execve() by harmlessly deferring the
491491
* failure to the execve() stage.
492492
*/
493-
if (is_ucounts_overlimit(new->ucounts, UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC)) &&
493+
if (is_rlimit_overlimit(new->ucounts, UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC)) &&
494494
new->user != INIT_USER)
495495
current->flags |= PF_NPROC_EXCEEDED;
496496
else

kernel/ucount.c

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,6 @@ static struct ctl_table user_table[] = {
8787
UCOUNT_ENTRY("max_fanotify_groups"),
8888
UCOUNT_ENTRY("max_fanotify_marks"),
8989
#endif
90-
{ },
91-
{ },
92-
{ },
93-
{ },
9490
{ }
9591
};
9692
#endif /* CONFIG_SYSCTL */
@@ -263,29 +259,29 @@ void dec_ucount(struct ucounts *ucounts, enum ucount_type type)
263259
put_ucounts(ucounts);
264260
}
265261

266-
long inc_rlimit_ucounts(struct ucounts *ucounts, enum ucount_type type, long v)
262+
long inc_rlimit_ucounts(struct ucounts *ucounts, enum rlimit_type type, long v)
267263
{
268264
struct ucounts *iter;
269265
long max = LONG_MAX;
270266
long ret = 0;
271267

272268
for (iter = ucounts; iter; iter = iter->ns->ucounts) {
273-
long new = atomic_long_add_return(v, &iter->ucount[type]);
269+
long new = atomic_long_add_return(v, &iter->rlimit[type]);
274270
if (new < 0 || new > max)
275271
ret = LONG_MAX;
276272
else if (iter == ucounts)
277273
ret = new;
278-
max = READ_ONCE(iter->ns->ucount_max[type]);
274+
max = get_userns_rlimit_max(iter->ns, type);
279275
}
280276
return ret;
281277
}
282278

283-
bool dec_rlimit_ucounts(struct ucounts *ucounts, enum ucount_type type, long v)
279+
bool dec_rlimit_ucounts(struct ucounts *ucounts, enum rlimit_type type, long v)
284280
{
285281
struct ucounts *iter;
286282
long new = -1; /* Silence compiler warning */
287283
for (iter = ucounts; iter; iter = iter->ns->ucounts) {
288-
long dec = atomic_long_sub_return(v, &iter->ucount[type]);
284+
long dec = atomic_long_sub_return(v, &iter->rlimit[type]);
289285
WARN_ON_ONCE(dec < 0);
290286
if (iter == ucounts)
291287
new = dec;
@@ -294,37 +290,37 @@ bool dec_rlimit_ucounts(struct ucounts *ucounts, enum ucount_type type, long v)
294290
}
295291

296292
static void do_dec_rlimit_put_ucounts(struct ucounts *ucounts,
297-
struct ucounts *last, enum ucount_type type)
293+
struct ucounts *last, enum rlimit_type type)
298294
{
299295
struct ucounts *iter, *next;
300296
for (iter = ucounts; iter != last; iter = next) {
301-
long dec = atomic_long_sub_return(1, &iter->ucount[type]);
297+
long dec = atomic_long_sub_return(1, &iter->rlimit[type]);
302298
WARN_ON_ONCE(dec < 0);
303299
next = iter->ns->ucounts;
304300
if (dec == 0)
305301
put_ucounts(iter);
306302
}
307303
}
308304

309-
void dec_rlimit_put_ucounts(struct ucounts *ucounts, enum ucount_type type)
305+
void dec_rlimit_put_ucounts(struct ucounts *ucounts, enum rlimit_type type)
310306
{
311307
do_dec_rlimit_put_ucounts(ucounts, NULL, type);
312308
}
313309

314-
long inc_rlimit_get_ucounts(struct ucounts *ucounts, enum ucount_type type)
310+
long inc_rlimit_get_ucounts(struct ucounts *ucounts, enum rlimit_type type)
315311
{
316312
/* Caller must hold a reference to ucounts */
317313
struct ucounts *iter;
318314
long max = LONG_MAX;
319315
long dec, ret = 0;
320316

321317
for (iter = ucounts; iter; iter = iter->ns->ucounts) {
322-
long new = atomic_long_add_return(1, &iter->ucount[type]);
318+
long new = atomic_long_add_return(1, &iter->rlimit[type]);
323319
if (new < 0 || new > max)
324320
goto unwind;
325321
if (iter == ucounts)
326322
ret = new;
327-
max = READ_ONCE(iter->ns->ucount_max[type]);
323+
max = get_userns_rlimit_max(iter->ns, type);
328324
/*
329325
* Grab an extra ucount reference for the caller when
330326
* the rlimit count was previously 0.
@@ -336,24 +332,24 @@ long inc_rlimit_get_ucounts(struct ucounts *ucounts, enum ucount_type type)
336332
}
337333
return ret;
338334
dec_unwind:
339-
dec = atomic_long_sub_return(1, &iter->ucount[type]);
335+
dec = atomic_long_sub_return(1, &iter->rlimit[type]);
340336
WARN_ON_ONCE(dec < 0);
341337
unwind:
342338
do_dec_rlimit_put_ucounts(ucounts, iter, type);
343339
return 0;
344340
}
345341

346-
bool is_ucounts_overlimit(struct ucounts *ucounts, enum ucount_type type, unsigned long rlimit)
342+
bool is_rlimit_overlimit(struct ucounts *ucounts, enum rlimit_type type, unsigned long rlimit)
347343
{
348344
struct ucounts *iter;
349345
long max = rlimit;
350346
if (rlimit > LONG_MAX)
351347
max = LONG_MAX;
352348
for (iter = ucounts; iter; iter = iter->ns->ucounts) {
353-
long val = get_ucounts_value(iter, type);
349+
long val = get_rlimit_value(iter, type);
354350
if (val < 0 || val > max)
355351
return true;
356-
max = READ_ONCE(iter->ns->ucount_max[type]);
352+
max = get_userns_rlimit_max(iter->ns, type);
357353
}
358354
return false;
359355
}

kernel/user_namespace.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,13 +131,13 @@ int create_user_ns(struct cred *new)
131131
ns->owner = owner;
132132
ns->group = group;
133133
INIT_WORK(&ns->work, free_user_ns);
134-
for (i = 0; i < MAX_PER_NAMESPACE_UCOUNTS; i++) {
134+
for (i = 0; i < UCOUNT_COUNTS; i++) {
135135
ns->ucount_max[i] = INT_MAX;
136136
}
137-
set_rlimit_ucount_max(ns, UCOUNT_RLIMIT_NPROC, enforced_nproc_rlimit());
138-
set_rlimit_ucount_max(ns, UCOUNT_RLIMIT_MSGQUEUE, rlimit(RLIMIT_MSGQUEUE));
139-
set_rlimit_ucount_max(ns, UCOUNT_RLIMIT_SIGPENDING, rlimit(RLIMIT_SIGPENDING));
140-
set_rlimit_ucount_max(ns, UCOUNT_RLIMIT_MEMLOCK, rlimit(RLIMIT_MEMLOCK));
137+
set_userns_rlimit_max(ns, UCOUNT_RLIMIT_NPROC, enforced_nproc_rlimit());
138+
set_userns_rlimit_max(ns, UCOUNT_RLIMIT_MSGQUEUE, rlimit(RLIMIT_MSGQUEUE));
139+
set_userns_rlimit_max(ns, UCOUNT_RLIMIT_SIGPENDING, rlimit(RLIMIT_SIGPENDING));
140+
set_userns_rlimit_max(ns, UCOUNT_RLIMIT_MEMLOCK, rlimit(RLIMIT_MEMLOCK));
141141
ns->ucounts = ucounts;
142142

143143
/* Inherit USERNS_SETGROUPS_ALLOWED from our parent */

0 commit comments

Comments
 (0)