Received: by 2002:a05:6a10:a841:0:0:0:0 with SMTP id d1csp426309pxy; Thu, 22 Apr 2021 05:29:24 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxYOc+RlSBPcQoGxguuAlhXixv/2He0Tp/wBTys0tbbi+FrwM5WPqE0oDVj8MDkNwaw6Puh X-Received: by 2002:a63:5d18:: with SMTP id r24mr3464583pgb.94.1619094564518; Thu, 22 Apr 2021 05:29:24 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1619094564; cv=none; d=google.com; s=arc-20160816; b=npWlNDg4/+0IbXH2wuIhAWOlF3s0C3+19SWCv21inzhu9by2RD13ZOWy+VGpcXDBg0 uLT0gpPdbCGjS4x7IEf03cGP/QrIOB2SkfJyKZHXSg925fcgUS3lERCzuMuvj4/gJEfg QrGd5D3eVbF1B2WXqlMQ/StGtOlaioPvmm880yo4iC6zINGuVEfdhMeKvxMvqdJlVJVj SraVjPYnRf2rjncM8vMV/RqOlfx9u9IjZ3BSxODpCtMP2uBk4EUGYKi2WmES9nCgOUDa 3RCTmauTGqloKc+/BzQ14U7IsuKMSkFg1tr85Wxa/9MdjcaU+Uo7dcGZmlEVhvK4Wo6m GbhA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=IjTBgONiRDAOSyDH589ME2pTISyv3yabm0iWasWY3Qw=; b=RN2aMQOtUBbMrvvzwBGMxduuwT7rPDTR7RdO62xb5XIWbBXgLeBcDCsGd+uXlBUKlB ioGqBlWpLYfteWzAtraz0sD06482coEWRpS4rWKZSWgdDxEQAAi69Lg2IQYQ896Hnu7P Z0aRBO6BgvMta7ab+fV/19av634D/jrpnIbkwvsXdYezQxvQWTjJBt+6buCkXzHBfr3M bN2YNPaj66SKpGUMCXGwcZ9h1S1w0w/2OkzvbT6LiczGxXlsqDKCRKYsC0sYWeBZEABE sXHiH/19yfEr1oEaQ7cHDREZ0aOybEa7ZjY+rmSTes3RrF6JaCmSFmp8aMOkhVx87sRQ 2kKQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=hb2FrSFb; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id h19si6151216pjq.75.2021.04.22.05.29.12; Thu, 22 Apr 2021 05:29:24 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=hb2FrSFb; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236338AbhDVM2c (ORCPT + 99 others); Thu, 22 Apr 2021 08:28:32 -0400 Received: from mail.kernel.org ([198.145.29.99]:36664 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236351AbhDVM2Z (ORCPT ); Thu, 22 Apr 2021 08:28:25 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 1106761466; Thu, 22 Apr 2021 12:27:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1619094470; bh=wGjk7sHNDH4H8Q8/yo1q/j8Yxn9l6/bqhk94/LFC13A=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=hb2FrSFbJ3Imx+TzBbkBU2/s1t5J1SGKH7EjMYNJzqSzGWa4TSt1vpeIWMboR49mr CvfUqrUFF4gggg/5sKHZ8KELNaJfxoX1Y/ZJUQtFIYekqStct5z8wKkp0KneW3wcOC tBRd17veoz3PvQC2O8Uvd9/XzIQxtOTUJcRMyeo48Cv9/BsnSG1I+pbGcQtZz5yjQi 7LFv5iGWti5FkzZTYUlxZvcK9NQ/LB56OQ4WxHl4shJKliKKI0pPUls6i/hofLYTMf IC7oIYERcCgrEq/9aFcMvYDySY6mLEtj+kG2Q5IjdavDsIZeTc4TQWqiWts6T+z7nj Jzi/d4b6C5UDA== From: legion@kernel.org To: LKML , 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 v11 6/9] Reimplement RLIMIT_SIGPENDING on top of ucounts Date: Thu, 22 Apr 2021 14:27:13 +0200 Message-Id: X-Mailer: git-send-email 2.29.3 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Alexey Gladkov 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. Changelog v11: * Revert most of changes to fix performance issues. v10: * Fix memory leak on get_ucounts failure. 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 | 25 +++++++++++++------------ kernel/ucount.c | 1 + kernel/user.c | 1 - kernel/user_namespace.c | 1 + 9 files changed, 21 insertions(+), 16 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, struct task_struct *p) collect_sigign_sigcatch(p, &ignored, &caught); num_threads = get_nr_threads(p); rcu_read_lock(); /* FIXME: is this correct? */ - qsize = atomic_read(&__task_cred(p)->user->sigpending); + qsize = get_ucounts_value(task_ucounts(p), UCOUNT_RLIMIT_SIGPENDING); rcu_read_unlock(); qlim = 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; +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; }; /* flags values. */ diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index 21ad1ad1b990..0e961bd8a090 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, }; diff --git a/kernel/fork.c b/kernel/fork.c index 85c6094f5a48..741f896c156e 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -824,6 +824,7 @@ void __init fork_init(void) init_user_ns.ucount_max[UCOUNT_RLIMIT_NPROC] = task_rlimit(&init_task, RLIMIT_NPROC); init_user_ns.ucount_max[UCOUNT_RLIMIT_MSGQUEUE] = task_rlimit(&init_task, RLIMIT_MSGQUEUE); + init_user_ns.ucount_max[UCOUNT_RLIMIT_SIGPENDING] = task_rlimit(&init_task, RLIMIT_SIGPENDING); #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 f2a1b898da29..92383b890b35 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -414,8 +414,8 @@ static struct sigqueue * __sigqueue_alloc(int sig, struct task_struct *t, gfp_t flags, int override_rlimit) { struct sigqueue *q = NULL; - struct user_struct *user; - int sigpending; + struct ucounts *ucounts = NULL; + long sigpending; /* * Protect access to @t credentials. This can go away when all @@ -426,27 +426,26 @@ __sigqueue_alloc(int sig, struct task_struct *t, gfp_t flags, int override_rlimi * changes from/to zero. */ rcu_read_lock(); - user = __task_cred(t)->user; - sigpending = atomic_inc_return(&user->sigpending); + ucounts = task_ucounts(t); + sigpending = inc_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_SIGPENDING, 1); if (sigpending == 1) - get_uid(user); + ucounts = get_ucounts(ucounts); rcu_read_unlock(); - if (override_rlimit || likely(sigpending <= task_rlimit(t, RLIMIT_SIGPENDING))) { + if (override_rlimit || (sigpending < LONG_MAX && sigpending <= task_rlimit(t, RLIMIT_SIGPENDING))) { q = kmem_cache_alloc(sigqueue_cachep, flags); } else { print_dropped_signal(sig); } if (unlikely(q == NULL)) { - if (atomic_dec_and_test(&user->sigpending)) - free_uid(user); + if (ucounts && dec_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_SIGPENDING, 1)) + put_ucounts(ucounts); } else { INIT_LIST_HEAD(&q->list); q->flags = 0; - q->user = user; + q->ucounts = ucounts; } - return q; } @@ -454,8 +453,10 @@ 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); + q->ucounts = NULL; + } kmem_cache_free(sigqueue_cachep, q); } diff --git a/kernel/ucount.c b/kernel/ucount.c index 6e6f936a5963..8ce62da6a62c 100644 --- a/kernel/ucount.c +++ b/kernel/ucount.c @@ -80,6 +80,7 @@ static struct ctl_table user_table[] = { 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 = { .__count = REFCOUNT_INIT(1), - .sigpending = ATOMIC_INIT(0), .locked_shm = 0, .uid = GLOBAL_ROOT_UID, .ratelimit = 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] = rlimit(RLIMIT_NPROC); ns->ucount_max[UCOUNT_RLIMIT_MSGQUEUE] = rlimit(RLIMIT_MSGQUEUE); + ns->ucount_max[UCOUNT_RLIMIT_SIGPENDING] = rlimit(RLIMIT_SIGPENDING); ns->ucounts = ucounts; /* Inherit USERNS_SETGROUPS_ALLOWED from our parent */ -- 2.29.3