Blame SOURCES/CVE-2022-43945.patch

cf3d8e
From 279997974099abbc4a1ac28ed243f62bc039cf65 Mon Sep 17 00:00:00 2001
cf3d8e
From: Yannick Cote <ycote@redhat.com>
cf3d8e
Date: Mon, 12 Dec 2022 19:34:33 -0500
cf3d8e
Subject: [KPATCH CVE-2022-43945] kpatch fixes for CVE-2022-43945
cf3d8e
cf3d8e
Kernels:
cf3d8e
5.14.0-162.6.1.el9_1
cf3d8e
cf3d8e
cf3d8e
Kpatch-MR: https://gitlab.com/redhat/prdsc/rhel/src/kpatch/rhel-9/-/merge_requests/14
cf3d8e
Approved-by: Joe Lawrence (@joe.lawrence)
cf3d8e
Changes since last build:
cf3d8e
[x86_64]:
cf3d8e
ax88179_178a.o: changed function: ax88179_rx_fixup
cf3d8e
callback_xdr.o: changed function: nfs_callback_dispatch
cf3d8e
intel_gt.o: changed function: intel_gt_invalidate_tlbs
cf3d8e
nfs3proc.o: changed function: nfsd3_init_dirlist_pages
cf3d8e
nfs3proc.o: changed function: nfsd3_proc_read
cf3d8e
nfsproc.o: changed function: nfsd_proc_read
cf3d8e
nfsproc.o: changed function: nfsd_proc_readdir
cf3d8e
nfssvc.o: changed function: nfsd_dispatch
cf3d8e
pipe.o: changed function: pipe_resize_ring
cf3d8e
svc.o: changed function: nlmsvc_dispatch
cf3d8e
cf3d8e
[ppc64le]:
cf3d8e
ax88179_178a.o: changed function: ax88179_rx_fixup
cf3d8e
callback_xdr.o: changed function: nfs_callback_dispatch
cf3d8e
nfs3proc.o: changed function: nfsd3_init_dirlist_pages
cf3d8e
nfs3proc.o: changed function: nfsd3_proc_read
cf3d8e
nfsproc.o: changed function: nfsd_proc_read
cf3d8e
nfsproc.o: changed function: nfsd_proc_readdir
cf3d8e
nfssvc.o: changed function: nfsd_dispatch
cf3d8e
pipe.o: changed function: pipe_resize_ring
cf3d8e
svc.o: changed function: nlmsvc_dispatch
cf3d8e
cf3d8e
---------------------------
cf3d8e
cf3d8e
Modifications:
cf3d8e
- Take out modifications to header routines and roll new kpatch versions
cf3d8e
  of them to be included at all call sites.
cf3d8e
- Wrapped new routines: svcxdr_init_decode(), svcxdr_init_encode()
cf3d8e
cf3d8e
commit a7e335af244128a81a936cfc8d23509e29fc0b72
cf3d8e
Author: Scott Mayhew <smayhew@redhat.com>
cf3d8e
Date:   Thu Nov 10 13:41:53 2022 -0500
cf3d8e
cf3d8e
    SUNRPC: Fix svcxdr_init_decode's end-of-buffer calculation
cf3d8e
cf3d8e
    Bugzilla: https://bugzilla.redhat.com/2141769
cf3d8e
    CVE: CVE-2022-43945
cf3d8e
    Y-Commit: 63e941917cd28dff8b33ce5c8658aac3b7dc5c75
cf3d8e
cf3d8e
    O-Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2141770
cf3d8e
    O-CVE: CVE-2022-43945
cf3d8e
cf3d8e
    commit 90bfc37b5ab91c1a6165e3e5cfc49bf04571b762
cf3d8e
    Author: Chuck Lever <chuck.lever@oracle.com>
cf3d8e
    Date:   Thu Sep 1 15:09:53 2022 -0400
cf3d8e
cf3d8e
        SUNRPC: Fix svcxdr_init_decode's end-of-buffer calculation
cf3d8e
cf3d8e
        Ensure that stream-based argument decoding can't go past the actual
cf3d8e
        end of the receive buffer. xdr_init_decode's calculation of the
cf3d8e
        value of xdr->end over-estimates the end of the buffer because the
cf3d8e
        Linux kernel RPC server code does not remove the size of the RPC
cf3d8e
        header from rqstp->rq_arg before calling the upper layer's
cf3d8e
        dispatcher.
cf3d8e
cf3d8e
        The server-side still uses the svc_getnl() macros to decode the
cf3d8e
        RPC call header. These macros reduce the length of the head iov
cf3d8e
        but do not update the total length of the message in the buffer
cf3d8e
        (buf->len).
cf3d8e
cf3d8e
        A proper fix for this would be to replace the use of svc_getnl() and
cf3d8e
        friends in the RPC header decoder, but that would be a large and
cf3d8e
        invasive change that would be difficult to backport.
cf3d8e
cf3d8e
        Fixes: 5191955d6fc6 ("SUNRPC: Prepare for xdr_stream-style decoding on the server-side")
cf3d8e
        Reviewed-by: Jeff Layton <jlayton@kernel.org>
cf3d8e
        Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
cf3d8e
cf3d8e
    Signed-off-by: Scott Mayhew <smayhew@redhat.com>
cf3d8e
    Signed-off-by: Patrick Talbert <ptalbert@redhat.com>
cf3d8e
cf3d8e
commit 8d718c29ff4601ff5ca279421f7e2187a38d856f
cf3d8e
Author: Scott Mayhew <smayhew@redhat.com>
cf3d8e
Date:   Thu Nov 10 13:41:52 2022 -0500
cf3d8e
cf3d8e
    SUNRPC: Fix svcxdr_init_encode's buflen calculation
cf3d8e
cf3d8e
    Bugzilla: https://bugzilla.redhat.com/2141769
cf3d8e
    CVE: CVE-2022-43945
cf3d8e
    Y-Commit: 02ef2175406bbe8753f6ff08d3dae4d927f88c69
cf3d8e
cf3d8e
    O-Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2141770
cf3d8e
    O-CVE: CVE-2022-43945
cf3d8e
cf3d8e
    commit 1242a87da0d8cd2a428e96ca68e7ea899b0f4624
cf3d8e
    Author: Chuck Lever <chuck.lever@oracle.com>
cf3d8e
    Date:   Thu Sep 1 15:09:59 2022 -0400
cf3d8e
cf3d8e
        SUNRPC: Fix svcxdr_init_encode's buflen calculation
cf3d8e
cf3d8e
        Commit 2825a7f90753 ("nfsd4: allow encoding across page boundaries")
cf3d8e
        added an explicit computation of the remaining length in the rq_res
cf3d8e
        XDR buffer.
cf3d8e
cf3d8e
        The computation appears to suffer from an "off-by-one" bug. Because
cf3d8e
        buflen is too large by one page, XDR encoding can run off the end of
cf3d8e
        the send buffer by eventually trying to use the struct page address
cf3d8e
        in rq_page_end, which always contains NULL.
cf3d8e
cf3d8e
        Fixes: bddfdbcddbe2 ("NFSD: Extract the svcxdr_init_encode() helper")
cf3d8e
        Reviewed-by: Jeff Layton <jlayton@kernel.org>
cf3d8e
        Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
cf3d8e
cf3d8e
    Signed-off-by: Scott Mayhew <smayhew@redhat.com>
cf3d8e
    Signed-off-by: Patrick Talbert <ptalbert@redhat.com>
cf3d8e
cf3d8e
commit b4648565ad97ee05956cabbb56d89f29932e7a02
cf3d8e
Author: Scott Mayhew <smayhew@redhat.com>
cf3d8e
Date:   Thu Nov 10 13:41:52 2022 -0500
cf3d8e
cf3d8e
    NFSD: Protect against send buffer overflow in NFSv2 READDIR
