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

Unified · Split

29 files
  1. fs/exec.c +5 −1
  2. fs/hugetlbfs/inode.c +8 −8
  3. fs/proc/array.c +1 −1
  4. include/linux/cred.h +4 −0
  5. include/linux/hugetlb.h +2 −2
  6. include/linux/mm.h +2 −2
  7. include/linux/sched/user.h +0 −7
  8. include/linux/shmem_fs.h +1 −1
  9. include/linux/signal_types.h +3 −1
  10. include/linux/user_namespace.h +28 −3
  11. ipc/mqueue.c +21 −19
  12. ipc/shm.c +13 −13
  13. kernel/cred.c +46 −5
  14. kernel/exit.c +1 −1
  15. kernel/fork.c +14 −4
  16. kernel/signal.c +13 −12
  17. kernel/sys.c +13 −1
  18. kernel/ucount.c +91 −25
  19. kernel/user.c +0 −3
  20. kernel/user_namespace.c +8 −1
  21. mm/memfd.c +2 −2
  22. mm/mlock.c +14 −8
  23. mm/mmap.c +2 −2
  24. mm/shmem.c +5 −5
  25. tools/testing/selftests/Makefile +1 −0
  26. tools/testing/selftests/rlimits/.gitignore +2 −0
  27. tools/testing/selftests/rlimits/Makefile +6 −0
  28. tools/testing/selftests/rlimits/config +1 −0
  29. tools/testing/selftests/rlimits/rlimits-per-userns.c +161 −0
