From: ChenXiaoSong chenxiaosong2@huawei.com
mainline inclusion from mainline-v5.18-rc2 commit ab0fc21bc7105b54bafd85bd8b82742f9e68898a category: bugfix bugzilla: 186890, https://gitee.com/openeuler/kernel/issues/I5BZTX CVE: NA
--------------------------------
This reverts commit 44942b4e457beda00981f616402a1a791e8c616e.
After secondly opening a file with O_ACCMODE|O_DIRECT flags, nfs4_valid_open_stateid() will dereference NULL nfs4_state when lseek().
Reproducer: 1. mount -t nfs -o vers=4.2 $server_ip:/ /mnt/ 2. fd = open("/mnt/file", O_ACCMODE|O_DIRECT|O_CREAT) 3. close(fd) 4. fd = open("/mnt/file", O_ACCMODE|O_DIRECT) 5. lseek(fd)
Reported-by: Lyu Tao tao.lyu@epfl.ch Signed-off-by: ChenXiaoSong chenxiaosong2@huawei.com Signed-off-by: Trond Myklebust trond.myklebust@hammerspace.com Signed-off-by: ChenXiaoSong chenxiaosong2@huawei.com Reviewed-by: Zhang Xiaoxu zhangxiaoxu5@huawei.com Signed-off-by: Yongqiang Liu liuyongqiang13@huawei.com --- fs/nfs/inode.c | 1 - fs/nfs/nfs4file.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index db52430dfbd7..053e78d777f1 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1103,7 +1103,6 @@ int nfs_open(struct inode *inode, struct file *filp) nfs_fscache_open_file(inode, filp); return 0; } -EXPORT_SYMBOL_GPL(nfs_open);
/* * This function is called whenever some part of NFS notices that diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index e053a883d08d..09d65a654c2b 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c @@ -49,7 +49,7 @@ nfs4_file_open(struct inode *inode, struct file *filp) return err;
if ((openflags & O_ACCMODE) == 3) - return nfs_open(inode, filp); + openflags--;
/* We can't create new files here */ openflags &= ~(O_CREAT|O_EXCL);
From: ChenXiaoSong chenxiaosong2@huawei.com
mainline inclusion from mainline-v5.18-rc2 commit b243874f6f9568b2daf1a00e9222cacdc15e159c category: bugfix bugzilla: 186890, https://gitee.com/openeuler/kernel/issues/I5BZTX CVE: NA
--------------------------------
open() with O_ACCMODE|O_DIRECT flags secondly will fail.
Reproducer: 1. mount -t nfs -o vers=4.2 $server_ip:/ /mnt/ 2. fd = open("/mnt/file", O_ACCMODE|O_DIRECT|O_CREAT) 3. close(fd) 4. fd = open("/mnt/file", O_ACCMODE|O_DIRECT)
Server nfsd4_decode_share_access() will fail with error nfserr_bad_xdr when client use incorrect share access mode of 0.
Fix this by using NFS4_SHARE_ACCESS_BOTH share access mode in client, just like firstly opening.
Fixes: ce4ef7c0a8a05 ("NFS: Split out NFS v4 file operations") Signed-off-by: ChenXiaoSong chenxiaosong2@huawei.com Signed-off-by: Trond Myklebust trond.myklebust@hammerspace.com
conflict: fs/nfs/internal.h
Signed-off-by: ChenXiaoSong chenxiaosong2@huawei.com Reviewed-by: Zhang Xiaoxu zhangxiaoxu5@huawei.com Signed-off-by: Yongqiang Liu liuyongqiang13@huawei.com --- fs/nfs/dir.c | 10 ---------- fs/nfs/internal.h | 10 ++++++++++ fs/nfs/nfs4file.c | 6 ++++-- 3 files changed, 14 insertions(+), 12 deletions(-)
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 2ec602eccb80..12d4c7686b2d 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1488,16 +1488,6 @@ const struct dentry_operations nfs4_dentry_operations = { }; EXPORT_SYMBOL_GPL(nfs4_dentry_operations);
-static fmode_t flags_to_mode(int flags) -{ - fmode_t res = (__force fmode_t)flags & FMODE_EXEC; - if ((flags & O_ACCMODE) != O_WRONLY) - res |= FMODE_READ; - if ((flags & O_ACCMODE) != O_RDONLY) - res |= FMODE_WRITE; - return res; -} - static struct nfs_open_context *create_nfs_open_context(struct dentry *dentry, int open_flags, struct file *filp) { return alloc_nfs_open_context(dentry, flags_to_mode(open_flags), filp); diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index c3c0b40f163f..0ce5a90640c4 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -39,6 +39,16 @@ static inline int nfs_attr_use_mounted_on_fileid(struct nfs_fattr *fattr) return 1; }
+static inline fmode_t flags_to_mode(int flags) +{ + fmode_t res = (__force fmode_t)flags & FMODE_EXEC; + if ((flags & O_ACCMODE) != O_WRONLY) + res |= FMODE_READ; + if ((flags & O_ACCMODE) != O_RDONLY) + res |= FMODE_WRITE; + return res; +} + struct nfs_clone_mount { const struct super_block *sb; const struct dentry *dentry; diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index 09d65a654c2b..5d3870836214 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c @@ -30,6 +30,7 @@ nfs4_file_open(struct inode *inode, struct file *filp) struct dentry *parent = NULL; struct inode *dir; unsigned openflags = filp->f_flags; + fmode_t f_mode; struct iattr attr; int err;
@@ -48,8 +49,9 @@ nfs4_file_open(struct inode *inode, struct file *filp) if (err) return err;
+ f_mode = filp->f_mode; if ((openflags & O_ACCMODE) == 3) - openflags--; + f_mode |= flags_to_mode(openflags);
/* We can't create new files here */ openflags &= ~(O_CREAT|O_EXCL); @@ -57,7 +59,7 @@ nfs4_file_open(struct inode *inode, struct file *filp) parent = dget_parent(dentry); dir = d_inode(parent);
- ctx = alloc_nfs_open_context(file_dentry(filp), filp->f_mode, filp); + ctx = alloc_nfs_open_context(file_dentry(filp), f_mode, filp); err = PTR_ERR(ctx); if (IS_ERR(ctx)) goto out;