cf3d8e
cf3d8e
    Bugzilla: https://bugzilla.redhat.com/2141769
cf3d8e
    CVE: CVE-2022-43945
cf3d8e
    Y-Commit: 13ed52506cc7713e48ae64bd11ba867295aed137
cf3d8e
cf3d8e
    O-Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2141770
cf3d8e
    O-CVE: CVE-2022-43945
cf3d8e
cf3d8e
    commit 00b4492686e0497fdb924a9d4c8f6f99377e176c
cf3d8e
    Author: Chuck Lever <chuck.lever@oracle.com>
cf3d8e
    Date:   Thu Sep 1 15:10:05 2022 -0400
cf3d8e
cf3d8e
        NFSD: Protect against send buffer overflow in NFSv2 READDIR
cf3d8e
cf3d8e
        Restore the previous limit on the @count argument to prevent a
cf3d8e
        buffer overflow attack.
cf3d8e
cf3d8e
        Fixes: 53b1119a6e50 ("NFSD: Fix READDIR buffer overflow")
cf3d8e
        Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
cf3d8e
        Reviewed-by: Jeff Layton <jlayton@kernel.org>
cf3d8e
        Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
cf3d8e
cf3d8e
    Signed-off-by: Scott Mayhew <smayhew@redhat.com>
cf3d8e
    Signed-off-by: Patrick Talbert <ptalbert@redhat.com>
cf3d8e
cf3d8e
commit 08fca21e5fe53bd2e0ef7ddbe9cb302ccedeba45
cf3d8e
Author: Scott Mayhew <smayhew@redhat.com>
cf3d8e
Date:   Thu Nov 10 13:41:52 2022 -0500
cf3d8e
cf3d8e
    NFSD: Protect against send buffer overflow in NFSv3 READDIR
cf3d8e
cf3d8e
    Bugzilla: https://bugzilla.redhat.com/2141769
cf3d8e
    CVE: CVE-2022-43945
cf3d8e
    Y-Commit: 2a688c7c62dce0bc5e4377d82d830fe2955503cc
cf3d8e
cf3d8e
    O-Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2141770
cf3d8e
    O-CVE: CVE-2022-43945
cf3d8e
cf3d8e
    commit 640f87c190e0d1b2a0fcb2ecf6d2cd53b1c41991
cf3d8e
    Author: Chuck Lever <chuck.lever@oracle.com>
cf3d8e
    Date:   Thu Sep 1 15:10:12 2022 -0400
cf3d8e
cf3d8e
        NFSD: Protect against send buffer overflow in NFSv3 READDIR
cf3d8e
cf3d8e
        Since before the git era, NFSD has conserved the number of pages
cf3d8e
        held by each nfsd thread by combining the RPC receive and send
cf3d8e
        buffers into a single array of pages. This works because there are
cf3d8e
        no cases where an operation needs a large RPC Call message and a
cf3d8e
        large RPC Reply message at the same time.
cf3d8e
cf3d8e
        Once an RPC Call has been received, svc_process() updates
cf3d8e
        svc_rqst::rq_res to describe the part of rq_pages that can be
cf3d8e
        used for constructing the Reply. This means that the send buffer
cf3d8e
        (rq_res) shrinks when the received RPC record containing the RPC
cf3d8e
        Call is large.
cf3d8e
cf3d8e
        A client can force this shrinkage on TCP by sending a correctly-
cf3d8e
        formed RPC Call header contained in an RPC record that is
cf3d8e
        excessively large. The full maximum payload size cannot be
cf3d8e
        constructed in that case.
cf3d8e
cf3d8e
        Thanks to Aleksi Illikainen and Kari Hulkko for uncovering this
cf3d8e
        issue.
cf3d8e
cf3d8e
        Reported-by: Ben Ronallo <Benjamin.Ronallo@synopsys.com>
cf3d8e
        Cc: <stable@vger.kernel.org>
cf3d8e
        Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
cf3d8e
        Reviewed-by: Jeff Layton <jlayton@kernel.org>
cf3d8e
        Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
cf3d8e
cf3d8e
    Signed-off-by: Scott Mayhew <smayhew@redhat.com>
cf3d8e
    Signed-off-by: Patrick Talbert <ptalbert@redhat.com>
cf3d8e
cf3d8e
commit 5665aff4c12502c39f372548d1be622d99ad2252
cf3d8e
Author: Scott Mayhew <smayhew@redhat.com>
cf3d8e
Date:   Thu Nov 10 13:41:52 2022 -0500
cf3d8e
cf3d8e
    NFSD: Protect against send buffer overflow in NFSv2 READ
cf3d8e
cf3d8e
    Bugzilla: https://bugzilla.redhat.com/2141769
cf3d8e
    CVE: CVE-2022-43945
cf3d8e
    Y-Commit: 385d7c5a859c93544e7aad1dfe8e955f2035ab5f
cf3d8e
cf3d8e
    O-Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2141770
cf3d8e
    O-CVE: CVE-2022-43945
cf3d8e
cf3d8e
    commit 401bc1f90874280a80b93f23be33a0e7e2d1f912
cf3d8e
    Author: Chuck Lever <chuck.lever@oracle.com>
cf3d8e
    Date:   Thu Sep 1 15:10:18 2022 -0400
cf3d8e
cf3d8e
        NFSD: Protect against send buffer overflow in NFSv2 READ
cf3d8e
cf3d8e
        Since before the git era, NFSD has conserved the number of pages
cf3d8e
        held by each nfsd thread by combining the RPC receive and send
cf3d8e
        buffers into a single array of pages. This works because there are
cf3d8e
        no cases where an operation needs a large RPC Call message and a
cf3d8e
        large RPC Reply at the same time.
cf3d8e
cf3d8e
        Once an RPC Call has been received, svc_process() updates
cf3d8e
        svc_rqst::rq_res to describe the part of rq_pages that can be
cf3d8e
        used for constructing the Reply. This means that the send buffer
cf3d8e
        (rq_res) shrinks when the received RPC record containing the RPC
cf3d8e
        Call is large.
cf3d8e
cf3d8e
        A client can force this shrinkage on TCP by sending a correctly-
cf3d8e
        formed RPC Call header contained in an RPC record that is
cf3d8e
        excessively large. The full maximum payload size cannot be
cf3d8e
        constructed in that case.
cf3d8e
cf3d8e
        Cc: <stable@vger.kernel.org>
cf3d8e
        Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
cf3d8e
        Reviewed-by: Jeff Layton <jlayton@kernel.org>
cf3d8e
        Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
cf3d8e
cf3d8e
    Signed-off-by: Scott Mayhew <smayhew@redhat.com>
cf3d8e
    Signed-off-by: Patrick Talbert <ptalbert@redhat.com>
cf3d8e
cf3d8e
commit f036edb9860c89970440f8d524831b11afd399fb
cf3d8e
Author: Scott Mayhew <smayhew@redhat.com>
cf3d8e
Date:   Thu Nov 10 13:41:52 2022 -0500
cf3d8e
cf3d8e
    NFSD: Protect against send buffer overflow in NFSv3 READ
cf3d8e
cf3d8e
    Bugzilla: https://bugzilla.redhat.com/2141769
cf3d8e
    CVE: CVE-2022-43945
cf3d8e
    Y-Commit: 45f0034c12711e534531b23c15c04aa060c9ed47
cf3d8e
cf3d8e
    O-Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2141770
cf3d8e
    O-CVE: CVE-2022-43945
cf3d8e
cf3d8e
    commit fa6be9cc6e80ec79892ddf08a8c10cabab9baf38
cf3d8e
    Author: Chuck Lever <chuck.lever@oracle.com>
cf3d8e
    Date:   Thu Sep 1 15:10:24 2022 -0400
cf3d8e
cf3d8e
        NFSD: Protect against send buffer overflow in NFSv3 READ
cf3d8e
cf3d8e
        Since before the git era, NFSD has conserved the number of pages
cf3d8e
        held by each nfsd thread by combining the RPC receive and send
cf3d8e
        buffers into a single array of pages. This works because there are
cf3d8e
        no cases where an operation needs a large RPC Call message and a
cf3d8e
        large RPC Reply at the same time.
cf3d8e
cf3d8e
        Once an RPC Call has been received, svc_process() updates
cf3d8e
        svc_rqst::rq_res to describe the part of rq_pages that can be
cf3d8e
        used for constructing the Reply. This means that the send buffer
cf3d8e
        (rq_res) shrinks when the received RPC record containing the RPC
cf3d8e
        Call is large.
cf3d8e
cf3d8e
        A client can force this shrinkage on TCP by sending a correctly-
cf3d8e
        formed RPC Call header contained in an RPC record that is
cf3d8e
        excessively large. The full maximum payload size cannot be
cf3d8e
        constructed in that case.
cf3d8e
cf3d8e
        Cc: <stable@vger.kernel.org>
cf3d8e
        Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
cf3d8e
        Reviewed-by: Jeff Layton <jlayton@kernel.org>
cf3d8e
        Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
cf3d8e
cf3d8e
    Signed-off-by: Scott Mayhew <smayhew@redhat.com>
cf3d8e
    Signed-off-by: Patrick Talbert <ptalbert@redhat.com>
cf3d8e
cf3d8e
Signed-off-by: Yannick Cote <ycote@redhat.com>
cf3d8e
---
cf3d8e
 fs/lockd/svc.c                        |  6 ++-
cf3d8e
 fs/nfs/callback_xdr.c                 |  6 ++-
cf3d8e
 fs/nfsd/nfs3proc.c                    | 11 +++---
cf3d8e
 fs/nfsd/nfsproc.c                     |  6 +--
cf3d8e
 fs/nfsd/nfssvc.c                      |  6 ++-
cf3d8e
 include/linux/kpatch_cve_2022_43945.h | 53 +++++++++++++++++++++++++++
cf3d8e
 6 files changed, 74 insertions(+), 14 deletions(-)
cf3d8e
 create mode 100644 include/linux/kpatch_cve_2022_43945.h
cf3d8e
cf3d8e
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
cf3d8e
index b220e1b91726..e8b6e09af323 100644
cf3d8e
--- a/fs/lockd/svc.c
cf3d8e
+++ b/fs/lockd/svc.c
cf3d8e
@@ -768,6 +768,8 @@ static void __exit exit_nlm(void)
cf3d8e
 module_init(init_nlm);
cf3d8e
 module_exit(exit_nlm);
cf3d8e
 