fs/exec.c+5−1
@@ -1360,6 +1360,10 @@ int begin_new_exec(struct linux_binprm * bprm) · 1359 unmodified lines
13601360 WRITE_ONCE(me->self_exec_id, me->self_exec_id + 1);
13611361 flush_signal_handlers(me, 0);
13621362
1363+ retval = set_cred_ucounts(bprm->cred);
1364+ if (retval < 0)
1365+ goto out_unlock;
1366+
13631367 /*
13641368 * install the new credentials for this executable
13651369 */
@@ -1874,7 +1878,7 @@ static int do_execveat_common(int fd, struct filename *filename, · 508 unmodified lines
18741878 * whether NPROC limit is still exceeded.
18751879 */
18761880 if ((current->flags & PF_NPROC_EXCEEDED) &&
1877− atomic_read(&current_user()->processes) > rlimit(RLIMIT_NPROC)) {
1881+ is_ucounts_overlimit(current_ucounts(), UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC))) {
18781882 retval = -EAGAIN;
18791883 goto out_ret;
18801884 }
fs/hugetlbfs/inode.c+8−8
@@ -1446,7 +1446,7 @@ static int get_hstate_idx(int page_size_log) · 1445 unmodified lines
14461446 * otherwise hugetlb_reserve_pages reserves one less hugepages than intended.
14471447 */
14481448 struct file *hugetlb_file_setup(const char *name, size_t size,
1449− vm_flags_t acctflag, struct user_struct **user,
1449+ vm_flags_t acctflag, struct ucounts **ucounts,
14501450 int creat_flags, int page_size_log)
14511451 {
14521452 struct inode *inode;
@@ -1458,20 +1458,20 @@ struct file *hugetlb_file_setup(const char *name, size_t size, · 5 unmodified lines
14581458 if (hstate_idx < 0)
14591459 return ERR_PTR(-ENODEV);
14601460
1461− *user = NULL;
1461+ *ucounts = NULL;
14621462 mnt = hugetlbfs_vfsmount[hstate_idx];
14631463 if (!mnt)
14641464 return ERR_PTR(-ENOENT);
14651465
14661466 if (creat_flags == HUGETLB_SHMFS_INODE && !can_do_hugetlb_shm()) {
1467− *user = current_user();
1468− if (user_shm_lock(size, *user)) {
1467+ *ucounts = current_ucounts();
1468+ if (user_shm_lock(size, *ucounts)) {
14691469 task_lock(current);
14701470 pr_warn_once("%s (%d): Using mlock ulimits for SHM_HUGETLB is deprecated\n",
14711471 current->comm, current->pid);
14721472 task_unlock(current);
14731473 } else {
1474− *user = NULL;
1474+ *ucounts = NULL;
14751475 return ERR_PTR(-EPERM);
14761476 }
14771477 }
@@ -1498,9 +1498,9 @@ struct file *hugetlb_file_setup(const char *name, size_t size, · 20 unmodified lines
14981498
14991499 iput(inode);
15001500 out:
1501− if (*user) {
1502− user_shm_unlock(size, *user);
1503− *user = NULL;
1501+ if (*ucounts) {
1502+ user_shm_unlock(size, *ucounts);
1503+ *ucounts = NULL;
15041504 }
15051505 return file;
15061506 }
fs/proc/array.c+1−1
@@ -284,7 +284,7 @@ static inline void task_sig(struct seq_file *m, struct task_struct *p) · 283 unmodified lines
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/cred.h+4−0
@@ -143,6 +143,7 @@ struct cred { · 142 unmodified lines
143143 #endif
144144 struct user_struct *user; /* real user ID subscription */
145145 struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */
146+ struct ucounts *ucounts;
146147 struct group_info *group_info; /* supplementary groups for euid/fsgid */
147148 /* RCU deletion */
148149 union {
@@ -169,6 +170,7 @@ extern int set_security_override_from_ctx(struct cred *, const char *); · 20 unmodified lines
169170 extern int set_create_files_as(struct cred *, struct inode *);
170171 extern int cred_fscmp(const struct cred *, const struct cred *);
171172 extern void __init cred_init(void);
173+extern int set_cred_ucounts(struct cred *);
172174
173175 /*
174176 * check for validity of credentials
@@ -369,6 +371,7 @@ static inline void put_cred(const struct cred *_cred) · 194 unmodified lines
369371
370372 #define task_uid(task) (task_cred_xxx((task), uid))
371373 #define task_euid(task) (task_cred_xxx((task), euid))
374+#define task_ucounts(task) (task_cred_xxx((task), ucounts))
372375
373376 #define current_cred_xxx(xxx) \
374377 ({ \
@@ -385,6 +388,7 @@ static inline void put_cred(const struct cred *_cred) · 10 unmodified lines
385388 #define current_fsgid() (current_cred_xxx(fsgid))
386389 #define current_cap() (current_cred_xxx(cap_effective))
387390 #define current_user() (current_cred_xxx(user))
391+#define current_ucounts() (current_cred_xxx(ucounts))
388392
389393 extern struct user_namespace init_user_ns;
390394 #ifdef CONFIG_USER_NS
include/linux/hugetlb.h+2−2
@@ -451,7 +451,7 @@ static inline struct hugetlbfs_inode_info *HUGETLBFS_I(struct inode *inode) · 450 unmodified lines
451451 extern const struct file_operations hugetlbfs_file_operations;
452452 extern const struct vm_operations_struct hugetlb_vm_ops;
453453 struct file *hugetlb_file_setup(const char *name, size_t size, vm_flags_t acct,
454− struct user_struct **user, int creat_flags,
454+ struct ucounts **ucounts, int creat_flags,
455455 int page_size_log);
456456
457457 static inline bool is_file_hugepages(struct file *file)
@@ -471,7 +471,7 @@ static inline struct hstate *hstate_inode(struct inode *i) · 13 unmodified lines
471471 #define is_file_hugepages(file) false
472472 static inline struct file *
473473 hugetlb_file_setup(const char *name, size_t size, vm_flags_t acctflag,
474− struct user_struct **user, int creat_flags,
474+ struct ucounts **ucounts, int creat_flags,
475475 int page_size_log)
476476 {
477477 return ERR_PTR(-ENOSYS);
include/linux/mm.h+2−2
@@ -1709,8 +1709,8 @@ extern bool can_do_mlock(void); · 1708 unmodified lines
17091709 #else
17101710 static inline bool can_do_mlock(void) { return false; }
17111711 #endif
1712−extern int user_shm_lock(size_t, struct user_struct *);
1713−extern void user_shm_unlock(size_t, struct user_struct *);
1712+extern int user_shm_lock(size_t, struct ucounts *);
1713+extern void user_shm_unlock(size_t, struct ucounts *);
17141714
17151715 /*
17161716 * Parameter block passed down to zap_pte_range in exceptional cases.
include/linux/sched/user.h+0−7
@@ -12,16 +12,9 @@ · 11 unmodified lines
1212 */
1313 struct user_struct {
1414 refcount_t __count; /* reference count */
15− atomic_t processes; /* How many processes does this user have? */
16− atomic_t sigpending; /* How many pending signals does this user have? */
1715 #ifdef CONFIG_EPOLL
1816 atomic_long_t epoll_watches; /* The number of file descriptors currently watched */
1917 #endif
20−#ifdef CONFIG_POSIX_MQUEUE
21− /* protected by mq_lock */
22− unsigned long mq_bytes; /* How many bytes can be allocated to mqueue? */
23−#endif
24− unsigned long locked_shm; /* How many pages of mlocked shm ? */
2518 unsigned long unix_inflight; /* How many files in flight in unix sockets */
2619 atomic_long_t pipe_bufs; /* how many pages are allocated in pipe buffers */
2720
include/linux/shmem_fs.h+1−1
@@ -65,7 +65,7 @@ extern struct file *shmem_file_setup_with_mnt(struct vfsmount *mnt, · 64 unmodified lines
6565 extern int shmem_zero_setup(struct vm_area_struct *);
6666 extern unsigned long shmem_get_unmapped_area(struct file *, unsigned long addr,
6767 unsigned long len, unsigned long pgoff, unsigned long flags);
68−extern int shmem_lock(struct file *file, int lock, struct user_struct *user);
68+extern int shmem_lock(struct file *file, int lock, struct ucounts *ucounts);
6969 #ifdef CONFIG_SHMEM
7070 extern const struct address_space_operations shmem_aops;
7171 static inline bool shmem_mapping(struct address_space *mapping)
include/linux/signal_types.h+3−1
@@ -13,6 +13,8 @@ typedef struct kernel_siginfo { · 12 unmodified lines
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 { · 2 unmodified lines
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+28−3
@@ -54,9 +54,15 @@ enum ucount_type { · 53 unmodified lines
5454 UCOUNT_FANOTIFY_GROUPS,
5555 UCOUNT_FANOTIFY_MARKS,
5656 #endif
57+ UCOUNT_RLIMIT_NPROC,
58+ UCOUNT_RLIMIT_MSGQUEUE,
59+ UCOUNT_RLIMIT_SIGPENDING,
60+ UCOUNT_RLIMIT_MEMLOCK,
5761 UCOUNT_COUNTS,
5862 };
5963
64+#define MAX_PER_NAMESPACE_UCOUNTS UCOUNT_RLIMIT_NPROC
65+
6066 struct user_namespace {
6167 struct uid_gid_map uid_map;
6268 struct uid_gid_map gid_map;
@@ -92,23 +98,42 @@ struct user_namespace { · 29 unmodified lines
9298 struct ctl_table_header *sysctls;
9399 #endif
94100 struct ucounts *ucounts;
95− int ucount_max[UCOUNT_COUNTS];
101+ long ucount_max[UCOUNT_COUNTS];
96102 } __randomize_layout;
97103
98104 struct ucounts {
99105 struct hlist_node node;
100106 struct user_namespace *ns;
101107 kuid_t uid;
102− int count;
103− atomic_t ucount[UCOUNT_COUNTS];
108+ atomic_t count;
109+ atomic_long_t ucount[UCOUNT_COUNTS];
104110 };
105111
106112 extern struct user_namespace init_user_ns;
113+extern struct ucounts init_ucounts;
107114
108115 bool setup_userns_sysctls(struct user_namespace *ns);
109116 void retire_userns_sysctls(struct user_namespace *ns);
110117 struct ucounts *inc_ucount(struct user_namespace *ns, kuid_t uid, enum ucount_type type);
111118 void dec_ucount(struct ucounts *ucounts, enum ucount_type type);
119+struct ucounts *alloc_ucounts(struct user_namespace *ns, kuid_t uid);
120+struct ucounts * __must_check get_ucounts(struct ucounts *ucounts);
121+void put_ucounts(struct ucounts *ucounts);
122+
123+static inline long get_ucounts_value(struct ucounts *ucounts, enum ucount_type type)
124+{
125+ return atomic_long_read(&ucounts->ucount[type]);
126+}
127+
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+bool is_ucounts_overlimit(struct ucounts *ucounts, enum ucount_type type, unsigned long max);
131+
132+static inline void set_rlimit_ucount_max(struct user_namespace *ns,
133+ enum ucount_type type, unsigned long max)
134+{
135+ ns->ucount_max[type] = max <= LONG_MAX ? max : LONG_MAX;
136+}
112137
113138 #ifdef CONFIG_USER_NS
114139
ipc/mqueue.c+21−19
@@ -144,7 +144,7 @@ struct mqueue_inode_info { · 143 unmodified lines
144144 struct pid *notify_owner;
145145 u32 notify_self_exec_id;
146146 struct user_namespace *notify_user_ns;
147− struct user_struct *user; /* user who created, for accounting */
147+ struct ucounts *ucounts; /* user who created, for accounting */
148148 struct sock *notify_sock;
149149 struct sk_buff *notify_cookie;
150150
@@ -292,7 +292,6 @@ static struct inode *mqueue_get_inode(struct super_block *sb, · 141 unmodified lines
292292 struct ipc_namespace *ipc_ns, umode_t mode,
293293 struct mq_attr *attr)
294294 {
295− struct user_struct *u = current_user();
296295 struct inode *inode;
297296 int ret = -ENOMEM;
298297
@@ -321,7 +320,7 @@ static struct inode *mqueue_get_inode(struct super_block *sb, · 22 unmodified lines
321320 info->notify_owner = NULL;
322321 info->notify_user_ns = NULL;
323322 info->qsize = 0;
324− info->user = NULL; /* set when all is ok */
323+ info->ucounts = NULL; /* set when all is ok */
325324 info->msg_tree = RB_ROOT;
326325 info->msg_tree_rightmost = NULL;
327326 info->node_cache = NULL;
@@ -371,19 +370,23 @@ static struct inode *mqueue_get_inode(struct super_block *sb, · 43 unmodified lines
371370 if (mq_bytes + mq_treesize < mq_bytes)
372371 goto out_inode;
373372 mq_bytes += mq_treesize;
374− spin_lock(&mq_lock);
375− if (u->mq_bytes + mq_bytes < u->mq_bytes ||
376− u->mq_bytes + mq_bytes > rlimit(RLIMIT_MSGQUEUE)) {
373+ info->ucounts = get_ucounts(current_ucounts());
374+ if (info->ucounts) {
375+ long msgqueue;
376+
377+ spin_lock(&mq_lock);
378+ msgqueue = inc_rlimit_ucounts(info->ucounts, UCOUNT_RLIMIT_MSGQUEUE, mq_bytes);
379+ if (msgqueue == LONG_MAX || msgqueue > rlimit(RLIMIT_MSGQUEUE)) {
380+ dec_rlimit_ucounts(info->ucounts, UCOUNT_RLIMIT_MSGQUEUE, mq_bytes);
381+ spin_unlock(&mq_lock);
382+ put_ucounts(info->ucounts);
383+ info->ucounts = NULL;
384+ /* mqueue_evict_inode() releases info->messages */
385+ ret = -EMFILE;
386+ goto out_inode;
387+ }
377388 spin_unlock(&mq_lock);
378− /* mqueue_evict_inode() releases info->messages */
379− ret = -EMFILE;
380− goto out_inode;
381389 }
382− u->mq_bytes += mq_bytes;
383− spin_unlock(&mq_lock);
384−
385− /* all is ok */
386− info->user = get_uid(u);
387390 } else if (S_ISDIR(mode)) {
388391 inc_nlink(inode);
389392 /* Some things misbehave if size == 0 on a directory */
@@ -497,7 +500,6 @@ static void mqueue_free_inode(struct inode *inode) · 107 unmodified lines
497500 static void mqueue_evict_inode(struct inode *inode)
498501 {
499502 struct mqueue_inode_info *info;
500− struct user_struct *user;
501503 struct ipc_namespace *ipc_ns;
502504 struct msg_msg *msg, *nmsg;
503505 LIST_HEAD(tmp_msg);
@@ -520,8 +522,7 @@ static void mqueue_evict_inode(struct inode *inode) · 16 unmodified lines
520522 free_msg(msg);
521523 }
522524
523− user = info->user;
524− if (user) {
525+ if (info->ucounts) {
525526 unsigned long mq_bytes, mq_treesize;
526527
527528 /* Total amount of bytes accounted for the mqueue */
@@ -533,7 +534,7 @@ static void mqueue_evict_inode(struct inode *inode) · 5 unmodified lines
533534 info->attr.mq_msgsize);
534535
535536 spin_lock(&mq_lock);
536− user->mq_bytes -= mq_bytes;
537+ dec_rlimit_ucounts(info->ucounts, UCOUNT_RLIMIT_MSGQUEUE, mq_bytes);
537538 /*
538539 * get_ns_from_inode() ensures that the
539540 * (ipc_ns = sb->s_fs_info) is either a valid ipc_ns
@@ -543,7 +544,8 @@ static void mqueue_evict_inode(struct inode *inode) · 3 unmodified lines
543544 if (ipc_ns)
544545 ipc_ns->mq_queues_count--;
545546 spin_unlock(&mq_lock);
546− free_uid(user);
547+ put_ucounts(info->ucounts);
548+ info->ucounts = NULL;
547549 }
548550 if (ipc_ns)
549551 put_ipc_ns(ipc_ns);
ipc/shm.c+13−13
@@ -60,7 +60,7 @@ struct shmid_kernel /* private to the kernel */ · 59 unmodified lines
6060 time64_t shm_ctim;
6161 struct pid *shm_cprid;
6262 struct pid *shm_lprid;
63− struct user_struct *mlock_user;
63+ struct ucounts *mlock_ucounts;
6464
6565 /* The task created the shm object. NULL if the task is dead. */
6666 struct task_struct *shm_creator;
@@ -286,10 +286,10 @@ static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp) · 219 unmodified lines
286286 shm_rmid(ns, shp);
287287 shm_unlock(shp);
288288 if (!is_file_hugepages(shm_file))
289− shmem_lock(shm_file, 0, shp->mlock_user);
290− else if (shp->mlock_user)
289+ shmem_lock(shm_file, 0, shp->mlock_ucounts);
290+ else if (shp->mlock_ucounts)
291291 user_shm_unlock(i_size_read(file_inode(shm_file)),
292− shp->mlock_user);
292+ shp->mlock_ucounts);
293293 fput(shm_file);
294294 ipc_update_pid(&shp->shm_cprid, NULL);
295295 ipc_update_pid(&shp->shm_lprid, NULL);
@@ -625,7 +625,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) · 329 unmodified lines
625625
626626 shp->shm_perm.key = key;
627627 shp->shm_perm.mode = (shmflg & S_IRWXUGO);
628− shp->mlock_user = NULL;
628+ shp->mlock_ucounts = NULL;
629629
630630 shp->shm_perm.security = NULL;
631631 error = security_shm_alloc(&shp->shm_perm);
@@ -650,7 +650,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) · 18 unmodified lines
650650 if (shmflg & SHM_NORESERVE)
651651 acctflag = VM_NORESERVE;
652652 file = hugetlb_file_setup(name, hugesize, acctflag,
653− &shp->mlock_user, HUGETLB_SHMFS_INODE,
653+ &shp->mlock_ucounts, HUGETLB_SHMFS_INODE,
654654 (shmflg >> SHM_HUGE_SHIFT) & SHM_HUGE_MASK);
655655 } else {
656656 /*
@@ -698,8 +698,8 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) · 41 unmodified lines
698698 no_id:
699699 ipc_update_pid(&shp->shm_cprid, NULL);
700700 ipc_update_pid(&shp->shm_lprid, NULL);
701− if (is_file_hugepages(file) && shp->mlock_user)
702− user_shm_unlock(size, shp->mlock_user);
701+ if (is_file_hugepages(file) && shp->mlock_ucounts)
702+ user_shm_unlock(size, shp->mlock_ucounts);
703703 fput(file);
704704 ipc_rcu_putref(&shp->shm_perm, shm_rcu_free);
705705 return error;
@@ -1105,12 +1105,12 @@ static int shmctl_do_lock(struct ipc_namespace *ns, int shmid, int cmd) · 399 unmodified lines
11051105 goto out_unlock0;
11061106
11071107 if (cmd == SHM_LOCK) {
1108− struct user_struct *user = current_user();
1108+ struct ucounts *ucounts = current_ucounts();
11091109
1110− err = shmem_lock(shm_file, 1, user);
1110+ err = shmem_lock(shm_file, 1, ucounts);
11111111 if (!err && !(shp->shm_perm.mode & SHM_LOCKED)) {
11121112 shp->shm_perm.mode |= SHM_LOCKED;
1113− shp->mlock_user = user;
1113+ shp->mlock_ucounts = ucounts;
11141114 }
11151115 goto out_unlock0;
11161116 }
@@ -1118,9 +1118,9 @@ static int shmctl_do_lock(struct ipc_namespace *ns, int shmid, int cmd) · 1 unmodified line
11181118 /* SHM_UNLOCK */
11191119 if (!(shp->shm_perm.mode & SHM_LOCKED))
11201120 goto out_unlock0;
1121− shmem_lock(shm_file, 0, shp->mlock_user);
1121+ shmem_lock(shm_file, 0, shp->mlock_ucounts);
11221122 shp->shm_perm.mode &= ~SHM_LOCKED;
1123− shp->mlock_user = NULL;
1123+ shp->mlock_ucounts = NULL;
11241124 get_file(shm_file);
11251125 ipc_unlock_object(&shp->shm_perm);
11261126 rcu_read_unlock();
kernel/cred.c+46−5
@@ -60,6 +60,7 @@ struct cred init_cred = { · 59 unmodified lines
6060 .user = INIT_USER,
6161 .user_ns = &init_user_ns,
6262 .group_info = &init_groups,
63+ .ucounts = &init_ucounts,
6364 };
6465
6566 static 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
119120 if (cred->group_info)
120121 put_group_info(cred->group_info);
121122 free_uid(cred->user);
123+ if (cred->ucounts)
124+ put_ucounts(cred->ucounts);
122125 put_user_ns(cred->user_ns);
123126 kmem_cache_free(cred_jar, cred);
124127 }
@@ -222,6 +225,7 @@ struct cred *cred_alloc_blank(void) · 97 unmodified lines
222225 #ifdef CONFIG_DEBUG_CREDENTIALS
223226 new->magic = CRED_MAGIC;
224227 #endif
228+ new->ucounts = get_ucounts(&init_ucounts);
225229
226230 if (security_cred_alloc_blank(new, GFP_KERNEL_ACCOUNT) < 0)
227231 goto error;
@@ -284,6 +288,11 @@ struct cred *prepare_creds(void) · 56 unmodified lines
284288
285289 if (security_prepare_creds(new, old, GFP_KERNEL_ACCOUNT) < 0)
286290 goto error;
291+
292+ new->ucounts = get_ucounts(new->ucounts);
293+ if (!new->ucounts)
294+ goto error;
295+
287296 validate_creds(new);
288297 return new;
289298
@@ -351,7 +360,7 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) · 61 unmodified lines
351360 kdebug("share_creds(%p{%d,%d})",
352361 p->cred, atomic_read(&p->cred->usage),
353362 read_cred_subscribers(p->cred));
354− atomic_inc(&p->cred->user->processes);
363+ inc_rlimit_ucounts(task_ucounts(p), UCOUNT_RLIMIT_NPROC, 1);
355364 return 0;
356365 }
357366
@@ -363,6 +372,9 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) · 5 unmodified lines
363372 ret = create_user_ns(new);
364373 if (ret < 0)
365374 goto error_put;
375+ ret = set_cred_ucounts(new);
376+ if (ret < 0)
377+ goto error_put;
366378 }
367379
368380 #ifdef CONFIG_KEYS
@@ -384,8 +396,8 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) · 15 unmodified lines
384396 }
385397 #endif
386398
387− atomic_inc(&new->user->processes);
388399 p->cred = p->real_cred = get_cred(new);
400+ inc_rlimit_ucounts(task_ucounts(p), UCOUNT_RLIMIT_NPROC, 1);
389401 alter_cred_subscribers(new, 2);
390402 validate_creds(new);
391403 return 0;
@@ -485,12 +497,12 @@ int commit_creds(struct cred *new) · 93 unmodified lines
485497 * in set_user().
486498 */
487499 alter_cred_subscribers(new, 2);
488− if (new->user != old->user)
489− atomic_inc(&new->user->processes);
500+ if (new->user != old->user || new->user_ns != old->user_ns)
501+ inc_rlimit_ucounts(new->ucounts, UCOUNT_RLIMIT_NPROC, 1);
490502 rcu_assign_pointer(task->real_cred, new);
491503 rcu_assign_pointer(task->cred, new);
492504 if (new->user != old->user)
493− atomic_dec(&old->user->processes);
505+ dec_rlimit_ucounts(old->ucounts, UCOUNT_RLIMIT_NPROC, 1);
494506 alter_cred_subscribers(old, -2);
495507
496508 /* send notifications */
@@ -653,6 +665,31 @@ int cred_fscmp(const struct cred *a, const struct cred *b) · 156 unmodified lines
653665 }
654666 EXPORT_SYMBOL(cred_fscmp);
655667
668+int 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+
656693 /*
657694 * initialise the credentials stuff
658695 */
@@ -719,6 +756,10 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon) · 60 unmodified lines
719756 if (security_prepare_creds(new, old, GFP_KERNEL_ACCOUNT) < 0)
720757 goto error;
721758
759+ new->ucounts = get_ucounts(new->ucounts);
760+ if (!new->ucounts)
761+ goto error;
762+
722763 put_cred(old);
723764 validate_creds(new);
724765 return new;
kernel/exit.c+1−1
@@ -188,7 +188,7 @@ repeat: · 187 unmodified lines
188188 /* don't need to get the RCU readlock here - the process is dead and
189189 * can't be modifying its own credentials. But shut RCU-lockdep up */
190190 rcu_read_lock();
191− atomic_dec(&__task_cred(p)->user->processes);
191+ dec_rlimit_ucounts(task_ucounts(p), UCOUNT_RLIMIT_NPROC, 1);
192192 rcu_read_unlock();
193193
194194 cgroup_release(p);
kernel/fork.c+14−4
@@ -825,9 +825,14 @@ void __init fork_init(void) · 824 unmodified lines
825825 init_task.signal->rlim[RLIMIT_SIGPENDING] =
826826 init_task.signal->rlim[RLIMIT_NPROC];
827827
828− for (i = 0; i < UCOUNT_COUNTS; i++)
828+ for (i = 0; i < MAX_PER_NAMESPACE_UCOUNTS; i++)
829829 init_user_ns.ucount_max[i] = max_threads/2;
830830
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+
831836 #ifdef CONFIG_VMAP_STACK
832837 cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "fork:vm_stack_cache",
833838 NULL, free_vm_stack_cache);
@@ -1978,8 +1983,7 @@ static __latent_entropy struct task_struct *copy_process( · 1144 unmodified lines
19781983 DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled);
19791984 #endif
19801985 retval = -EAGAIN;
1981− if (atomic_read(&p->real_cred->user->processes) >=
1982− task_rlimit(p, RLIMIT_NPROC)) {
1986+ if (is_ucounts_overlimit(task_ucounts(p), UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC))) {
19831987 if (p->real_cred->user != INIT_USER &&
19841988 !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN))
19851989 goto bad_fork_free;
@@ -2388,7 +2392,7 @@ bad_fork_cleanup_threadgroup_lock: · 402 unmodified lines
23882392 #endif
23892393 delayacct_tsk_free(p);
23902394 bad_fork_cleanup_count:
2391− atomic_dec(&p->cred->user->processes);
2395+ dec_rlimit_ucounts(task_ucounts(p), UCOUNT_RLIMIT_NPROC, 1);
23922396 exit_creds(p);
23932397 bad_fork_free:
23942398 WRITE_ONCE(p->__state, TASK_DEAD);
@@ -3001,6 +3005,12 @@ int ksys_unshare(unsigned long unshare_flags) · 606 unmodified lines
30013005 if (err)
30023006 goto bad_unshare_cleanup_cred;
30033007
3008+ if (new_cred) {
3009+ err = set_cred_ucounts(new_cred);
3010+ if (err)
3011+ goto bad_unshare_cleanup_cred;
3012+ }
3013+
30043014 if (new_fs || new_fd || do_sysvsem || new_cred || new_nsproxy) {
30053015 if (do_sysvsem) {
30063016 /*
kernel/signal.c+13−12
@@ -412,8 +412,8 @@ __sigqueue_alloc(int sig, struct task_struct *t, gfp_t gfp_flags, · 411 unmodified lines
412412 int override_rlimit, const unsigned int sigqueue_flags)
413413 {
414414 struct sigqueue *q = NULL;
415− struct user_struct *user;
416− int sigpending;
415+ struct ucounts *ucounts = NULL;
416+ long sigpending;
417417
418418 /*
419419 * 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
424424 * changes from/to zero.
425425 */
426426 rcu_read_lock();
427− user = __task_cred(t)->user;
428− sigpending = atomic_inc_return(&user->sigpending);
427+ ucounts = task_ucounts(t);
428+ sigpending = inc_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_SIGPENDING, 1);
429429 if (sigpending == 1)
430− get_uid(user);
430+ ucounts = get_ucounts(ucounts);
431431 rcu_read_unlock();
432432
433− if (override_rlimit || likely(sigpending <= task_rlimit(t, RLIMIT_SIGPENDING))) {
433+ if (override_rlimit || (sigpending < LONG_MAX && sigpending <= task_rlimit(t, RLIMIT_SIGPENDING))) {
434434 q = kmem_cache_alloc(sigqueue_cachep, gfp_flags);
435435 } else {
436436 print_dropped_signal(sig);
437437 }
438438
439439 if (unlikely(q == NULL)) {
440− if (atomic_dec_and_test(&user->sigpending))
441− free_uid(user);
440+ if (ucounts && dec_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_SIGPENDING, 1))
441+ put_ucounts(ucounts);
442442 } else {
443443 INIT_LIST_HEAD(&q->list);
444444 q->flags = sigqueue_flags;
445− q->user = user;
445+ q->ucounts = ucounts;
446446 }
447−
448447 return q;
449448 }
450449
@@ -452,8 +451,10 @@ static void __sigqueue_free(struct sigqueue *q) · 1 unmodified line
452451 {
453452 if (q->flags & SIGQUEUE_PREALLOC)
454453 return;
455− if (atomic_dec_and_test(&q->user->sigpending))
456− free_uid(q->user);
454+ if (q->ucounts && dec_rlimit_ucounts(q->ucounts, UCOUNT_RLIMIT_SIGPENDING, 1)) {
455+ put_ucounts(q->ucounts);
456+ q->ucounts = NULL;
457+ }
457458 kmem_cache_free(sigqueue_cachep, q);
458459 }
459460
kernel/sys.c+13−1
@@ -479,7 +479,7 @@ static int set_user(struct cred *new) · 478 unmodified lines
479479 * for programs doing set*uid()+execve() by harmlessly deferring the
480480 * failure to the execve() stage.
481481 */
482− if (atomic_read(&new_user->processes) >= rlimit(RLIMIT_NPROC) &&
482+ if (is_ucounts_overlimit(new->ucounts, UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC)) &&
483483 new_user != INIT_USER)
484484 current->flags |= PF_NPROC_EXCEEDED;
485485 else
@@ -558,6 +558,10 @@ long __sys_setreuid(uid_t ruid, uid_t euid) · 72 unmodified lines
558558 if (retval < 0)
559559 goto error;
560560
561+ retval = set_cred_ucounts(new);
562+ if (retval < 0)
563+ goto error;
564+
561565 return commit_creds(new);
562566
563567 error:
@@ -616,6 +620,10 @@ long __sys_setuid(uid_t uid) · 52 unmodified lines
616620 if (retval < 0)
617621 goto error;
618622
623+ retval = set_cred_ucounts(new);
624+ if (retval < 0)
625+ goto error;
626+
619627 return commit_creds(new);
620628
621629 error:
@@ -691,6 +699,10 @@ long __sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) · 69 unmodified lines
691699 if (retval < 0)
692700 goto error;
693701
702+ retval = set_cred_ucounts(new);
703+ if (retval < 0)
704+ goto error;
705+
694706 return commit_creds(new);
695707
696708 error:
kernel/ucount.c+91−25
@@ -8,6 +8,12 @@ · 7 unmodified lines
88 #include <linux/kmemleak.h>
99 #include <linux/user_namespace.h>
1010
11+struct ucounts init_ucounts = {
12+ .ns = &init_user_ns,
13+ .uid = GLOBAL_ROOT_UID,
14+ .count = ATOMIC_INIT(1),
15+};
16+
1117 #define UCOUNTS_HASHTABLE_BITS 10
1218 static struct hlist_head ucounts_hashtable[(1 << UCOUNTS_HASHTABLE_BITS)];
1319 static DEFINE_SPINLOCK(ucounts_lock);
@@ -78,6 +84,10 @@ static struct ctl_table user_table[] = { · 64 unmodified lines
7884 UCOUNT_ENTRY("max_fanotify_groups"),
7985 UCOUNT_ENTRY("max_fanotify_marks"),
8086 #endif
87+ { },
88+ { },
89+ { },
90+ { },
8191 { }
8292 };
8393 #endif /* CONFIG_SYSCTL */
@@ -129,7 +139,24 @@ static struct ucounts *find_ucounts(struct user_namespace *ns, kuid_t uid, struc · 45 unmodified lines
129139 return NULL;
130140 }
131141
132−static struct ucounts *get_ucounts(struct user_namespace *ns, kuid_t uid)
142+static 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+
150+struct 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+
159+struct ucounts *alloc_ucounts(struct user_namespace *ns, kuid_t uid)
133160 {
134161 struct hlist_head *hashent = ucounts_hashentry(ns, uid);
135162 struct ucounts *ucounts, *new;
@@ -145,7 +172,7 @@ static struct ucounts *get_ucounts(struct user_namespace *ns, kuid_t uid) · 9 unmodified lines
145172
146173 new->ns = ns;
147174 new->uid = uid;
148− new->count = 0;
175+ atomic_set(&new->count, 1);
149176
150177 spin_lock_irq(&ucounts_lock);
151178 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
153180 kfree(new);
154181 } else {
155182 hlist_add_head(&new->node, hashent);
156− ucounts = new;
183+ spin_unlock_irq(&ucounts_lock);
184+ return new;
157185 }
158186 }
159− if (ucounts->count == INT_MAX)
160− ucounts = NULL;
161− else
162− ucounts->count += 1;
163187 spin_unlock_irq(&ucounts_lock);
188+ ucounts = get_ucounts(ucounts);
164189 return ucounts;
165190 }
166191
167−static void put_ucounts(struct ucounts *ucounts)
192+void put_ucounts(struct ucounts *ucounts)
168193 {
169194 unsigned long flags;
170195
171− spin_lock_irqsave(&ucounts_lock, flags);
172− ucounts->count -= 1;
173− if (!ucounts->count)
196+ if (atomic_dec_and_test(&ucounts->count)) {
197+ spin_lock_irqsave(&ucounts_lock, flags);
174198 hlist_del_init(&ucounts->node);
175− else
176− ucounts = NULL;
177− spin_unlock_irqrestore(&ucounts_lock, flags);
178−
179− kfree(ucounts);
199+ spin_unlock_irqrestore(&ucounts_lock, flags);
200+ kfree(ucounts);
201+ }
180202 }
181203
182−static inline bool atomic_inc_below(atomic_t *v, int u)
204+static inline bool atomic_long_inc_below(atomic_long_t *v, int u)
183205 {
184− int c, old;
185− c = atomic_read(v);
206+ long c, old;
207+ c = atomic_long_read(v);
186208 for (;;) {
187209 if (unlikely(c >= u))
188210 return false;
189− old = atomic_cmpxchg(v, c, c+1);
211+ old = atomic_long_cmpxchg(v, c, c+1);
190212 if (likely(old == c))
191213 return true;
192214 c = old;
@@ -198,19 +220,19 @@ struct ucounts *inc_ucount(struct user_namespace *ns, kuid_t uid, · 5 unmodified lines
198220 {
199221 struct ucounts *ucounts, *iter, *bad;
200222 struct user_namespace *tns;
201− ucounts = get_ucounts(ns, uid);
223+ ucounts = alloc_ucounts(ns, uid);
202224 for (iter = ucounts; iter; iter = tns->ucounts) {
203− int max;
225+ long max;
204226 tns = iter->ns;
205227 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))
207229 goto fail;
208230 }
209231 return ucounts;
210232 fail:
211233 bad = iter;
212234 for (iter = ucounts; iter != bad; iter = iter->ns->ucounts)
213− atomic_dec(&iter->ucount[type]);
235+ atomic_long_dec(&iter->ucount[type]);
214236
215237 put_ucounts(ucounts);
216238 return NULL;
@@ -220,12 +242,54 @@ void dec_ucount(struct ucounts *ucounts, enum ucount_type type) · 3 unmodified lines
220242 {
221243 struct ucounts *iter;
222244 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]);
224246 WARN_ON_ONCE(dec < 0);
225247 }
226248 put_ucounts(ucounts);
227249 }
228250
251+long 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+
267+bool 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+
280+bool 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+
229293 static __init int user_namespace_sysctl_init(void)
230294 {
231295 #ifdef CONFIG_SYSCTL
@@ -241,6 +305,8 @@ static __init int user_namespace_sysctl_init(void) · 9 unmodified lines
241305 BUG_ON(!user_header);
242306 BUG_ON(!setup_userns_sysctls(&init_user_ns));
243307 #endif
308+ hlist_add_ucounts(&init_ucounts);
309+ inc_rlimit_ucounts(&init_ucounts, UCOUNT_RLIMIT_NPROC, 1);
244310 return 0;
245311 }
246312 subsys_initcall(user_namespace_sysctl_init);
kernel/user.c+0−3
@@ -98,9 +98,6 @@ static DEFINE_SPINLOCK(uidhash_lock); · 97 unmodified lines
9898 /* root_user.__count is 1, for init task cred */
9999 struct user_struct root_user = {
100100 .__count = REFCOUNT_INIT(1),
101− .processes = ATOMIC_INIT(1),
102− .sigpending = ATOMIC_INIT(0),
103− .locked_shm = 0,
104101 .uid = GLOBAL_ROOT_UID,
105102 .ratelimit = RATELIMIT_STATE_INIT(root_user.ratelimit, 0, 0),
106103 };
kernel/user_namespace.c+8−1
@@ -119,9 +119,13 @@ int create_user_ns(struct cred *new) · 118 unmodified lines
119119 ns->owner = owner;
120120 ns->group = group;
121121 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++) {
123123 ns->ucount_max[i] = INT_MAX;
124124 }
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));
125129 ns->ucounts = ucounts;
126130
127131 /* 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
13401344 put_user_ns(cred->user_ns);
13411345 set_cred_user_ns(cred, get_user_ns(user_ns));
13421346
1347+ if (set_cred_ucounts(cred) < 0)
1348+ return -EINVAL;
1349+
13431350 return 0;
13441351 }
13451352
mm/memfd.c+2−2
@@ -297,9 +297,9 @@ SYSCALL_DEFINE2(memfd_create, · 296 unmodified lines
297297 }
298298
299299 if (flags & MFD_HUGETLB) {
300− struct user_struct *user = NULL;
300+ struct ucounts *ucounts = NULL;
301301
302− file = hugetlb_file_setup(name, 0, VM_NORESERVE, &user,
302+ file = hugetlb_file_setup(name, 0, VM_NORESERVE, &ucounts,
303303 HUGETLB_ANONHUGE_INODE,
304304 (flags >> MFD_HUGE_SHIFT) &
305305 MFD_HUGE_MASK);
mm/mlock.c+14−8
@@ -817,9 +817,10 @@ SYSCALL_DEFINE0(munlockall) · 816 unmodified lines
817817 */
818818 static DEFINE_SPINLOCK(shmlock_user_lock);
819819
820−int user_shm_lock(size_t size, struct user_struct *user)
820+int user_shm_lock(size_t size, struct ucounts *ucounts)
821821 {
822822 unsigned long lock_limit, locked;
823+ long memlock;
823824 int allowed = 0;
824825
825826 locked = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
@@ -828,21 +829,26 @@ int user_shm_lock(size_t size, struct user_struct *user) · 2 unmodified lines
828829 allowed = 1;
829830 lock_limit >>= PAGE_SHIFT;
830831 spin_lock(&shmlock_user_lock);
831− if (!allowed &&
832− locked + user->locked_shm > lock_limit && !capable(CAP_IPC_LOCK))
832+ memlock = inc_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_MEMLOCK, locked);
833+
834+ if (!allowed && (memlock == LONG_MAX || memlock > lock_limit) && !capable(CAP_IPC_LOCK)) {
835+ dec_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_MEMLOCK, locked);
836+ goto out;
837+ }
838+ if (!get_ucounts(ucounts)) {
839+ dec_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_MEMLOCK, locked);
833840 goto out;
834− get_uid(user);
835− user->locked_shm += locked;
841+ }
836842 allowed = 1;
837843 out:
838844 spin_unlock(&shmlock_user_lock);
839845 return allowed;
840846 }
841847
842−void user_shm_unlock(size_t size, struct user_struct *user)
848+void user_shm_unlock(size_t size, struct ucounts *ucounts)
843849 {
844850 spin_lock(&shmlock_user_lock);
845− user->locked_shm -= (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
851+ dec_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_MEMLOCK, (size + PAGE_SIZE - 1) >> PAGE_SHIFT);
846852 spin_unlock(&shmlock_user_lock);
847− free_uid(user);
853+ put_ucounts(ucounts);
848854 }
mm/mmap.c+2−2
@@ -1611,7 +1611,7 @@ unsigned long ksys_mmap_pgoff(unsigned long addr, unsigned long len, · 1610 unmodified lines
16111611 goto out_fput;
16121612 }
16131613 } else if (flags & MAP_HUGETLB) {
1614− struct user_struct *user = NULL;
1614+ struct ucounts *ucounts = NULL;
16151615 struct hstate *hs;
16161616
16171617 hs = hstate_sizelog((flags >> MAP_HUGE_SHIFT) & MAP_HUGE_MASK);
@@ -1627,7 +1627,7 @@ unsigned long ksys_mmap_pgoff(unsigned long addr, unsigned long len, · 9 unmodified lines
16271627 */
16281628 file = hugetlb_file_setup(HUGETLB_ANON_FILE, len,
16291629 VM_NORESERVE,
1630− &user, HUGETLB_ANONHUGE_INODE,
1630+ &ucounts, HUGETLB_ANONHUGE_INODE,
16311631 (flags >> MAP_HUGE_SHIFT) & MAP_HUGE_MASK);
16321632 if (IS_ERR(file))
16331633 return PTR_ERR(file);
mm/shmem.c+5−5
@@ -2227,7 +2227,7 @@ static struct mempolicy *shmem_get_policy(struct vm_area_struct *vma, · 2226 unmodified lines
22272227 }
22282228 #endif
22292229
2230−int shmem_lock(struct file *file, int lock, struct user_struct *user)
2230+int shmem_lock(struct file *file, int lock, struct ucounts *ucounts)
22312231 {
22322232 struct inode *inode = file_inode(file);
22332233 struct shmem_inode_info *info = SHMEM_I(inode);
@@ -2239,13 +2239,13 @@ int shmem_lock(struct file *file, int lock, struct user_struct *user) · 5 unmodified lines
22392239 * no serialization needed when called from shm_destroy().
22402240 */
22412241 if (lock && !(info->flags & VM_LOCKED)) {
2242− if (!user_shm_lock(inode->i_size, user))
2242+ if (!user_shm_lock(inode->i_size, ucounts))
22432243 goto out_nomem;
22442244 info->flags |= VM_LOCKED;
22452245 mapping_set_unevictable(file->f_mapping);
22462246 }
2247− if (!lock && (info->flags & VM_LOCKED) && user) {
2248− user_shm_unlock(inode->i_size, user);
2247+ if (!lock && (info->flags & VM_LOCKED) && ucounts) {
2248+ user_shm_unlock(inode->i_size, ucounts);
22492249 info->flags &= ~VM_LOCKED;
22502250 mapping_clear_unevictable(file->f_mapping);
22512251 }
@@ -4092,7 +4092,7 @@ int shmem_unuse(unsigned int type, bool frontswap, · 1840 unmodified lines
40924092 return 0;
40934093 }
40944094
4095−int shmem_lock(struct file *file, int lock, struct user_struct *user)
4095+int shmem_lock(struct file *file, int lock, struct ucounts *ucounts)
40964096 {
40974097 return 0;
40984098 }
tools/testing/selftests/Makefile+1−0
@@ -49,6 +49,7 @@ TARGETS += proc · 48 unmodified lines
4949 TARGETS += pstore
5050 TARGETS += ptrace
5151 TARGETS += openat2
52+TARGETS += rlimits
5253 TARGETS += rseq
5354 TARGETS += rtc
5455 TARGETS += seccomp
tools/testing/selftests/rlimits/.gitignore+2−0
@@ -0,0 +1,2 @@
1+# SPDX-License-Identifier: GPL-2.0-only
2+rlimits-per-userns
tools/testing/selftests/rlimits/Makefile+6−0
@@ -0,0 +1,6 @@
1+# SPDX-License-Identifier: GPL-2.0-or-later
2+
3+CFLAGS += -Wall -O2 -g
4+TEST_GEN_PROGS := rlimits-per-userns
5+
6+include ../lib.mk
tools/testing/selftests/rlimits/config+1−0
@@ -0,0 +1 @@
1+CONFIG_USER_NS=y
tools/testing/selftests/rlimits/rlimits-per-userns.c+161−0
@@ -0,0 +1,161 @@
1+// SPDX-License-Identifier: GPL-2.0-or-later
2+/*
3+ * Author: Alexey Gladkov <gladkov.alexey@gmail.com>
4+ */
5+#define _GNU_SOURCE
6+#include <sys/types.h>
7+#include <sys/wait.h>
8+#include <sys/time.h>
9+#include <sys/resource.h>
10+#include <sys/prctl.h>
11+#include <sys/stat.h>
12+
13+#include <unistd.h>
14+#include <stdlib.h>
15+#include <stdio.h>
16+#include <string.h>
17+#include <sched.h>
18+#include <signal.h>
19+#include <limits.h>
20+#include <fcntl.h>
21+#include <errno.h>
22+#include <err.h>
23+
24+#define NR_CHILDS 2
25+
26+static char *service_prog;
27+static uid_t user = 60000;
28+static uid_t group = 60000;
29+
30+static void setrlimit_nproc(rlim_t n)
31+{
32+ pid_t pid = getpid();
33+ struct rlimit limit = {
34+ .rlim_cur = n,
35+ .rlim_max = n
36+ };
37+
38+ warnx("(pid=%d): Setting RLIMIT_NPROC=%ld", pid, n);
39+
40+ if (setrlimit(RLIMIT_NPROC, &limit) < 0)
41+ err(EXIT_FAILURE, "(pid=%d): setrlimit(RLIMIT_NPROC)", pid);
42+}
43+
44+static pid_t fork_child(void)
45+{
46+ pid_t pid = fork();
47+
48+ if (pid < 0)
49+ err(EXIT_FAILURE, "fork");
50+
51+ if (pid > 0)
52+ return pid;
53+
54+ pid = getpid();
55+
56+ warnx("(pid=%d): New process starting ...", pid);
57+
58+ if (prctl(PR_SET_PDEATHSIG, SIGKILL) < 0)
59+ err(EXIT_FAILURE, "(pid=%d): prctl(PR_SET_PDEATHSIG)", pid);
60+
61+ signal(SIGUSR1, SIG_DFL);
62+
63+ warnx("(pid=%d): Changing to uid=%d, gid=%d", pid, user, group);
64+
65+ if (setgid(group) < 0)
66+ err(EXIT_FAILURE, "(pid=%d): setgid(%d)", pid, group);
67+ if (setuid(user) < 0)
68+ err(EXIT_FAILURE, "(pid=%d): setuid(%d)", pid, user);
69+
70+ warnx("(pid=%d): Service running ...", pid);
71+
72+ warnx("(pid=%d): Unshare user namespace", pid);
73+ if (unshare(CLONE_NEWUSER) < 0)
74+ err(EXIT_FAILURE, "unshare(CLONE_NEWUSER)");
75+
76+ char *const argv[] = { "service", NULL };
77+ char *const envp[] = { "I_AM_SERVICE=1", NULL };
78+
79+ warnx("(pid=%d): Executing real service ...", pid);
80+
81+ execve(service_prog, argv, envp);
82+ err(EXIT_FAILURE, "(pid=%d): execve", pid);
83+}
84+
85+int main(int argc, char **argv)
86+{
87+ size_t i;
88+ pid_t child[NR_CHILDS];
89+ int wstatus[NR_CHILDS];
90+ int childs = NR_CHILDS;
91+ pid_t pid;
92+
93+ if (getenv("I_AM_SERVICE")) {
94+ pause();
95+ exit(EXIT_SUCCESS);
96+ }
97+
98+ service_prog = argv[0];
99+ pid = getpid();
100+
101+ warnx("(pid=%d) Starting testcase", pid);
102+
103+ /*
104+ * This rlimit is not a problem for root because it can be exceeded.
105+ */
106+ setrlimit_nproc(1);
107+
108+ for (i = 0; i < NR_CHILDS; i++) {
109+ child[i] = fork_child();
110+ wstatus[i] = 0;
111+ usleep(250000);
112+ }
113+
114+ while (1) {
115+ for (i = 0; i < NR_CHILDS; i++) {
116+ if (child[i] <= 0)
117+ continue;
118+
119+ errno = 0;
120+ pid_t ret = waitpid(child[i], &wstatus[i], WNOHANG);
121+
122+ if (!ret || (!WIFEXITED(wstatus[i]) && !WIFSIGNALED(wstatus[i])))
123+ continue;
124+
125+ if (ret < 0 && errno != ECHILD)
126+ warn("(pid=%d): waitpid(%d)", pid, child[i]);
127+
128+ child[i] *= -1;
129+ childs -= 1;
130+ }
131+
132+ if (!childs)
133+ break;
134+
135+ usleep(250000);
136+
137+ for (i = 0; i < NR_CHILDS; i++) {
138+ if (child[i] <= 0)
139+ continue;
140+ kill(child[i], SIGUSR1);
141+ }
142+ }
143+
144+ for (i = 0; i < NR_CHILDS; i++) {
145+ if (WIFEXITED(wstatus[i]))
146+ warnx("(pid=%d): pid %d exited, status=%d",
147+ pid, -child[i], WEXITSTATUS(wstatus[i]));
148+ else if (WIFSIGNALED(wstatus[i]))
149+ warnx("(pid=%d): pid %d killed by signal %d",
150+ pid, -child[i], WTERMSIG(wstatus[i]));
151+
152+ if (WIFSIGNALED(wstatus[i]) && WTERMSIG(wstatus[i]) == SIGUSR1)
153+ continue;
154+
155+ warnx("(pid=%d): Test failed", pid);
156+ exit(EXIT_FAILURE);
157+ }
158+
159+ warnx("(pid=%d): Test passed", pid);
160+ exit(EXIT_SUCCESS);
161+}

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