Skip to content

Commit 29e44f4

Browse files
dhowellstorvalds
authored andcommitted
watch_queue: Limit the number of watches a user can hold
Impose a limit on the number of watches that a user can hold so that they can't use this mechanism to fill up all the available memory. This is done by putting a counter in user_struct that's incremented when a watch is allocated and decreased when it is released. If the number exceeds the RLIMIT_NOFILE limit, the watch is rejected with EAGAIN. This can be tested by the following means: (1) Create a watch queue and attach it to fd 5 in the program given - in this case, bash: keyctl watch_session /tmp/nlog /tmp/gclog 5 bash (2) In the shell, set the maximum number of files to, say, 99: ulimit -n 99 (3) Add 200 keyrings: for ((i=0; i<200; i++)); do keyctl newring a$i @s || break; done (4) Try to watch all of the keyrings: for ((i=0; i<200; i++)); do echo $i; keyctl watch_add 5 %:a$i || break; done This should fail when the number of watches belonging to the user hits 99. (5) Remove all the keyrings and all of those watches should go away: for ((i=0; i<200; i++)); do keyctl unlink %:a$i; done (6) Kill off the watch queue by exiting the shell spawned by watch_session. Fixes: c73be61 ("pipe: Add general notification queue support") Reported-by: Linus Torvalds <[email protected]> Signed-off-by: David Howells <[email protected]> Reviewed-by: Jarkko Sakkinen <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 9123e3a commit 29e44f4

File tree

2 files changed

+11
-0
lines changed

2 files changed

+11
-0
lines changed

include/linux/sched/user.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ struct user_struct {
3636
defined(CONFIG_NET) || defined(CONFIG_IO_URING)
3737
atomic_long_t locked_vm;
3838
#endif
39+
#ifdef CONFIG_WATCH_QUEUE
40+
atomic_t nr_watches; /* The number of watches this user currently has */
41+
#endif
3942

4043
/* Miscellaneous per-user rate limit */
4144
struct ratelimit_state ratelimit;

kernel/watch_queue.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,7 @@ static void free_watch(struct rcu_head *rcu)
393393
struct watch *watch = container_of(rcu, struct watch, rcu);
394394

395395
put_watch_queue(rcu_access_pointer(watch->queue));
396+
atomic_dec(&watch->cred->user->nr_watches);
396397
put_cred(watch->cred);
397398
}
398399

@@ -452,6 +453,13 @@ int add_watch_to_object(struct watch *watch, struct watch_list *wlist)
452453
watch->cred = get_current_cred();
453454
rcu_assign_pointer(watch->watch_list, wlist);
454455

456+
if (atomic_inc_return(&watch->cred->user->nr_watches) >
457+
task_rlimit(current, RLIMIT_NOFILE)) {
458+
atomic_dec(&watch->cred->user->nr_watches);
459+
put_cred(watch->cred);
460+
return -EAGAIN;
461+
}
462+
455463
spin_lock_bh(&wqueue->lock);
456464
kref_get(&wqueue->usage);
457465
kref_get(&watch->usage);

0 commit comments

Comments
 (0)