cf3d8e
+#include <linux/kpatch_cve_2022_43945.h>
cf3d8e
+
cf3d8e
 /**
cf3d8e
  * nlmsvc_dispatch - Process an NLM Request
cf3d8e
  * @rqstp: incoming request
cf3d8e
@@ -781,7 +783,7 @@ static int nlmsvc_dispatch(struct svc_rqst *rqstp, __be32 *statp)
cf3d8e
 {
cf3d8e
 	const struct svc_procedure *procp = rqstp->rq_procinfo;
cf3d8e
 
cf3d8e
-	svcxdr_init_decode(rqstp);
cf3d8e
+	kpatch_cve_2022_43945_svcxdr_init_decode(rqstp);
cf3d8e
 	if (!procp->pc_decode(rqstp, &rqstp->rq_arg_stream))
cf3d8e
 		goto out_decode_err;
cf3d8e
 
cf3d8e
@@ -791,7 +793,7 @@ static int nlmsvc_dispatch(struct svc_rqst *rqstp, __be32 *statp)
cf3d8e
 	if (*statp != rpc_success)
cf3d8e
 		return 1;
cf3d8e
 
cf3d8e
-	svcxdr_init_encode(rqstp);
cf3d8e
+	kpatch_cve_2022_43945_svcxdr_init_encode(rqstp);
cf3d8e
 	if (!procp->pc_encode(rqstp, &rqstp->rq_res_stream))
cf3d8e
 		goto out_encode_err;
cf3d8e
 
cf3d8e
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c
cf3d8e
index a67c41ec545f..9438f91b9c2d 100644
cf3d8e
--- a/fs/nfs/callback_xdr.c
cf3d8e
+++ b/fs/nfs/callback_xdr.c
cf3d8e
@@ -983,13 +983,15 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp)
cf3d8e
 	return rpc_success;
cf3d8e
 }
cf3d8e
 
cf3d8e
+#include <linux/kpatch_cve_2022_43945.h>
cf3d8e
+
cf3d8e
 static int
cf3d8e
 nfs_callback_dispatch(struct svc_rqst *rqstp, __be32 *statp)
cf3d8e
 {
cf3d8e
 	const struct svc_procedure *procp = rqstp->rq_procinfo;
cf3d8e
 
cf3d8e
-	svcxdr_init_decode(rqstp);
cf3d8e
-	svcxdr_init_encode(rqstp);
cf3d8e
+	kpatch_cve_2022_43945_svcxdr_init_decode(rqstp);
cf3d8e
+	kpatch_cve_2022_43945_svcxdr_init_encode(rqstp);
cf3d8e
 
cf3d8e
 	*statp = procp->pc_func(rqstp);
cf3d8e
 	return 1;
cf3d8e
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
cf3d8e
index 9d2667a8dbd1..e0eb8b7acec8 100644
cf3d8e
--- a/fs/nfsd/nfs3proc.c
cf3d8e
+++ b/fs/nfsd/nfs3proc.c
cf3d8e
@@ -147,7 +147,6 @@ nfsd3_proc_read(struct svc_rqst *rqstp)
cf3d8e
 {
cf3d8e
 	struct nfsd3_readargs *argp = rqstp->rq_argp;
cf3d8e
 	struct nfsd3_readres *resp = rqstp->rq_resp;
cf3d8e
-	u32 max_blocksize = svc_max_payload(rqstp);
cf3d8e
 	unsigned int len;
cf3d8e
 	int v;
cf3d8e
 
cf3d8e
@@ -156,7 +155,8 @@ nfsd3_proc_read(struct svc_rqst *rqstp)
cf3d8e
 				(unsigned long) argp->count,
cf3d8e
 				(unsigned long long) argp->offset);
cf3d8e
 
cf3d8e
-	argp->count = min_t(u32, argp->count, max_blocksize);
cf3d8e
+	argp->count = min_t(u32, argp->count, svc_max_payload(rqstp));
cf3d8e
+	argp->count = min_t(u32, argp->count, rqstp->rq_res.buflen);
cf3d8e
 	if (argp->offset > (u64)OFFSET_MAX)
cf3d8e
 		argp->offset = (u64)OFFSET_MAX;
cf3d8e
 	if (argp->offset + argp->count > (u64)OFFSET_MAX)
cf3d8e
@@ -554,13 +554,14 @@ static void nfsd3_init_dirlist_pages(struct svc_rqst *rqstp,
cf3d8e
 {
cf3d8e
 	struct xdr_buf *buf = &resp->dirlist;
cf3d8e
 	struct xdr_stream *xdr = &resp->xdr;
cf3d8e
-
cf3d8e
-	count = clamp(count, (u32)(XDR_UNIT * 2), svc_max_payload(rqstp));
cf3d8e
+	unsigned int sendbuf = min_t(unsigned int, rqstp->rq_res.buflen,
cf3d8e
+				     svc_max_payload(rqstp));
cf3d8e
 
cf3d8e
 	memset(buf, 0, sizeof(*buf));
cf3d8e
 
cf3d8e
 	/* Reserve room for the NULL ptr & eof flag (-2 words) */
cf3d8e
-	buf->buflen = count - XDR_UNIT * 2;
cf3d8e
+	buf->buflen = clamp(count, (u32)(XDR_UNIT * 2), sendbuf);
cf3d8e
+	buf->buflen -= XDR_UNIT * 2;
cf3d8e
 	buf->pages = rqstp->rq_next_page;
cf3d8e
 	rqstp->rq_next_page += (buf->buflen + PAGE_SIZE - 1) >> PAGE_SHIFT;
cf3d8e
 
cf3d8e
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
cf3d8e
index de282f3273c5..6c15d4ac52e8 100644
cf3d8e
--- a/fs/nfsd/nfsproc.c
cf3d8e
+++ b/fs/nfsd/nfsproc.c
cf3d8e
@@ -182,6 +182,7 @@ nfsd_proc_read(struct svc_rqst *rqstp)
cf3d8e
 		argp->count, argp->offset);
cf3d8e
 
cf3d8e
 	argp->count = min_t(u32, argp->count, NFSSVC_MAXBLKSIZE_V2);
cf3d8e
+	argp->count = min_t(u32, argp->count, rqstp->rq_res.buflen);
cf3d8e
 
cf3d8e
 	v = 0;
cf3d8e
 	len = argp->count;
cf3d8e
@@ -561,12 +562,11 @@ static void nfsd_init_dirlist_pages(struct svc_rqst *rqstp,
cf3d8e
 	struct xdr_buf *buf = &resp->dirlist;
cf3d8e
 	struct xdr_stream *xdr = &resp->xdr;
cf3d8e
 
cf3d8e
-	count = clamp(count, (u32)(XDR_UNIT * 2), svc_max_payload(rqstp));
cf3d8e
-
cf3d8e
 	memset(buf, 0, sizeof(*buf));
cf3d8e
 
cf3d8e
 	/* Reserve room for the NULL ptr & eof flag (-2 words) */
cf3d8e
-	buf->buflen = count - XDR_UNIT * 2;
cf3d8e
+	buf->buflen = clamp(count, (u32)(XDR_UNIT * 2), (u32)PAGE_SIZE);
cf3d8e
+	buf->buflen -= XDR_UNIT * 2;
cf3d8e
 	buf->pages = rqstp->rq_next_page;
cf3d8e
 	rqstp->rq_next_page++;
cf3d8e
 
cf3d8e
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
cf3d8e
index 80431921e5d7..125f490147df 100644
cf3d8e
--- a/fs/nfsd/nfssvc.c
cf3d8e
+++ b/fs/nfsd/nfssvc.c
cf3d8e
@@ -990,6 +990,8 @@ nfsd(void *vrqstp)
cf3d8e
 	return 0;
cf3d8e
 }
cf3d8e
 
cf3d8e
+#include <linux/kpatch_cve_2022_43945.h>
cf3d8e
+
cf3d8e
 /**
cf3d8e
  * nfsd_dispatch - Process an NFS or NFSACL Request
cf3d8e
  * @rqstp: incoming request
cf3d8e
@@ -1011,7 +1013,7 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
cf3d8e
 	 */
cf3d8e
 	rqstp->rq_cachetype = proc->pc_cachetype;
cf3d8e
 
cf3d8e
-	svcxdr_init_decode(rqstp);
cf3d8e
+	kpatch_cve_2022_43945_svcxdr_init_decode(rqstp);
cf3d8e
 	if (!proc->pc_decode(rqstp, &rqstp->rq_arg_stream))
cf3d8e
 		goto out_decode_err;
cf3d8e
 
cf3d8e
@@ -1028,7 +1030,7 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
cf3d8e
 	 * Need to grab the location to store the status, as
cf3d8e
 	 * NFSv4 does some encoding while processing
cf3d8e
 	 */
cf3d8e
-	svcxdr_init_encode(rqstp);
cf3d8e
+	kpatch_cve_2022_43945_svcxdr_init_encode(rqstp);
cf3d8e
 
cf3d8e
 	*statp = proc->pc_func(rqstp);
