]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.15-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 21 Feb 2022 07:04:15 +0000 (08:04 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 21 Feb 2022 07:04:15 +0000 (08:04 +0100)
added patches:
edac-fix-calculation-of-returned-address-and-next-offset-in-edac_align_ptr.patch
rlimit-fix-rlimit_nproc-enforcement-failure-caused-by-capability-calls-in-set_user.patch
scsi-lpfc-fix-pt2pt-nvme-prli-reject-logo-loop.patch
ucounts-base-set_cred_ucounts-changes-on-the-real-user.patch
ucounts-enforce-rlimit_nproc-not-rlimit_nproc-1.patch
ucounts-handle-wrapping-in-is_ucounts_overlimit.patch
ucounts-in-set_cred_ucounts-assume-new-ucounts-is-non-null.patch
ucounts-move-rlimit_nproc-handling-after-set_user.patch

queue-5.15/edac-fix-calculation-of-returned-address-and-next-offset-in-edac_align_ptr.patch [new file with mode: 0644]
queue-5.15/rlimit-fix-rlimit_nproc-enforcement-failure-caused-by-capability-calls-in-set_user.patch [new file with mode: 0644]
queue-5.15/scsi-lpfc-fix-pt2pt-nvme-prli-reject-logo-loop.patch [new file with mode: 0644]
queue-5.15/series
queue-5.15/ucounts-base-set_cred_ucounts-changes-on-the-real-user.patch [new file with mode: 0644]
queue-5.15/ucounts-enforce-rlimit_nproc-not-rlimit_nproc-1.patch [new file with mode: 0644]
queue-5.15/ucounts-handle-wrapping-in-is_ucounts_overlimit.patch [new file with mode: 0644]
queue-5.15/ucounts-in-set_cred_ucounts-assume-new-ucounts-is-non-null.patch [new file with mode: 0644]
queue-5.15/ucounts-move-rlimit_nproc-handling-after-set_user.patch [new file with mode: 0644]

diff --git a/queue-5.15/edac-fix-calculation-of-returned-address-and-next-offset-in-edac_align_ptr.patch b/queue-5.15/edac-fix-calculation-of-returned-address-and-next-offset-in-edac_align_ptr.patch
new file mode 100644 (file)
index 0000000..85ee5d4
--- /dev/null
@@ -0,0 +1,45 @@
+From f8efca92ae509c25e0a4bd5d0a86decea4f0c41e Mon Sep 17 00:00:00 2001
+From: Eliav Farber <farbere@amazon.com>
+Date: Thu, 13 Jan 2022 10:06:19 +0000
+Subject: EDAC: Fix calculation of returned address and next offset in edac_align_ptr()
+
+From: Eliav Farber <farbere@amazon.com>
+
+commit f8efca92ae509c25e0a4bd5d0a86decea4f0c41e upstream.
+
+Do alignment logic properly and use the "ptr" local variable for
+calculating the remainder of the alignment.
+
+This became an issue because struct edac_mc_layer has a size that is not
+zero modulo eight, and the next offset that was prepared for the private
+data was unaligned, causing an alignment exception.
+
+The patch in Fixes: which broke this actually wanted to "what we
+actually care about is the alignment of the actual pointer that's about
+to be returned." But it didn't check that alignment.
+
+Use the correct variable "ptr" for that.
+
+  [ bp: Massage commit message. ]
+
+Fixes: 8447c4d15e35 ("edac: Do alignment logic properly in edac_align_ptr()")
+Signed-off-by: Eliav Farber <farbere@amazon.com>
+Signed-off-by: Borislav Petkov <bp@suse.de>
+Cc: <stable@vger.kernel.org>
+Link: https://lore.kernel.org/r/20220113100622.12783-2-farbere@amazon.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/edac/edac_mc.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/edac/edac_mc.c
++++ b/drivers/edac/edac_mc.c
+@@ -215,7 +215,7 @@ void *edac_align_ptr(void **p, unsigned
+       else
+               return (char *)ptr;
+-      r = (unsigned long)p % align;
++      r = (unsigned long)ptr % align;
+       if (r == 0)
+               return (char *)ptr;
diff --git a/queue-5.15/rlimit-fix-rlimit_nproc-enforcement-failure-caused-by-capability-calls-in-set_user.patch b/queue-5.15/rlimit-fix-rlimit_nproc-enforcement-failure-caused-by-capability-calls-in-set_user.patch
new file mode 100644 (file)
index 0000000..b2cf0c3
--- /dev/null
@@ -0,0 +1,103 @@
+From c16bdeb5a39ffa3f32b32f812831a2092d2a3061 Mon Sep 17 00:00:00 2001
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Fri, 11 Feb 2022 13:57:44 -0600
+Subject: rlimit: Fix RLIMIT_NPROC enforcement failure caused by capability calls in set_user
+
+From: Eric W. Biederman <ebiederm@xmission.com>
+
+commit c16bdeb5a39ffa3f32b32f812831a2092d2a3061 upstream.
+
+Solar Designer <solar@openwall.com> wrote:
+> I'm not aware of anyone actually running into this issue and reporting
+> it.  The systems that I personally know use suexec along with rlimits
+> still run older/distro kernels, so would not yet be affected.
+>
+> So my mention was based on my understanding of how suexec works, and
+> code review.  Specifically, Apache httpd has the setting RLimitNPROC,
+> which makes it set RLIMIT_NPROC:
+>
+> https://httpd.apache.org/docs/2.4/mod/core.html#rlimitnproc
+>
+> The above documentation for it includes:
+>
+> "This applies to processes forked from Apache httpd children servicing
+> requests, not the Apache httpd children themselves. This includes CGI
+> scripts and SSI exec commands, but not any processes forked from the
+> Apache httpd parent, such as piped logs."
+>
+> In code, there are:
+>
+> ./modules/generators/mod_cgid.c:        ( (cgid_req.limits.limit_nproc_set) && ((rc = apr_procattr_limit_set(procattr, APR_LIMIT_NPROC,
+> ./modules/generators/mod_cgi.c:        ((rc = apr_procattr_limit_set(procattr, APR_LIMIT_NPROC,
+> ./modules/filters/mod_ext_filter.c:    rv = apr_procattr_limit_set(procattr, APR_LIMIT_NPROC, conf->limit_nproc);
+>
+> For example, in mod_cgi.c this is in run_cgi_child().
+>
+> I think this means an httpd child sets RLIMIT_NPROC shortly before it
+> execs suexec, which is a SUID root program.  suexec then switches to the
+> target user and execs the CGI script.
+>
+> Before 2863643fb8b9, the setuid() in suexec would set the flag, and the
+> target user's process count would be checked against RLIMIT_NPROC on
+> execve().  After 2863643fb8b9, the setuid() in suexec wouldn't set the
+> flag because setuid() is (naturally) called when the process is still
+> running as root (thus, has those limits bypass capabilities), and
+> accordingly execve() would not check the target user's process count
+> against RLIMIT_NPROC.
+
+In commit 2863643fb8b9 ("set_user: add capability check when
+rlimit(RLIMIT_NPROC) exceeds") capable calls were added to set_user to
+make it more consistent with fork.  Unfortunately because of call site
+differences those capable calls were checking the credentials of the
+user before set*id() instead of after set*id().
+
+This breaks enforcement of RLIMIT_NPROC for applications that set the
+rlimit and then call set*id() while holding a full set of
+capabilities.  The capabilities are only changed in the new credential
+in security_task_fix_setuid().
+
+The code in apache suexec appears to follow this pattern.
+
+Commit 909cc4ae86f3 ("[PATCH] Fix two bugs with process limits
+(RLIMIT_NPROC)") where this check was added describes the targes of this
+capability check as:
+
+  2/ When a root-owned process (e.g. cgiwrap) sets up process limits and then
+      calls setuid, the setuid should fail if the user would then be running
+      more than rlim_cur[RLIMIT_NPROC] processes, but it doesn't.  This patch
+      adds an appropriate test.  With this patch, and per-user process limit
+      imposed in cgiwrap really works.
+
+So the original use case of this check also appears to match the broken
+pattern.
+
+Restore the enforcement of RLIMIT_NPROC by removing the bad capable
+checks added in set_user.  This unfortunately restores the
+inconsistent state the code has been in for the last 11 years, but
+dealing with the inconsistencies looks like a larger problem.
+
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/all/20210907213042.GA22626@openwall.com/
+Link: https://lkml.kernel.org/r/20220212221412.GA29214@openwall.com
+Link: https://lkml.kernel.org/r/20220216155832.680775-1-ebiederm@xmission.com
+Fixes: 2863643fb8b9 ("set_user: add capability check when rlimit(RLIMIT_NPROC) exceeds")
+History-Tree: https://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git
+Reviewed-by: Solar Designer <solar@openwall.com>
+Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/sys.c |    3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/kernel/sys.c
++++ b/kernel/sys.c
+@@ -480,8 +480,7 @@ static int set_user(struct cred *new)
+        * failure to the execve() stage.
+        */
+       if (is_ucounts_overlimit(new->ucounts, UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC)) &&
+-                      new_user != INIT_USER &&
+-                      !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN))
++                      new_user != INIT_USER)
+               current->flags |= PF_NPROC_EXCEEDED;
+       else
+               current->flags &= ~PF_NPROC_EXCEEDED;
diff --git a/queue-5.15/scsi-lpfc-fix-pt2pt-nvme-prli-reject-logo-loop.patch b/queue-5.15/scsi-lpfc-fix-pt2pt-nvme-prli-reject-logo-loop.patch
new file mode 100644 (file)
index 0000000..6c3f04c
--- /dev/null
@@ -0,0 +1,111 @@
+From 7f4c5a26f735dea4bbc0eb8eb9da99cda95a8563 Mon Sep 17 00:00:00 2001
+From: James Smart <jsmart2021@gmail.com>
+Date: Sat, 12 Feb 2022 08:31:20 -0800
+Subject: scsi: lpfc: Fix pt2pt NVMe PRLI reject LOGO loop
+
+From: James Smart <jsmart2021@gmail.com>
+
+commit 7f4c5a26f735dea4bbc0eb8eb9da99cda95a8563 upstream.
+
+When connected point to point, the driver does not know the FC4's supported
+by the other end. In Fabrics, it can query the nameserver.  Thus the driver
+must send PRLIs for the FC4s it supports and enable support based on the
+acc(ept) or rej(ect) of the respective FC4 PRLI.  Currently the driver
+supports SCSI and NVMe PRLIs.
+
+Unfortunately, although the behavior is per standard, many devices have
+come to expect only SCSI PRLIs. In this particular example, the NVMe PRLI
+is properly RJT'd but the target decided that it must LOGO after seeing the
+unexpected NVMe PRLI. The LOGO causes the sequence to restart and login is
+now in an infinite failure loop.
+
+Fix the problem by having the driver, on a pt2pt link, remember NVMe PRLI
+accept or reject status across logout as long as the link stays "up".  When
+retrying login, if the prior NVMe PRLI was rejected, it will not be sent on
+the next login.
+
+Link: https://lore.kernel.org/r/20220212163120.15385-1-jsmart2021@gmail.com
+Cc: <stable@vger.kernel.org> # v5.4+
+Reviewed-by: Ewan D. Milne <emilne@redhat.com>
+Signed-off-by: James Smart <jsmart2021@gmail.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/scsi/lpfc/lpfc.h           |    1 +
+ drivers/scsi/lpfc/lpfc_attr.c      |    3 +++
+ drivers/scsi/lpfc/lpfc_els.c       |   20 +++++++++++++++++++-
+ drivers/scsi/lpfc/lpfc_nportdisc.c |    5 +++--
+ 4 files changed, 26 insertions(+), 3 deletions(-)
+
+--- a/drivers/scsi/lpfc/lpfc.h
++++ b/drivers/scsi/lpfc/lpfc.h
+@@ -593,6 +593,7 @@ struct lpfc_vport {
+ #define FC_VPORT_LOGO_RCVD      0x200    /* LOGO received on vport */
+ #define FC_RSCN_DISCOVERY       0x400  /* Auth all devices after RSCN */
+ #define FC_LOGO_RCVD_DID_CHNG   0x800    /* FDISC on phys port detect DID chng*/
++#define FC_PT2PT_NO_NVME        0x1000   /* Don't send NVME PRLI */
+ #define FC_SCSI_SCAN_TMO        0x4000         /* scsi scan timer running */
+ #define FC_ABORT_DISCOVERY      0x8000         /* we want to abort discovery */
+ #define FC_NDISC_ACTIVE         0x10000        /* NPort discovery active */
+--- a/drivers/scsi/lpfc/lpfc_attr.c
++++ b/drivers/scsi/lpfc/lpfc_attr.c
+@@ -1315,6 +1315,9 @@ lpfc_issue_lip(struct Scsi_Host *shost)
+       pmboxq->u.mb.mbxCommand = MBX_DOWN_LINK;
+       pmboxq->u.mb.mbxOwner = OWN_HOST;
++      if ((vport->fc_flag & FC_PT2PT) && (vport->fc_flag & FC_PT2PT_NO_NVME))
++              vport->fc_flag &= ~FC_PT2PT_NO_NVME;
++
+       mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO * 2);
+       if ((mbxstatus == MBX_SUCCESS) &&
+--- a/drivers/scsi/lpfc/lpfc_els.c
++++ b/drivers/scsi/lpfc/lpfc_els.c
+@@ -1072,7 +1072,8 @@ stop_rr_fcf_flogi:
+               /* FLOGI failed, so there is no fabric */
+               spin_lock_irq(shost->host_lock);
+-              vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
++              vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP |
++                                  FC_PT2PT_NO_NVME);
+               spin_unlock_irq(shost->host_lock);
+               /* If private loop, then allow max outstanding els to be
+@@ -4587,6 +4588,23 @@ lpfc_els_retry(struct lpfc_hba *phba, st
+               /* Added for Vendor specifc support
+                * Just keep retrying for these Rsn / Exp codes
+                */
++              if ((vport->fc_flag & FC_PT2PT) &&
++                  cmd == ELS_CMD_NVMEPRLI) {
++                      switch (stat.un.b.lsRjtRsnCode) {
++                      case LSRJT_UNABLE_TPC:
++                      case LSRJT_INVALID_CMD:
++                      case LSRJT_LOGICAL_ERR:
++                      case LSRJT_CMD_UNSUPPORTED:
++                              lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS,
++                                               "0168 NVME PRLI LS_RJT "
++                                               "reason %x port doesn't "
++                                               "support NVME, disabling NVME\n",
++                                               stat.un.b.lsRjtRsnCode);
++                              retry = 0;
++                              vport->fc_flag |= FC_PT2PT_NO_NVME;
++                              goto out_retry;
++                      }
++              }
+               switch (stat.un.b.lsRjtRsnCode) {
+               case LSRJT_UNABLE_TPC:
+                       /* The driver has a VALID PLOGI but the rport has
+--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
++++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
+@@ -1961,8 +1961,9 @@ lpfc_cmpl_reglogin_reglogin_issue(struct
+                        * is configured try it.
+                        */
+                       ndlp->nlp_fc4_type |= NLP_FC4_FCP;
+-                      if ((vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) ||
+-                          (vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME)) {
++                      if ((!(vport->fc_flag & FC_PT2PT_NO_NVME)) &&
++                          (vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH ||
++                          vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME)) {
+                               ndlp->nlp_fc4_type |= NLP_FC4_NVME;
+                               /* We need to update the localport also */
+                               lpfc_nvme_update_localport(vport);
index ef286313307365a7c56e2c80ea2dcd5adf5d0df4..e534e6f2b4198f8417c4ff8ad7faf801cf5bfb7c 100644 (file)
@@ -173,3 +173,11 @@ drm-amd-display-fix-yellow-carp-wm-clamping.patch
 net-usb-qmi_wwan-add-support-for-dell-dw5829e.patch
 net-macb-align-the-dma-and-coherent-dma-masks.patch
 kconfig-fix-failing-to-generate-auto.conf.patch
+scsi-lpfc-fix-pt2pt-nvme-prli-reject-logo-loop.patch
+edac-fix-calculation-of-returned-address-and-next-offset-in-edac_align_ptr.patch
+ucounts-handle-wrapping-in-is_ucounts_overlimit.patch
+ucounts-in-set_cred_ucounts-assume-new-ucounts-is-non-null.patch
+ucounts-base-set_cred_ucounts-changes-on-the-real-user.patch
+ucounts-enforce-rlimit_nproc-not-rlimit_nproc-1.patch
+rlimit-fix-rlimit_nproc-enforcement-failure-caused-by-capability-calls-in-set_user.patch
+ucounts-move-rlimit_nproc-handling-after-set_user.patch
diff --git a/queue-5.15/ucounts-base-set_cred_ucounts-changes-on-the-real-user.patch b/queue-5.15/ucounts-base-set_cred_ucounts-changes-on-the-real-user.patch
new file mode 100644 (file)
index 0000000..737a187
--- /dev/null
@@ -0,0 +1,80 @@
+From a55d07294f1e9b576093bdfa95422f8119941e83 Mon Sep 17 00:00:00 2001
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Wed, 9 Feb 2022 16:22:20 -0600
+Subject: ucounts: Base set_cred_ucounts changes on the real user
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Eric W. Biederman <ebiederm@xmission.com>
+
+commit a55d07294f1e9b576093bdfa95422f8119941e83 upstream.
+
+Michal Koutný <mkoutny@suse.com> wrote:
+> Tasks are associated to multiple users at once. Historically and as per
+> setrlimit(2) RLIMIT_NPROC is enforce based on real user ID.
+>
+> The commit 21d1c5e386bc ("Reimplement RLIMIT_NPROC on top of ucounts")
+> made the accounting structure "indexed" by euid and hence potentially
+> account tasks differently.
+>
+> The effective user ID may be different e.g. for setuid programs but
+> those are exec'd into already existing task (i.e. below limit), so
+> different accounting is moot.
+>
+> Some special setresuid(2) users may notice the difference, justifying
+> this fix.
+
+I looked at cred->ucount and it is only used for rlimit operations
+that were previously stored in cred->user.  Making the fact
+cred->ucount can refer to a different user from cred->user a bug,
+affecting all uses of cred->ulimit not just RLIMIT_NPROC.
+
+Fix set_cred_ucounts to always use the real uid not the effective uid.
+
+Further simplify set_cred_ucounts by noticing that set_cred_ucounts
+somehow retained a draft version of the check to see if alloc_ucounts
+was needed that checks the new->user and new->user_ns against the
+current_real_cred().  Remove that draft version of the check.
+
+All that matters for setting the cred->ucounts are the user_ns and uid
+fields in the cred.
+
+Cc: stable@vger.kernel.org
+Link: https://lkml.kernel.org/r/20220207121800.5079-4-mkoutny@suse.com
+Link: https://lkml.kernel.org/r/20220216155832.680775-3-ebiederm@xmission.com
+Reported-by: Michal Koutný <mkoutny@suse.com>
+Reviewed-by: Michal Koutný <mkoutny@suse.com>
+Fixes: 21d1c5e386bc ("Reimplement RLIMIT_NPROC on top of ucounts")
+Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/cred.c |    9 ++-------
+ 1 file changed, 2 insertions(+), 7 deletions(-)
+
+--- a/kernel/cred.c
++++ b/kernel/cred.c
+@@ -665,21 +665,16 @@ EXPORT_SYMBOL(cred_fscmp);
+ int set_cred_ucounts(struct cred *new)
+ {
+-      struct task_struct *task = current;
+-      const struct cred *old = task->real_cred;
+       struct ucounts *new_ucounts, *old_ucounts = new->ucounts;
+-      if (new->user == old->user && new->user_ns == old->user_ns)
+-              return 0;
+-
+       /*
+        * This optimization is needed because alloc_ucounts() uses locks
+        * for table lookups.
+        */
+-      if (old_ucounts->ns == new->user_ns && uid_eq(old_ucounts->uid, new->euid))
++      if (old_ucounts->ns == new->user_ns && uid_eq(old_ucounts->uid, new->uid))
+               return 0;
+-      if (!(new_ucounts = alloc_ucounts(new->user_ns, new->euid)))
++      if (!(new_ucounts = alloc_ucounts(new->user_ns, new->uid)))
+               return -EAGAIN;
+       new->ucounts = new_ucounts;
diff --git a/queue-5.15/ucounts-enforce-rlimit_nproc-not-rlimit_nproc-1.patch b/queue-5.15/ucounts-enforce-rlimit_nproc-not-rlimit_nproc-1.patch
new file mode 100644 (file)
index 0000000..f1836ef
--- /dev/null
@@ -0,0 +1,73 @@
+From 8f2f9c4d82f24f172ae439e5035fc1e0e4c229dd Mon Sep 17 00:00:00 2001
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Wed, 9 Feb 2022 20:03:19 -0600
+Subject: ucounts: Enforce RLIMIT_NPROC not RLIMIT_NPROC+1
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Eric W. Biederman <ebiederm@xmission.com>
+
+commit 8f2f9c4d82f24f172ae439e5035fc1e0e4c229dd upstream.
+
+Michal Koutný <mkoutny@suse.com> wrote:
+
+> It was reported that v5.14 behaves differently when enforcing
+> RLIMIT_NPROC limit, namely, it allows one more task than previously.
+> This is consequence of the commit 21d1c5e386bc ("Reimplement
+> RLIMIT_NPROC on top of ucounts") that missed the sharpness of
+> equality in the forking path.
+
+This can be fixed either by fixing the test or by moving the increment
+to be before the test.  Fix it my moving copy_creds which contains
+the increment before is_ucounts_overlimit.
+
+In the case of CLONE_NEWUSER the ucounts in the task_cred changes.
+The function is_ucounts_overlimit needs to use the final version of
+the ucounts for the new process.  Which means moving the
+is_ucounts_overlimit test after copy_creds is necessary.
+
+Both the test in fork and the test in set_user were semantically
+changed when the code moved to ucounts.  The change of the test in
+fork was bad because it was before the increment.  The test in
+set_user was wrong and the change to ucounts fixed it.  So this
+fix only restores the old behavior in one lcation not two.
+
+Link: https://lkml.kernel.org/r/20220204181144.24462-1-mkoutny@suse.com
+Link: https://lkml.kernel.org/r/20220216155832.680775-2-ebiederm@xmission.com
+Cc: stable@vger.kernel.org
+Reported-by: Michal Koutný <mkoutny@suse.com>
+Reviewed-by: Michal Koutný <mkoutny@suse.com>
+Fixes: 21d1c5e386bc ("Reimplement RLIMIT_NPROC on top of ucounts")
+Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/fork.c |   10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/kernel/fork.c
++++ b/kernel/fork.c
+@@ -2055,18 +2055,18 @@ static __latent_entropy struct task_stru
+ #ifdef CONFIG_PROVE_LOCKING
+       DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled);
+ #endif
++      retval = copy_creds(p, clone_flags);
++      if (retval < 0)
++              goto bad_fork_free;
++
+       retval = -EAGAIN;
+       if (is_ucounts_overlimit(task_ucounts(p), UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC))) {
+               if (p->real_cred->user != INIT_USER &&
+                   !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN))
+-                      goto bad_fork_free;
++                      goto bad_fork_cleanup_count;
+       }
+       current->flags &= ~PF_NPROC_EXCEEDED;
+-      retval = copy_creds(p, clone_flags);
+-      if (retval < 0)
+-              goto bad_fork_free;
+-
+       /*
+        * If multiple threads are within copy_process(), then this check
+        * triggers too late. This doesn't hurt, the check is only there
diff --git a/queue-5.15/ucounts-handle-wrapping-in-is_ucounts_overlimit.patch b/queue-5.15/ucounts-handle-wrapping-in-is_ucounts_overlimit.patch
new file mode 100644 (file)
index 0000000..99a6357
--- /dev/null
@@ -0,0 +1,38 @@
+From 0cbae9e24fa7d6c6e9f828562f084da82217a0c5 Mon Sep 17 00:00:00 2001
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Wed, 9 Feb 2022 18:09:41 -0600
+Subject: ucounts: Handle wrapping in is_ucounts_overlimit
+
+From: Eric W. Biederman <ebiederm@xmission.com>
+
+commit 0cbae9e24fa7d6c6e9f828562f084da82217a0c5 upstream.
+
+While examining is_ucounts_overlimit and reading the various messages
+I realized that is_ucounts_overlimit fails to deal with counts that
+may have wrapped.
+
+Being wrapped should be a transitory state for counts and they should
+never be wrapped for long, but it can happen so handle it.
+
+Cc: stable@vger.kernel.org
+Fixes: 21d1c5e386bc ("Reimplement RLIMIT_NPROC on top of ucounts")
+Link: https://lkml.kernel.org/r/20220216155832.680775-5-ebiederm@xmission.com
+Reviewed-by: Shuah Khan <skhan@linuxfoundation.org>
+Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/ucount.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/kernel/ucount.c
++++ b/kernel/ucount.c
+@@ -344,7 +344,8 @@ bool is_ucounts_overlimit(struct ucounts
+       if (rlimit > LONG_MAX)
+               max = LONG_MAX;
+       for (iter = ucounts; iter; iter = iter->ns->ucounts) {
+-              if (get_ucounts_value(iter, type) > max)
++              long val = get_ucounts_value(iter, type);
++              if (val < 0 || val > max)
+                       return true;
+               max = READ_ONCE(iter->ns->ucount_max[type]);
+       }
diff --git a/queue-5.15/ucounts-in-set_cred_ucounts-assume-new-ucounts-is-non-null.patch b/queue-5.15/ucounts-in-set_cred_ucounts-assume-new-ucounts-is-non-null.patch
new file mode 100644 (file)
index 0000000..71bc942
--- /dev/null
@@ -0,0 +1,45 @@
+From 99c31f9feda41d0f10d030dc04ba106c93295aa2 Mon Sep 17 00:00:00 2001
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Sat, 16 Oct 2021 12:51:58 -0500
+Subject: ucounts: In set_cred_ucounts assume new->ucounts is non-NULL
+
+From: Eric W. Biederman <ebiederm@xmission.com>
+
+commit 99c31f9feda41d0f10d030dc04ba106c93295aa2 upstream.
+
+Any cred that is destined for use by commit_creds must have a non-NULL
+cred->ucounts field.  Only curing credential construction is a NULL
+cred->ucounts valid.  Only abort_creds, put_cred, and put_cred_rcu
+needs to deal with a cred with a NULL ucount.  As set_cred_ucounts is
+non of those case don't confuse people by handling something that can
+not happen.
+
+Link: https://lkml.kernel.org/r/871r4irzds.fsf_-_@disp2133
+Tested-by: Yu Zhao <yuzhao@google.com>
+Reviewed-by: Alexey Gladkov <legion@kernel.org>
+Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/cred.c |    5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+--- a/kernel/cred.c
++++ b/kernel/cred.c
+@@ -676,15 +676,14 @@ int set_cred_ucounts(struct cred *new)
+        * This optimization is needed because alloc_ucounts() uses locks
+        * for table lookups.
+        */
+-      if (old_ucounts && old_ucounts->ns == new->user_ns && uid_eq(old_ucounts->uid, new->euid))
++      if (old_ucounts->ns == new->user_ns && uid_eq(old_ucounts->uid, new->euid))
+               return 0;
+       if (!(new_ucounts = alloc_ucounts(new->user_ns, new->euid)))
+               return -EAGAIN;
+       new->ucounts = new_ucounts;
+-      if (old_ucounts)
+-              put_ucounts(old_ucounts);
++      put_ucounts(old_ucounts);
+       return 0;
+ }
diff --git a/queue-5.15/ucounts-move-rlimit_nproc-handling-after-set_user.patch b/queue-5.15/ucounts-move-rlimit_nproc-handling-after-set_user.patch
new file mode 100644 (file)
index 0000000..3089999
--- /dev/null
@@ -0,0 +1,89 @@
+From c923a8e7edb010da67424077cbf1a6f1396ebd2e Mon Sep 17 00:00:00 2001
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Mon, 14 Feb 2022 09:40:25 -0600
+Subject: ucounts: Move RLIMIT_NPROC handling after set_user
+
+From: Eric W. Biederman <ebiederm@xmission.com>
+
+commit c923a8e7edb010da67424077cbf1a6f1396ebd2e upstream.
+
+During set*id() which cred->ucounts to charge the the current process
+to is not known until after set_cred_ucounts.  So move the
+RLIMIT_NPROC checking into a new helper flag_nproc_exceeded and call
+flag_nproc_exceeded after set_cred_ucounts.
+
+This is very much an arbitrary subset of the places where we currently
+change the RLIMIT_NPROC accounting, designed to preserve the existing
+logic.
+
+Fixing the existing logic will be the subject of another series of
+changes.
+
+Cc: stable@vger.kernel.org
+Link: https://lkml.kernel.org/r/20220216155832.680775-4-ebiederm@xmission.com
+Fixes: 21d1c5e386bc ("Reimplement RLIMIT_NPROC on top of ucounts")
+Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/sys.c |   19 ++++++++++++++-----
+ 1 file changed, 14 insertions(+), 5 deletions(-)
+
+--- a/kernel/sys.c
++++ b/kernel/sys.c
+@@ -472,6 +472,16 @@ static int set_user(struct cred *new)
+       if (!new_user)
+               return -EAGAIN;
++      free_uid(new->user);
++      new->user = new_user;
++      return 0;
++}
++
++static void flag_nproc_exceeded(struct cred *new)
++{
++      if (new->ucounts == current_ucounts())
++              return;
++
+       /*
+        * We don't fail in case of NPROC limit excess here because too many
+        * poorly written programs don't check set*uid() return code, assuming
+@@ -480,14 +490,10 @@ static int set_user(struct cred *new)
+        * failure to the execve() stage.
+        */
+       if (is_ucounts_overlimit(new->ucounts, UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC)) &&
+-                      new_user != INIT_USER)
++                      new->user != INIT_USER)
+               current->flags |= PF_NPROC_EXCEEDED;
+       else
+               current->flags &= ~PF_NPROC_EXCEEDED;
+-
+-      free_uid(new->user);
+-      new->user = new_user;
+-      return 0;
+ }
+ /*
+@@ -562,6 +568,7 @@ long __sys_setreuid(uid_t ruid, uid_t eu
+       if (retval < 0)
+               goto error;
++      flag_nproc_exceeded(new);
+       return commit_creds(new);
+ error:
+@@ -624,6 +631,7 @@ long __sys_setuid(uid_t uid)
+       if (retval < 0)
+               goto error;
++      flag_nproc_exceeded(new);
+       return commit_creds(new);
+ error:
+@@ -703,6 +711,7 @@ long __sys_setresuid(uid_t ruid, uid_t e
+       if (retval < 0)
+               goto error;
++      flag_nproc_exceeded(new);
+       return commit_creds(new);
+ error: