From: Chuck Lever <chuck.lever(a)oracle.com>
mainline inclusion
from mainline-v5.17-rc4
commit 0cb4d23ae08c48f6bf3c29a8e5c4a74b8388b960
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IADG80
CVE: CVE-2022-48827
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?…
--------------------------------
Dan Aloni reports:
> Due to commit 8cfb9015280d ("NFS: Always provide aligned buffers to
> the RPC read layers") on the client, a read of 0xfff is aligned up
> to server rsize of 0x1000.
>
> As a result, in a test where the server has a file of size
> 0x7fffffffffffffff, and the client tries to read from the offset
> 0x7ffffffffffff000, the read causes loff_t overflow in the server
> and it returns an NFS code of EINVAL to the client. The client as
> a result indefinitely retries the request.
The Linux NFS client does not handle NFS?ERR_INVAL, even though all
NFS specifications permit servers to return that status code for a
READ.
Instead of NFS?ERR_INVAL, have out-of-range READ requests succeed
and return a short result. Set the EOF flag in the result to prevent
the client from retrying the READ request. This behavior appears to
be consistent with Solaris NFS servers.
Note that NFSv3 and NFSv4 use u64 offset values on the wire. These
must be converted to loff_t internally before use -- an implicit
type cast is not adequate for this purpose. Otherwise VFS checks
against sb->s_maxbytes do not work properly.
Reported-by: Dan Aloni <dan.aloni(a)vastdata.com>
Cc: stable(a)vger.kernel.org
Signed-off-by: Chuck Lever <chuck.lever(a)oracle.com>
Conflicts:
fs/nfsd/nfs3proc.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4xdr.c
[Commit be63bd2ac6bb("NFSD: Update READ3arg decoder to use struct
xdr_stream") modified the method of initializing resp->count;
Commit 5c4583b2b78e("nfsd: hook up nfs4_preprocess_stateid_op to the
nfsd_file cache") remove rd_filp from nfsd4_read and remove the check of
rd_tmp_file in nfsd4_encode_read;
Commit 528b84934eb9("NFSD: Add READ_PLUS data support") add READ_PLUS data
support.]
Signed-off-by: Li Lingfeng <lilingfeng3(a)huawei.com>
---
fs/nfsd/nfs3proc.c | 11 ++++++++---
fs/nfsd/nfs4proc.c | 8 ++++++--
fs/nfsd/nfs4xdr.c | 5 +----
3 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index c9cf46e0c040..2ac8f5912dfa 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -154,18 +154,23 @@ nfsd3_proc_read(struct svc_rqst *rqstp)
struct nfsd3_readres *resp = rqstp->rq_resp;
__be32 nfserr;
u32 max_blocksize = svc_max_payload(rqstp);
- unsigned long cnt = min(argp->count, max_blocksize);
dprintk("nfsd: READ(3) %s %lu bytes at %Lu\n",
SVCFH_fmt(&argp->fh),
(unsigned long) argp->count,
(unsigned long long) argp->offset);
+ argp->count = min_t(u32, argp->count, max_blocksize);
+ if (argp->offset > (u64)OFFSET_MAX)
+ argp->offset = (u64)OFFSET_MAX;
+ if (argp->offset + argp->count > (u64)OFFSET_MAX)
+ argp->count = (u64)OFFSET_MAX - argp->offset;
+
/* Obtain buffer pointer for payload.
* 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof)
* + 1 (xdr opaque byte count) = 26
*/
- resp->count = cnt;
+ resp->count = argp->count;
svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4);
fh_copy(&resp->fh, &argp->fh);
@@ -175,7 +180,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp)
&resp->count);
if (nfserr == 0) {
struct inode *inode = d_inode(resp->fh.fh_dentry);
- resp->eof = nfsd_eof_on_read(cnt, resp->count, argp->offset,
+ resp->eof = nfsd_eof_on_read(resp->count, resp->count, argp->offset,
inode->i_size);
}
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 1c3e6de6bcba..8bb0b6d2ea4e 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -760,12 +760,16 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
__be32 status;
read->rd_filp = NULL;
- if (read->rd_offset >= OFFSET_MAX)
- return nfserr_inval;
trace_nfsd_read_start(rqstp, &cstate->current_fh,
read->rd_offset, read->rd_length);
+ read->rd_length = min_t(u32, read->rd_length, svc_max_payload(rqstp));
+ if (read->rd_offset > (u64)OFFSET_MAX)
+ read->rd_offset = (u64)OFFSET_MAX;
+ if (read->rd_offset + read->rd_length > (u64)OFFSET_MAX)
+ read->rd_length = (u64)OFFSET_MAX - read->rd_offset;
+
/*
* If we do a zero copy read, then a client will see read data
* that reflects the state of the file *after* performing the
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index db0beefe65ec..7dae38d21041 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3595,11 +3595,8 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
}
xdr_commit_encode(xdr);
- maxcount = svc_max_payload(resp->rqstp);
- maxcount = min_t(unsigned long, maxcount,
+ maxcount = min_t(unsigned long, read->rd_length,
(xdr->buf->buflen - xdr->buf->len));
- maxcount = min_t(unsigned long, maxcount, read->rd_length);
-
if (read->rd_tmp_file)
ra = nfsd_init_raparms(file);
--
2.31.1
tree: https://gitee.com/openeuler/kernel.git openEuler-1.0-LTS
head: 8d2f09e210f079f53eb6c1ba1ef639d73a17d61b
commit: bb87eff0e698d6e312b435f482d4b0b5672b11d0 [1696/23347] usb: roles: Add a description for the class to Kconfig
config: x86_64-buildonly-randconfig-005-20240723 (https://download.01.org/0day-ci/archive/20240723/202407232033.iAaUwu3f-lkp@…)
compiler: gcc-12 (Ubuntu 12.3.0-9ubuntu2) 12.3.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240723/202407232033.iAaUwu3f-lkp@…)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp(a)intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202407232033.iAaUwu3f-lkp@intel.com/
All warnings (new ones prefixed by >>):
In file included from drivers/usb/roles/class.c:12:
include/linux/module.h:133:13: warning: 'init_module' specifies less restrictive attribute than its target 'usb_roles_init': 'cold' [-Wmissing-attributes]
133 | int init_module(void) __attribute__((alias(#initfn)));
| ^~~~~~~~~~~
include/linux/module.h:116:41: note: in expansion of macro 'module_init'
116 | #define subsys_initcall(fn) module_init(fn)
| ^~~~~~~~~~~
drivers/usb/roles/class.c:303:1: note: in expansion of macro 'subsys_initcall'
303 | subsys_initcall(usb_roles_init);
| ^~~~~~~~~~~~~~~
drivers/usb/roles/class.c:298:19: note: 'init_module' target declared here
298 | static int __init usb_roles_init(void)
| ^~~~~~~~~~~~~~
include/linux/module.h:139:14: warning: 'cleanup_module' specifies less restrictive attribute than its target 'usb_roles_exit': 'cold' [-Wmissing-attributes]
139 | void cleanup_module(void) __attribute__((alias(#exitfn)));
| ^~~~~~~~~~~~~~
drivers/usb/roles/class.c:309:1: note: in expansion of macro 'module_exit'
309 | module_exit(usb_roles_exit);
| ^~~~~~~~~~~
drivers/usb/roles/class.c:305:20: note: 'cleanup_module' target declared here
305 | static void __exit usb_roles_exit(void)
| ^~~~~~~~~~~~~~
>> drivers/usb/roles/class.o: warning: objtool: missing symbol for section .exit.text
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki