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
1360 WRITE_ONCE(me->self_exec_id, me->self_exec_id + 1);1360 WRITE_ONCE(me->self_exec_id, me->self_exec_id + 1);
1361 flush_signal_handlers(me, 0);1361 flush_signal_handlers(me, 0);
1362 1362
1363 retval = set_cred_ucounts(bprm->cred);
1364 if (retval < 0)
1365 goto out_unlock;
1366
1363 /*1367 /*
1364 * install the new credentials for this executable1368 * install the new credentials for this executable
1365 */1369 */
@@ -1874,7 +1878,7 @@ static int do_execveat_common(int fd, struct filename *filename, · 508 unmodified lines
1874 * whether NPROC limit is still exceeded.1878 * whether NPROC limit is still exceeded.
1875 */1879 */
1876 if ((current->flags & PF_NPROC_EXCEEDED) &&1880 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))) {
1878 retval = -EAGAIN;1882 retval = -EAGAIN;
1879 goto out_ret;1883 goto out_ret;
1880 }1884 }
fs/hugetlbfs/inode.c+8−8
@@ -1446,7 +1446,7 @@ static int get_hstate_idx(int page_size_log) · 1445 unmodified lines
1446 * otherwise hugetlb_reserve_pages reserves one less hugepages than intended.1446 * otherwise hugetlb_reserve_pages reserves one less hugepages than intended.
1447 */1447 */
1448struct file *hugetlb_file_setup(const char *name, size_t size,1448struct 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,
1450 int creat_flags, int page_size_log)1450 int creat_flags, int page_size_log)
1451{1451{
1452 struct inode *inode;1452 struct inode *inode;
@@ -1458,20 +1458,20 @@ struct file *hugetlb_file_setup(const char *name, size_t size, · 5 unmodified lines
1458 if (hstate_idx < 0)1458 if (hstate_idx < 0)
1459 return ERR_PTR(-ENODEV);1459 return ERR_PTR(-ENODEV);
1460 1460
1461 *user = NULL;1461 *ucounts = NULL;
1462 mnt = hugetlbfs_vfsmount[hstate_idx];1462 mnt = hugetlbfs_vfsmount[hstate_idx];
1463 if (!mnt)1463 if (!mnt)
1464 return ERR_PTR(-ENOENT);1464 return ERR_PTR(-ENOENT);
1465 1465
1466 if (creat_flags == HUGETLB_SHMFS_INODE && !can_do_hugetlb_shm()) {1466 if (creat_flags == HUGETLB_SHMFS_INODE && !can_do_hugetlb_shm()) {
1467 *user = current_user();1467 *ucounts = current_ucounts();
1468 if (user_shm_lock(size, *user)) {1468 if (user_shm_lock(size, *ucounts)) {
1469 task_lock(current);1469 task_lock(current);
1470 pr_warn_once("%s (%d): Using mlock ulimits for SHM_HUGETLB is deprecated\n",1470 pr_warn_once("%s (%d): Using mlock ulimits for SHM_HUGETLB is deprecated\n",
1471 current->comm, current->pid);1471 current->comm, current->pid);
1472 task_unlock(current);1472 task_unlock(current);
1473 } else {1473 } else {
1474 *user = NULL;1474 *ucounts = NULL;
1475 return ERR_PTR(-EPERM);1475 return ERR_PTR(-EPERM);
1476 }1476 }
1477 }1477 }
@@ -1498,9 +1498,9 @@ struct file *hugetlb_file_setup(const char *name, size_t size, · 20 unmodified lines
1498 1498
1499 iput(inode);1499 iput(inode);
1500out:1500out:
1501 if (*user) {1501 if (*ucounts) {
1502 user_shm_unlock(size, *user);1502 user_shm_unlock(size, *ucounts);
1503 *user = NULL;1503 *ucounts = NULL;
1504 }1504 }
1505 return file;1505 return file;
1506}1506}
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
284 collect_sigign_sigcatch(p, &ignored, &caught);284 collect_sigign_sigcatch(p, &ignored, &caught);
285 num_threads = get_nr_threads(p);285 num_threads = get_nr_threads(p);
286 rcu_read_lock(); /* FIXME: is this correct? */286 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);
288 rcu_read_unlock();288 rcu_read_unlock();
289 qlim = task_rlimit(p, RLIMIT_SIGPENDING);289 qlim = task_rlimit(p, RLIMIT_SIGPENDING);
290 unlock_task_sighand(p, &flags);290 unlock_task_sighand(p, &flags);
include/linux/cred.h+4−0
@@ -143,6 +143,7 @@ struct cred { · 142 unmodified lines
143#endif143#endif
144 struct user_struct *user; /* real user ID subscription */144 struct user_struct *user; /* real user ID subscription */
145 struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */145 struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */
146 struct ucounts *ucounts;
146 struct group_info *group_info; /* supplementary groups for euid/fsgid */147 struct group_info *group_info; /* supplementary groups for euid/fsgid */
147 /* RCU deletion */148 /* RCU deletion */
148 union {149 union {
@@ -169,6 +170,7 @@ extern int set_security_override_from_ctx(struct cred *, const char *); · 20 unmodified lines
169extern int set_create_files_as(struct cred *, struct inode *);170extern int set_create_files_as(struct cred *, struct inode *);
170extern int cred_fscmp(const struct cred *, const struct cred *);171extern int cred_fscmp(const struct cred *, const struct cred *);
171extern void __init cred_init(void);172extern void __init cred_init(void);
173extern int set_cred_ucounts(struct cred *);
172 174
173/*175/*
174 * check for validity of credentials176 * check for validity of credentials
@@ -369,6 +371,7 @@ static inline void put_cred(const struct cred *_cred) · 194 unmodified lines
369 371
370#define task_uid(task) (task_cred_xxx((task), uid))372#define task_uid(task) (task_cred_xxx((task), uid))
371#define task_euid(task) (task_cred_xxx((task), euid))373#define task_euid(task) (task_cred_xxx((task), euid))
374#define task_ucounts(task) (task_cred_xxx((task), ucounts))
372 375
373#define current_cred_xxx(xxx) \376#define current_cred_xxx(xxx) \
374({ \377({ \
@@ -385,6 +388,7 @@ static inline void put_cred(const struct cred *_cred) · 10 unmodified lines
385#define current_fsgid() (current_cred_xxx(fsgid))388#define current_fsgid() (current_cred_xxx(fsgid))
386#define current_cap() (current_cred_xxx(cap_effective))389#define current_cap() (current_cred_xxx(cap_effective))
387#define current_user() (current_cred_xxx(user))390#define current_user() (current_cred_xxx(user))
391#define current_ucounts() (current_cred_xxx(ucounts))
388 392
389extern struct user_namespace init_user_ns;393extern struct user_namespace init_user_ns;
390#ifdef CONFIG_USER_NS394#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
451extern const struct file_operations hugetlbfs_file_operations;451extern const struct file_operations hugetlbfs_file_operations;
452extern const struct vm_operations_struct hugetlb_vm_ops;452extern const struct vm_operations_struct hugetlb_vm_ops;
453struct file *hugetlb_file_setup(const char *name, size_t size, vm_flags_t acct,453struct 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,
455 int page_size_log);455 int page_size_log);
456 456
457static inline bool is_file_hugepages(struct file *file)457static inline bool is_file_hugepages(struct file *file)
@@ -471,7 +471,7 @@ static inline struct hstate *hstate_inode(struct inode *i) · 13 unmodified lines
471#define is_file_hugepages(file) false471#define is_file_hugepages(file) false
472static inline struct file *472static inline struct file *
473hugetlb_file_setup(const char *name, size_t size, vm_flags_t acctflag,473hugetlb_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,
475 int page_size_log)475 int page_size_log)
476{476{
477 return ERR_PTR(-ENOSYS);477 return ERR_PTR(-ENOSYS);
include/linux/mm.h+2−2
@@ -1709,8 +1709,8 @@ extern bool can_do_mlock(void); · 1708 unmodified lines
1709#else1709#else
1710static inline bool can_do_mlock(void) { return false; }1710static inline bool can_do_mlock(void) { return false; }
1711#endif1711#endif
1712extern int user_shm_lock(size_t, struct user_struct *);1712extern int user_shm_lock(size_t, struct ucounts *);
1713extern void user_shm_unlock(size_t, struct user_struct *);1713extern void user_shm_unlock(size_t, struct ucounts *);
1714 1714
1715/*1715/*
1716 * Parameter block passed down to zap_pte_range in exceptional cases.1716 * 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
12 */12 */
13struct user_struct {13struct user_struct {
14 refcount_t __count; /* reference count */14 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? */
17#ifdef CONFIG_EPOLL15#ifdef CONFIG_EPOLL
18 atomic_long_t epoll_watches; /* The number of file descriptors currently watched */16 atomic_long_t epoll_watches; /* The number of file descriptors currently watched */
19#endif17#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 ? */
25 unsigned long unix_inflight; /* How many files in flight in unix sockets */18 unsigned long unix_inflight; /* How many files in flight in unix sockets */
26 atomic_long_t pipe_bufs; /* how many pages are allocated in pipe buffers */19 atomic_long_t pipe_bufs; /* how many pages are allocated in pipe buffers */
27 20
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
65extern int shmem_zero_setup(struct vm_area_struct *);65extern int shmem_zero_setup(struct vm_area_struct *);
66extern unsigned long shmem_get_unmapped_area(struct file *, unsigned long addr,66extern unsigned long shmem_get_unmapped_area(struct file *, unsigned long addr,
67 unsigned long len, unsigned long pgoff, unsigned long flags);67 unsigned long len, unsigned long pgoff, unsigned long flags);
68extern int shmem_lock(struct file *file, int lock, struct user_struct *user);68extern int shmem_lock(struct file *file, int lock, struct ucounts *ucounts);
69#ifdef CONFIG_SHMEM69#ifdef CONFIG_SHMEM
70extern const struct address_space_operations shmem_aops;70extern const struct address_space_operations shmem_aops;
71static inline bool shmem_mapping(struct address_space *mapping)71static 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
13 __SIGINFO;13 __SIGINFO;
14} kernel_siginfo_t;14} kernel_siginfo_t;
15 15
16struct ucounts;
17
16/*18/*
17 * Real Time signals may be queued.19 * Real Time signals may be queued.
18 */20 */
@@ -21,7 +23,7 @@ struct sigqueue { · 2 unmodified lines
21 struct list_head list;23 struct list_head list;
22 int flags;24 int flags;
23 kernel_siginfo_t info;25 kernel_siginfo_t info;
24 struct user_struct *user;26 struct ucounts *ucounts;
25};27};
26 28
27/* flags values. */29/* flags values. */
include/linux/user_namespace.h+28−3
@@ -54,9 +54,15 @@ enum ucount_type { · 53 unmodified lines
54 UCOUNT_FANOTIFY_GROUPS,54 UCOUNT_FANOTIFY_GROUPS,
55 UCOUNT_FANOTIFY_MARKS,55 UCOUNT_FANOTIFY_MARKS,
56#endif56#endif
57 UCOUNT_RLIMIT_NPROC,
58 UCOUNT_RLIMIT_MSGQUEUE,
59 UCOUNT_RLIMIT_SIGPENDING,
60 UCOUNT_RLIMIT_MEMLOCK,
57 UCOUNT_COUNTS,61 UCOUNT_COUNTS,
58};62};
59 63
64#define MAX_PER_NAMESPACE_UCOUNTS UCOUNT_RLIMIT_NPROC
65
60struct user_namespace {66struct user_namespace {
61 struct uid_gid_map uid_map;67 struct uid_gid_map uid_map;
62 struct uid_gid_map gid_map;68 struct uid_gid_map gid_map;
@@ -92,23 +98,42 @@ struct user_namespace { · 29 unmodified lines
92 struct ctl_table_header *sysctls;98 struct ctl_table_header *sysctls;
93#endif99#endif
94 struct ucounts *ucounts;100 struct ucounts *ucounts;
95 int ucount_max[UCOUNT_COUNTS];101 long ucount_max[UCOUNT_COUNTS];
96} __randomize_layout;102} __randomize_layout;
97 103
98struct ucounts {104struct ucounts {
99 struct hlist_node node;105 struct hlist_node node;
100 struct user_namespace *ns;106 struct user_namespace *ns;
101 kuid_t uid;107 kuid_t uid;
102 int count;108 atomic_t count;
103 atomic_t ucount[UCOUNT_COUNTS];109 atomic_long_t ucount[UCOUNT_COUNTS];
104};110};
105 111
106extern struct user_namespace init_user_ns;112extern struct user_namespace init_user_ns;
113extern struct ucounts init_ucounts;
107 114
108bool setup_userns_sysctls(struct user_namespace *ns);115bool setup_userns_sysctls(struct user_namespace *ns);
109void retire_userns_sysctls(struct user_namespace *ns);116void retire_userns_sysctls(struct user_namespace *ns);
110struct ucounts *inc_ucount(struct user_namespace *ns, kuid_t uid, enum ucount_type type);117struct ucounts *inc_ucount(struct user_namespace *ns, kuid_t uid, enum ucount_type type);
111void dec_ucount(struct ucounts *ucounts, enum ucount_type type);118void dec_ucount(struct ucounts *ucounts, enum ucount_type type);
119struct ucounts *alloc_ucounts(struct user_namespace *ns, kuid_t uid);
120struct ucounts * __must_check get_ucounts(struct ucounts *ucounts);
121void put_ucounts(struct ucounts *ucounts);
122
123static inline long get_ucounts_value(struct ucounts *ucounts, enum ucount_type type)
124{
125 return atomic_long_read(&ucounts->ucount[type]);
126}
127
128long inc_rlimit_ucounts(struct ucounts *ucounts, enum ucount_type type, long v);
129bool dec_rlimit_ucounts(struct ucounts *ucounts, enum ucount_type type, long v);
130bool is_ucounts_overlimit(struct ucounts *ucounts, enum ucount_type type, unsigned long max);
131
132static 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}
112 137
113#ifdef CONFIG_USER_NS138#ifdef CONFIG_USER_NS
114 139
ipc/mqueue.c+21−19
@@ -144,7 +144,7 @@ struct mqueue_inode_info { · 143 unmodified lines
144 struct pid *notify_owner;144 struct pid *notify_owner;
145 u32 notify_self_exec_id;145 u32 notify_self_exec_id;
146 struct user_namespace *notify_user_ns;146 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 */
148 struct sock *notify_sock;148 struct sock *notify_sock;
149 struct sk_buff *notify_cookie;149 struct sk_buff *notify_cookie;
150 150
@@ -292,7 +292,6 @@ static struct inode *mqueue_get_inode(struct super_block *sb, · 141 unmodified lines
292 struct ipc_namespace *ipc_ns, umode_t mode,292 struct ipc_namespace *ipc_ns, umode_t mode,
293 struct mq_attr *attr)293 struct mq_attr *attr)
294{294{
295 struct user_struct *u = current_user();
296 struct inode *inode;295 struct inode *inode;
297 int ret = -ENOMEM;296 int ret = -ENOMEM;
298 297
@@ -321,7 +320,7 @@ static struct inode *mqueue_get_inode(struct super_block *sb, · 22 unmodified lines
321 info->notify_owner = NULL;320 info->notify_owner = NULL;
322 info->notify_user_ns = NULL;321 info->notify_user_ns = NULL;
323 info->qsize = 0;322 info->qsize = 0;
324 info->user = NULL; /* set when all is ok */323 info->ucounts = NULL; /* set when all is ok */
325 info->msg_tree = RB_ROOT;324 info->msg_tree = RB_ROOT;
326 info->msg_tree_rightmost = NULL;325 info->msg_tree_rightmost = NULL;
327 info->node_cache = NULL;326 info->node_cache = NULL;
@@ -371,19 +370,23 @@ static struct inode *mqueue_get_inode(struct super_block *sb, · 43 unmodified lines
371 if (mq_bytes + mq_treesize < mq_bytes)370 if (mq_bytes + mq_treesize < mq_bytes)
372 goto out_inode;371 goto out_inode;
373 mq_bytes += mq_treesize;372 mq_bytes += mq_treesize;
374 spin_lock(&mq_lock);373 info->ucounts = get_ucounts(current_ucounts());
375 if (u->mq_bytes + mq_bytes < u->mq_bytes ||374 if (info->ucounts) {
376 u->mq_bytes + mq_bytes > rlimit(RLIMIT_MSGQUEUE)) {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 }
377 spin_unlock(&mq_lock);388 spin_unlock(&mq_lock);
378 /* mqueue_evict_inode() releases info->messages */
379 ret = -EMFILE;
380 goto out_inode;
381 }389 }
382 u->mq_bytes += mq_bytes;
383 spin_unlock(&mq_lock);
384
385 /* all is ok */
386 info->user = get_uid(u);
387 } else if (S_ISDIR(mode)) {390 } else if (S_ISDIR(mode)) {
388 inc_nlink(inode);391 inc_nlink(inode);
389 /* Some things misbehave if size == 0 on a directory */392 /* Some things misbehave if size == 0 on a directory */
@@ -497,7 +500,6 @@ static void mqueue_free_inode(struct inode *inode) · 107 unmodified lines
497static void mqueue_evict_inode(struct inode *inode)500static void mqueue_evict_inode(struct inode *inode)
498{501{
499 struct mqueue_inode_info *info;502 struct mqueue_inode_info *info;
500 struct user_struct *user;
501 struct ipc_namespace *ipc_ns;503 struct ipc_namespace *ipc_ns;
502 struct msg_msg *msg, *nmsg;504 struct msg_msg *msg, *nmsg;
503 LIST_HEAD(tmp_msg);505 LIST_HEAD(tmp_msg);
@@ -520,8 +522,7 @@ static void mqueue_evict_inode(struct inode *inode) · 16 unmodified lines
520 free_msg(msg);522 free_msg(msg);
521 }523 }
522 524
523 user = info->user;525 if (info->ucounts) {
524 if (user) {
525 unsigned long mq_bytes, mq_treesize;526 unsigned long mq_bytes, mq_treesize;
526 527
527 /* Total amount of bytes accounted for the mqueue */528 /* Total amount of bytes accounted for the mqueue */
@@ -533,7 +534,7 @@ static void mqueue_evict_inode(struct inode *inode) · 5 unmodified lines
533 info->attr.mq_msgsize);534 info->attr.mq_msgsize);
534 535
535 spin_lock(&mq_lock);536 spin_lock(&mq_lock);
536 user->mq_bytes -= mq_bytes;537 dec_rlimit_ucounts(info->ucounts, UCOUNT_RLIMIT_MSGQUEUE, mq_bytes);
537 /*538 /*
538 * get_ns_from_inode() ensures that the539 * get_ns_from_inode() ensures that the
539 * (ipc_ns = sb->s_fs_info) is either a valid ipc_ns540 * (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
543 if (ipc_ns)544 if (ipc_ns)
544 ipc_ns->mq_queues_count--;545 ipc_ns->mq_queues_count--;
545 spin_unlock(&mq_lock);546 spin_unlock(&mq_lock);
546 free_uid(user);547 put_ucounts(info->ucounts);
548 info->ucounts = NULL;
547 }549 }
548 if (ipc_ns)550 if (ipc_ns)
549 put_ipc_ns(ipc_ns);551 put_ipc_ns(ipc_ns);
ipc/shm.c+13−13
@@ -60,7 +60,7 @@ struct shmid_kernel /* private to the kernel */ · 59 unmodified lines
60 time64_t shm_ctim;60 time64_t shm_ctim;
61 struct pid *shm_cprid;61 struct pid *shm_cprid;
62 struct pid *shm_lprid;62 struct pid *shm_lprid;
63 struct user_struct *mlock_user;63 struct ucounts *mlock_ucounts;
64 64
65 /* The task created the shm object. NULL if the task is dead. */65 /* The task created the shm object. NULL if the task is dead. */
66 struct task_struct *shm_creator;66 struct task_struct *shm_creator;
@@ -286,10 +286,10 @@ static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp) · 219 unmodified lines
286 shm_rmid(ns, shp);286 shm_rmid(ns, shp);
287 shm_unlock(shp);287 shm_unlock(shp);
288 if (!is_file_hugepages(shm_file))288 if (!is_file_hugepages(shm_file))
289 shmem_lock(shm_file, 0, shp->mlock_user);289 shmem_lock(shm_file, 0, shp->mlock_ucounts);
290 else if (shp->mlock_user)290 else if (shp->mlock_ucounts)
291 user_shm_unlock(i_size_read(file_inode(shm_file)),291 user_shm_unlock(i_size_read(file_inode(shm_file)),
292 shp->mlock_user);292 shp->mlock_ucounts);
293 fput(shm_file);293 fput(shm_file);
294 ipc_update_pid(&shp->shm_cprid, NULL);294 ipc_update_pid(&shp->shm_cprid, NULL);
295 ipc_update_pid(&shp->shm_lprid, NULL);295 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
625 625
626 shp->shm_perm.key = key;626 shp->shm_perm.key = key;
627 shp->shm_perm.mode = (shmflg & S_IRWXUGO);627 shp->shm_perm.mode = (shmflg & S_IRWXUGO);
628 shp->mlock_user = NULL;628 shp->mlock_ucounts = NULL;
629 629
630 shp->shm_perm.security = NULL;630 shp->shm_perm.security = NULL;
631 error = security_shm_alloc(&shp->shm_perm);631 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
650 if (shmflg & SHM_NORESERVE)650 if (shmflg & SHM_NORESERVE)
651 acctflag = VM_NORESERVE;651 acctflag = VM_NORESERVE;
652 file = hugetlb_file_setup(name, hugesize, acctflag,652 file = hugetlb_file_setup(name, hugesize, acctflag,
653 &shp->mlock_user, HUGETLB_SHMFS_INODE,653 &shp->mlock_ucounts, HUGETLB_SHMFS_INODE,
654 (shmflg >> SHM_HUGE_SHIFT) & SHM_HUGE_MASK);654 (shmflg >> SHM_HUGE_SHIFT) & SHM_HUGE_MASK);
655 } else {655 } else {
656 /*656 /*
@@ -698,8 +698,8 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) · 41 unmodified lines
698no_id:698no_id:
699 ipc_update_pid(&shp->shm_cprid, NULL);699 ipc_update_pid(&shp->shm_cprid, NULL);
700 ipc_update_pid(&shp->shm_lprid, NULL);700 ipc_update_pid(&shp->shm_lprid, NULL);
701 if (is_file_hugepages(file) && shp->mlock_user)701 if (is_file_hugepages(file) && shp->mlock_ucounts)
702 user_shm_unlock(size, shp->mlock_user);702 user_shm_unlock(size, shp->mlock_ucounts);
703 fput(file);703 fput(file);
704 ipc_rcu_putref(&shp->shm_perm, shm_rcu_free);704 ipc_rcu_putref(&shp->shm_perm, shm_rcu_free);
705 return error;705 return error;
@@ -1105,12 +1105,12 @@ static int shmctl_do_lock(struct ipc_namespace *ns, int shmid, int cmd) · 399 unmodified lines
1105 goto out_unlock0;1105 goto out_unlock0;
1106 1106
1107 if (cmd == SHM_LOCK) {1107 if (cmd == SHM_LOCK) {
1108 struct user_struct *user = current_user();1108 struct ucounts *ucounts = current_ucounts();
1109 1109
1110 err = shmem_lock(shm_file, 1, user);1110 err = shmem_lock(shm_file, 1, ucounts);
1111 if (!err && !(shp->shm_perm.mode & SHM_LOCKED)) {1111 if (!err && !(shp->shm_perm.mode & SHM_LOCKED)) {
1112 shp->shm_perm.mode |= SHM_LOCKED;1112 shp->shm_perm.mode |= SHM_LOCKED;
1113 shp->mlock_user = user;1113 shp->mlock_ucounts = ucounts;
1114 }1114 }
1115 goto out_unlock0;1115 goto out_unlock0;
1116 }1116 }
@@ -1118,9 +1118,9 @@ static int shmctl_do_lock(struct ipc_namespace *ns, int shmid, int cmd) · 1 unmodified line
1118 /* SHM_UNLOCK */1118 /* SHM_UNLOCK */
1119 if (!(shp->shm_perm.mode & SHM_LOCKED))1119 if (!(shp->shm_perm.mode & SHM_LOCKED))
1120 goto out_unlock0;1120 goto out_unlock0;
1121 shmem_lock(shm_file, 0, shp->mlock_user);1121 shmem_lock(shm_file, 0, shp->mlock_ucounts);
1122 shp->shm_perm.mode &= ~SHM_LOCKED;1122 shp->shm_perm.mode &= ~SHM_LOCKED;
1123 shp->mlock_user = NULL;1123 shp->mlock_ucounts = NULL;
1124 get_file(shm_file);1124 get_file(shm_file);
1125 ipc_unlock_object(&shp->shm_perm);1125 ipc_unlock_object(&shp->shm_perm);
1126 rcu_read_unlock();1126 rcu_read_unlock();
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
mm/memfd.c+2−2
@@ -297,9 +297,9 @@ SYSCALL_DEFINE2(memfd_create, · 296 unmodified lines
297 }297 }
298 298
299 if (flags & MFD_HUGETLB) {299 if (flags & MFD_HUGETLB) {
300 struct user_struct *user = NULL;300 struct ucounts *ucounts = NULL;
301 301
302 file = hugetlb_file_setup(name, 0, VM_NORESERVE, &user,302 file = hugetlb_file_setup(name, 0, VM_NORESERVE, &ucounts,
303 HUGETLB_ANONHUGE_INODE,303 HUGETLB_ANONHUGE_INODE,
304 (flags >> MFD_HUGE_SHIFT) &304 (flags >> MFD_HUGE_SHIFT) &
305 MFD_HUGE_MASK);305 MFD_HUGE_MASK);
mm/mlock.c+14−8
@@ -817,9 +817,10 @@ SYSCALL_DEFINE0(munlockall) · 816 unmodified lines
817 */817 */
818static DEFINE_SPINLOCK(shmlock_user_lock);818static DEFINE_SPINLOCK(shmlock_user_lock);
819 819
820int user_shm_lock(size_t size, struct user_struct *user)820int user_shm_lock(size_t size, struct ucounts *ucounts)
821{821{
822 unsigned long lock_limit, locked;822 unsigned long lock_limit, locked;
823 long memlock;
823 int allowed = 0;824 int allowed = 0;
824 825
825 locked = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;826 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
828 allowed = 1;829 allowed = 1;
829 lock_limit >>= PAGE_SHIFT;830 lock_limit >>= PAGE_SHIFT;
830 spin_lock(&shmlock_user_lock);831 spin_lock(&shmlock_user_lock);
831 if (!allowed &&832 memlock = inc_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_MEMLOCK, locked);
832 locked + user->locked_shm > lock_limit && !capable(CAP_IPC_LOCK))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);
833 goto out;840 goto out;
834 get_uid(user);841 }
835 user->locked_shm += locked;
836 allowed = 1;842 allowed = 1;
837out:843out:
838 spin_unlock(&shmlock_user_lock);844 spin_unlock(&shmlock_user_lock);
839 return allowed;845 return allowed;
840}846}
841 847
842void user_shm_unlock(size_t size, struct user_struct *user)848void user_shm_unlock(size_t size, struct ucounts *ucounts)
843{849{
844 spin_lock(&shmlock_user_lock);850 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);
846 spin_unlock(&shmlock_user_lock);852 spin_unlock(&shmlock_user_lock);
847 free_uid(user);853 put_ucounts(ucounts);
848}854}
mm/mmap.c+2−2
@@ -1611,7 +1611,7 @@ unsigned long ksys_mmap_pgoff(unsigned long addr, unsigned long len, · 1610 unmodified lines
1611 goto out_fput;1611 goto out_fput;
1612 }1612 }
1613 } else if (flags & MAP_HUGETLB) {1613 } else if (flags & MAP_HUGETLB) {
1614 struct user_struct *user = NULL;1614 struct ucounts *ucounts = NULL;
1615 struct hstate *hs;1615 struct hstate *hs;
1616 1616
1617 hs = hstate_sizelog((flags >> MAP_HUGE_SHIFT) & MAP_HUGE_MASK);1617 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
1627 */1627 */
1628 file = hugetlb_file_setup(HUGETLB_ANON_FILE, len,1628 file = hugetlb_file_setup(HUGETLB_ANON_FILE, len,
1629 VM_NORESERVE,1629 VM_NORESERVE,
1630 &user, HUGETLB_ANONHUGE_INODE,1630 &ucounts, HUGETLB_ANONHUGE_INODE,
1631 (flags >> MAP_HUGE_SHIFT) & MAP_HUGE_MASK);1631 (flags >> MAP_HUGE_SHIFT) & MAP_HUGE_MASK);
1632 if (IS_ERR(file))1632 if (IS_ERR(file))
1633 return PTR_ERR(file);1633 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
2227}2227}
2228#endif2228#endif
2229 2229
2230int shmem_lock(struct file *file, int lock, struct user_struct *user)2230int shmem_lock(struct file *file, int lock, struct ucounts *ucounts)
2231{2231{
2232 struct inode *inode = file_inode(file);2232 struct inode *inode = file_inode(file);
2233 struct shmem_inode_info *info = SHMEM_I(inode);2233 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
2239 * no serialization needed when called from shm_destroy().2239 * no serialization needed when called from shm_destroy().
2240 */2240 */
2241 if (lock && !(info->flags & VM_LOCKED)) {2241 if (lock && !(info->flags & VM_LOCKED)) {
2242 if (!user_shm_lock(inode->i_size, user))2242 if (!user_shm_lock(inode->i_size, ucounts))
2243 goto out_nomem;2243 goto out_nomem;
2244 info->flags |= VM_LOCKED;2244 info->flags |= VM_LOCKED;
2245 mapping_set_unevictable(file->f_mapping);2245 mapping_set_unevictable(file->f_mapping);
2246 }2246 }
2247 if (!lock && (info->flags & VM_LOCKED) && user) {2247 if (!lock && (info->flags & VM_LOCKED) && ucounts) {
2248 user_shm_unlock(inode->i_size, user);2248 user_shm_unlock(inode->i_size, ucounts);
2249 info->flags &= ~VM_LOCKED;2249 info->flags &= ~VM_LOCKED;
2250 mapping_clear_unevictable(file->f_mapping);2250 mapping_clear_unevictable(file->f_mapping);
2251 }2251 }
@@ -4092,7 +4092,7 @@ int shmem_unuse(unsigned int type, bool frontswap, · 1840 unmodified lines
4092 return 0;4092 return 0;
4093}4093}
4094 4094
4095int shmem_lock(struct file *file, int lock, struct user_struct *user)4095int shmem_lock(struct file *file, int lock, struct ucounts *ucounts)
4096{4096{
4097 return 0;4097 return 0;
4098}4098}
tools/testing/selftests/Makefile+1−0
@@ -49,6 +49,7 @@ TARGETS += proc · 48 unmodified lines
49TARGETS += pstore49TARGETS += pstore
50TARGETS += ptrace50TARGETS += ptrace
51TARGETS += openat251TARGETS += openat2
52TARGETS += rlimits
52TARGETS += rseq53TARGETS += rseq
53TARGETS += rtc54TARGETS += rtc
54TARGETS += seccomp55TARGETS += seccomp
tools/testing/selftests/rlimits/.gitignore+2−0
@@ -0,0 +1,2 @@
1# SPDX-License-Identifier: GPL-2.0-only
2rlimits-per-userns
tools/testing/selftests/rlimits/Makefile+6−0
@@ -0,0 +1,6 @@
1# SPDX-License-Identifier: GPL-2.0-or-later
2
3CFLAGS += -Wall -O2 -g
4TEST_GEN_PROGS := rlimits-per-userns
5
6include ../lib.mk
tools/testing/selftests/rlimits/config+1−0
@@ -0,0 +1 @@
1CONFIG_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
26static char *service_prog;
27static uid_t user = 60000;
28static uid_t group = 60000;
29
30static 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
44static 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
85int 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