cf3d8e
 	if (*statp == rpc_drop_reply || test_bit(RQ_DROPME, &rqstp->rq_flags))
cf3d8e
diff --git a/include/linux/kpatch_cve_2022_43945.h b/include/linux/kpatch_cve_2022_43945.h
cf3d8e
new file mode 100644
cf3d8e
index 000000000000..d52392485a57
cf3d8e
--- /dev/null
cf3d8e
+++ b/include/linux/kpatch_cve_2022_43945.h
cf3d8e
@@ -0,0 +1,53 @@
cf3d8e
+#ifndef _KPATCH_CVE_2022_43945_H
cf3d8e
+#define _KPATCH_CVE_2022_43945_H
cf3d8e
+
cf3d8e
+/*
cf3d8e
+ * svcxdr_init_decode - Prepare an xdr_stream for Call decoding
cf3d8e
+ * @rqstp: controlling server RPC transaction context
cf3d8e
+ *
cf3d8e
+ * This function currently assumes the RPC header in rq_arg has
cf3d8e
+ * already been decoded. Upon return, xdr->p points to the
cf3d8e
+ * location of the upper layer header.
cf3d8e
+ */
cf3d8e
+static inline void kpatch_cve_2022_43945_svcxdr_init_decode(struct svc_rqst *rqstp)
cf3d8e
+{
cf3d8e
+	struct xdr_stream *xdr = &rqstp->rq_arg_stream;
cf3d8e
+	struct xdr_buf *buf = &rqstp->rq_arg;
cf3d8e
+	struct kvec *argv = buf->head;
cf3d8e
+
cf3d8e
+	/*
cf3d8e
+	 * svc_getnl() and friends do not keep the xdr_buf's ::len
cf3d8e
+	 * field up to date. Refresh that field before initializing
cf3d8e
+	 * the argument decoding stream.
cf3d8e
+	 */
cf3d8e
+	buf->len = buf->head->iov_len + buf->page_len + buf->tail->iov_len;
cf3d8e
+
cf3d8e
+	xdr_init_decode(xdr, buf, argv->iov_base, NULL);
cf3d8e
+	xdr_set_scratch_page(xdr, rqstp->rq_scratch_page);
cf3d8e
+}
cf3d8e
+
cf3d8e
+/*
cf3d8e
+ * svcxdr_init_encode - Prepare an xdr_stream for svc Reply encoding
cf3d8e
+ * @rqstp: controlling server RPC transaction context
cf3d8e
+ *
cf3d8e
+ */
cf3d8e
+static inline void kpatch_cve_2022_43945_svcxdr_init_encode(struct svc_rqst *rqstp)
cf3d8e
+{
cf3d8e
+	struct xdr_stream *xdr = &rqstp->rq_res_stream;
cf3d8e
+	struct xdr_buf *buf = &rqstp->rq_res;
cf3d8e
+	struct kvec *resv = buf->head;
cf3d8e
+
cf3d8e
+	xdr_reset_scratch_buffer(xdr);
cf3d8e
+
cf3d8e
+	xdr->buf = buf;
cf3d8e
+	xdr->iov = resv;
cf3d8e
+	xdr->p   = resv->iov_base + resv->iov_len;
cf3d8e
+	xdr->end = resv->iov_base + PAGE_SIZE - rqstp->rq_auth_slack;
cf3d8e
+	buf->len = resv->iov_len;
cf3d8e
+	xdr->page_ptr = buf->pages - 1;
cf3d8e
+	buf->buflen = PAGE_SIZE * (rqstp->rq_page_end - buf->pages);
cf3d8e
+	buf->buflen -= rqstp->rq_auth_slack;
cf3d8e
+	xdr->rqst = NULL;
cf3d8e
+}
cf3d8e
+
cf3d8e
+#endif /* _KPATCH_CVE_2022_43945_H */
cf3d8e
-- 
cf3d8e
2.39.0
cf3d8e
cf3d8e