From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.7 required=3.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0A6D5C433E0 for ; Mon, 22 Feb 2021 09:57:26 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id 86AB564E5F for ; Mon, 22 Feb 2021 09:57:25 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 86AB564E5F Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id 5674F8D0002; Mon, 22 Feb 2021 04:57:16 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 4A0D58D0001; Mon, 22 Feb 2021 04:57:16 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 345138D0002; Mon, 22 Feb 2021 04:57:16 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0006.hostedemail.com [216.40.44.6]) by kanga.kvack.org (Postfix) with ESMTP id 0ABC48D0001 for ; Mon, 22 Feb 2021 04:57:16 -0500 (EST) Received: from smtpin21.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay01.hostedemail.com (Postfix) with ESMTP id CEAE4180ACEE4 for ; Mon, 22 Feb 2021 09:57:15 +0000 (UTC) X-FDA: 77845450830.21.F980A7C Received: from raptor.unsafe.ru (raptor.unsafe.ru [5.9.43.93]) by imf21.hostedemail.com (Postfix) with ESMTP id 6BC10E0001B4 for ; Mon, 22 Feb 2021 09:57:12 +0000 (UTC) Received: from comp-core-i7-2640m-0182e6.redhat.com (ip-94-113-225-162.net.upcbroadband.cz [94.113.225.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by raptor.unsafe.ru (Postfix) with ESMTPSA id 6FD8920A19; Mon, 22 Feb 2021 09:57:14 +0000 (UTC) From: Alexey Gladkov To: LKML , io-uring@vger.kernel.org, Kernel Hardening , Linux Containers , linux-mm@kvack.org Cc: Alexey Gladkov , Andrew Morton , Christian Brauner , "Eric W . Biederman" , Jann Horn , Jens Axboe , Kees Cook , Linus Torvalds , Oleg Nesterov Subject: [PATCH v7 5/7] Reimplement RLIMIT_SIGPENDING on top of ucounts Date: Mon, 22 Feb 2021 10:56:30 +0100 Message-Id: <2d4a2e2be7db42c95acb98abfc2a9b370ddd0604.1613987704.git.gladkov.alexey@gmail.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: References: MIME-Version: 1.0 X-Greylist: Sender succeeded SMTP AUTH, not delayed by milter-greylist-4.6.1 (raptor.unsafe.ru [5.9.43.93]); Mon, 22 Feb 2021 09:57:14 +0000 (UTC) X-Stat-Signature: qg47r3ryrn43byosi4mb7weijhawpt9u X-Rspamd-Server: rspam05 X-Rspamd-Queue-Id: 6BC10E0001B4 Received-SPF: none (gmail.com>: No applicable sender policy available) receiver=imf21; identity=mailfrom; envelope-from=""; helo=raptor.unsafe.ru; client-ip=5.9.43.93 X-HE-DKIM-Result: none/none X-HE-Tag: 1613987832-875381 Content-Transfer-Encoding: quoted-printable X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: The rlimit counter is tied to uid in the user_namespace. This allows rlimit values to be specified in userns even if they are already globally exceeded by the user. However, the value of the previous user_namespaces cannot be exceeded. Signed-off-by: Alexey Gladkov --- fs/proc/array.c | 2 +- include/linux/sched/user.h | 1 - include/linux/signal_types.h | 4 ++- include/linux/user_namespace.h | 1 + kernel/fork.c | 1 + kernel/signal.c | 57 ++++++++++++++++------------------ kernel/ucount.c | 1 + kernel/user.c | 1 - kernel/user_namespace.c | 1 + 9 files changed, 34 insertions(+), 35 deletions(-) diff --git a/fs/proc/array.c b/fs/proc/array.c index bb87e4d89cd8..74b0ea4b7e38 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -284,7 +284,7 @@ static inline void task_sig(struct seq_file *m, struc= t task_struct *p) collect_sigign_sigcatch(p, &ignored, &caught); num_threads =3D get_nr_threads(p); rcu_read_lock(); /* FIXME: is this correct? */ - qsize =3D atomic_read(&__task_cred(p)->user->sigpending); + qsize =3D get_ucounts_value(task_ucounts(p), UCOUNT_RLIMIT_SIGPENDING)= ; rcu_read_unlock(); qlim =3D task_rlimit(p, RLIMIT_SIGPENDING); unlock_task_sighand(p, &flags); diff --git a/include/linux/sched/user.h b/include/linux/sched/user.h index 8a34446681aa..8ba9cec4fb99 100644 --- a/include/linux/sched/user.h +++ b/include/linux/sched/user.h @@ -12,7 +12,6 @@ */ struct user_struct { refcount_t __count; /* reference count */ - atomic_t sigpending; /* How many pending signals does this user have? *= / #ifdef CONFIG_FANOTIFY atomic_t fanotify_listeners; #endif diff --git a/include/linux/signal_types.h b/include/linux/signal_types.h index 68e06c75c5b2..34cb28b8f16c 100644 --- a/include/linux/signal_types.h +++ b/include/linux/signal_types.h @@ -13,6 +13,8 @@ typedef struct kernel_siginfo { __SIGINFO; } kernel_siginfo_t; =20 +struct ucounts; + /* * Real Time signals may be queued. */ @@ -21,7 +23,7 @@ struct sigqueue { struct list_head list; int flags; kernel_siginfo_t info; - struct user_struct *user; + struct ucounts *ucounts; }; =20 /* flags values. */ diff --git a/include/linux/user_namespace.h b/include/linux/user_namespac= e.h index 52453143fe23..f84b68832c56 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h @@ -52,6 +52,7 @@ enum ucount_type { #endif UCOUNT_RLIMIT_NPROC, UCOUNT_RLIMIT_MSGQUEUE, + UCOUNT_RLIMIT_SIGPENDING, UCOUNT_COUNTS, }; =20 diff --git a/kernel/fork.c b/kernel/fork.c index 0a939332efcc..99b10b9fe4b6 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -824,6 +824,7 @@ void __init fork_init(void) =20 init_user_ns.ucount_max[UCOUNT_RLIMIT_NPROC] =3D task_rlimit(&init_task= , RLIMIT_NPROC); init_user_ns.ucount_max[UCOUNT_RLIMIT_MSGQUEUE] =3D task_rlimit(&init_t= ask, RLIMIT_MSGQUEUE); + init_user_ns.ucount_max[UCOUNT_RLIMIT_SIGPENDING] =3D task_rlimit(&init= _task, RLIMIT_SIGPENDING); =20 #ifdef CONFIG_VMAP_STACK cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "fork:vm_stack_cache", diff --git a/kernel/signal.c b/kernel/signal.c index 5ad8566534e7..a515e36a8a11 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -412,49 +412,44 @@ void task_join_group_stop(struct task_struct *task) static struct sigqueue * __sigqueue_alloc(int sig, struct task_struct *t, gfp_t flags, int overri= de_rlimit) { - struct sigqueue *q =3D NULL; - struct user_struct *user; - int sigpending; + struct sigqueue *q =3D kmem_cache_alloc(sigqueue_cachep, flags); =20 - /* - * Protect access to @t credentials. This can go away when all - * callers hold rcu read lock. - * - * NOTE! A pending signal will hold on to the user refcount, - * and we get/put the refcount only when the sigpending count - * changes from/to zero. - */ - rcu_read_lock(); - user =3D __task_cred(t)->user; - sigpending =3D atomic_inc_return(&user->sigpending); - if (sigpending =3D=3D 1) - get_uid(user); - rcu_read_unlock(); + if (likely(q !=3D NULL)) { + bool overlimit; =20 - if (override_rlimit || likely(sigpending <=3D task_rlimit(t, RLIMIT_SIG= PENDING))) { - q =3D kmem_cache_alloc(sigqueue_cachep, flags); - } else { - print_dropped_signal(sig); - } - - if (unlikely(q =3D=3D NULL)) { - if (atomic_dec_and_test(&user->sigpending)) - free_uid(user); - } else { INIT_LIST_HEAD(&q->list); q->flags =3D 0; - q->user =3D user; + + /* + * Protect access to @t credentials. This can go away when all + * callers hold rcu read lock. + */ + rcu_read_lock(); + q->ucounts =3D get_ucounts(task_ucounts(t)); + if (q->ucounts) { + overlimit =3D inc_rlimit_ucounts_and_test(q->ucounts, UCOUNT_RLIMIT_S= IGPENDING, + 1, task_rlimit(t, RLIMIT_SIGPENDING)); + + if (override_rlimit || likely(!overlimit)) { + rcu_read_unlock(); + return q; + } + } + rcu_read_unlock(); } =20 - return q; + print_dropped_signal(sig); + return NULL; } =20 static void __sigqueue_free(struct sigqueue *q) { if (q->flags & SIGQUEUE_PREALLOC) return; - if (atomic_dec_and_test(&q->user->sigpending)) - free_uid(q->user); + if (q->ucounts) { + dec_rlimit_ucounts(q->ucounts, UCOUNT_RLIMIT_SIGPENDING, 1); + put_ucounts(q->ucounts); + } kmem_cache_free(sigqueue_cachep, q); } =20 diff --git a/kernel/ucount.c b/kernel/ucount.c index 6fb2ebdef0bc..2ac969fba668 100644 --- a/kernel/ucount.c +++ b/kernel/ucount.c @@ -81,6 +81,7 @@ static struct ctl_table user_table[] =3D { UCOUNT_ENTRY("max_inotify_instances"), UCOUNT_ENTRY("max_inotify_watches"), #endif + { }, { }, { }, { } diff --git a/kernel/user.c b/kernel/user.c index 7f5ff498207a..6737327f83be 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -98,7 +98,6 @@ static DEFINE_SPINLOCK(uidhash_lock); /* root_user.__count is 1, for init task cred */ struct user_struct root_user =3D { .__count =3D REFCOUNT_INIT(1), - .sigpending =3D ATOMIC_INIT(0), .locked_shm =3D 0, .uid =3D GLOBAL_ROOT_UID, .ratelimit =3D RATELIMIT_STATE_INIT(root_user.ratelimit, 0, 0), diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index cc90d5203acf..df1bed32dd48 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -123,6 +123,7 @@ int create_user_ns(struct cred *new) } ns->ucount_max[UCOUNT_RLIMIT_NPROC] =3D rlimit(RLIMIT_NPROC); ns->ucount_max[UCOUNT_RLIMIT_MSGQUEUE] =3D rlimit(RLIMIT_MSGQUEUE); + ns->ucount_max[UCOUNT_RLIMIT_SIGPENDING] =3D rlimit(RLIMIT_SIGPENDING); ns->ucounts =3D ucounts; =20 /* Inherit USERNS_SETGROUPS_ALLOWED from our parent */ --=20 2.29.2