Skip to content

Commit a18093a

Browse files
committed
Merge tag 'nfsd-6.11-2' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux
Pull nfsd fixes from Chuck Lever: - Fix a number of crashers - Update email address for an NFSD reviewer * tag 'nfsd-6.11-2' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux: fs/nfsd: fix update of inode attrs in CB_GETATTR nfsd: fix potential UAF in nfsd4_cb_getattr_release nfsd: hold reference to delegation when updating it for cb_getattr MAINTAINERS: Update Olga Kornievskaia's email address nfsd: prevent panic for nfsv4.0 closed files in nfs4_show_open nfsd: ensure that nfsd4_fattr_args.context is zeroed out
2 parents 2840526 + 7e8ae84 commit a18093a

6 files changed

Lines changed: 51 additions & 25 deletions

File tree

MAINTAINERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12167,7 +12167,7 @@ KERNEL NFSD, SUNRPC, AND LOCKD SERVERS
1216712167
M: Chuck Lever <chuck.lever@oracle.com>
1216812168
M: Jeff Layton <jlayton@kernel.org>
1216912169
R: Neil Brown <neilb@suse.de>
12170-
R: Olga Kornievskaia <kolga@netapp.com>
12170+
R: Olga Kornievskaia <okorniev@redhat.com>
1217112171
R: Dai Ngo <Dai.Ngo@oracle.com>
1217212172
R: Tom Talpey <tom@talpey.com>
1217312173
L: linux-nfs@vger.kernel.org

fs/attr.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -487,9 +487,17 @@ int notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
487487
error = security_inode_setattr(idmap, dentry, attr);
488488
if (error)
489489
return error;
490-
error = try_break_deleg(inode, delegated_inode);
491-
if (error)
492-
return error;
490+
491+
/*
492+
* If ATTR_DELEG is set, then these attributes are being set on
493+
* behalf of the holder of a write delegation. We want to avoid
494+
* breaking the delegation in this case.
495+
*/
496+
if (!(ia_valid & ATTR_DELEG)) {
497+
error = try_break_deleg(inode, delegated_inode);
498+
if (error)
499+
return error;
500+
}
493501

494502
if (inode->i_op->setattr)
495503
error = inode->i_op->setattr(idmap, dentry, attr);

fs/nfsd/nfs4state.c

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2789,15 +2789,18 @@ static int nfs4_show_open(struct seq_file *s, struct nfs4_stid *st)
27892789
deny & NFS4_SHARE_ACCESS_READ ? "r" : "-",
27902790
deny & NFS4_SHARE_ACCESS_WRITE ? "w" : "-");
27912791

2792-
spin_lock(&nf->fi_lock);
2793-
file = find_any_file_locked(nf);
2794-
if (file) {
2795-
nfs4_show_superblock(s, file);
2796-
seq_puts(s, ", ");
2797-
nfs4_show_fname(s, file);
2798-
seq_puts(s, ", ");
2799-
}
2800-
spin_unlock(&nf->fi_lock);
2792+
if (nf) {
2793+
spin_lock(&nf->fi_lock);
2794+
file = find_any_file_locked(nf);
2795+
if (file) {
2796+
nfs4_show_superblock(s, file);
2797+
seq_puts(s, ", ");
2798+
nfs4_show_fname(s, file);
2799+
seq_puts(s, ", ");
2800+
}
2801+
spin_unlock(&nf->fi_lock);
2802+
} else
2803+
seq_puts(s, "closed, ");
28012804
nfs4_show_owner(s, oo);
28022805
if (st->sc_status & SC_STATUS_ADMIN_REVOKED)
28032806
seq_puts(s, ", admin-revoked");
@@ -3075,9 +3078,9 @@ nfsd4_cb_getattr_release(struct nfsd4_callback *cb)
30753078
struct nfs4_delegation *dp =
30763079
container_of(ncf, struct nfs4_delegation, dl_cb_fattr);
30773080

3078-
nfs4_put_stid(&dp->dl_stid);
30793081
clear_bit(CB_GETATTR_BUSY, &ncf->ncf_cb_flags);
30803082
wake_up_bit(&ncf->ncf_cb_flags, CB_GETATTR_BUSY);
3083+
nfs4_put_stid(&dp->dl_stid);
30813084
}
30823085

30833086
static const struct nfsd4_callback_ops nfsd4_cb_recall_any_ops = {
@@ -8812,7 +8815,7 @@ nfsd4_get_writestateid(struct nfsd4_compound_state *cstate,
88128815
/**
88138816
* nfsd4_deleg_getattr_conflict - Recall if GETATTR causes conflict
88148817
* @rqstp: RPC transaction context
8815-
* @inode: file to be checked for a conflict
8818+
* @dentry: dentry of inode to be checked for a conflict
88168819
* @modified: return true if file was modified
88178820
* @size: new size of file if modified is true
88188821
*
@@ -8827,16 +8830,16 @@ nfsd4_get_writestateid(struct nfsd4_compound_state *cstate,
88278830
* code is returned.
88288831
*/
88298832
__be32
8830-
nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode,
8833+
nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct dentry *dentry,
88318834
bool *modified, u64 *size)
88328835
{
88338836
__be32 status;
88348837
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
88358838
struct file_lock_context *ctx;
88368839
struct file_lease *fl;
8837-
struct nfs4_delegation *dp;
88388840
struct iattr attrs;
88398841
struct nfs4_cb_fattr *ncf;
8842+
struct inode *inode = d_inode(dentry);
88408843

88418844
*modified = false;
88428845
ctx = locks_inode_context(inode);
@@ -8859,14 +8862,16 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode,
88598862
goto break_lease;
88608863
}
88618864
if (type == F_WRLCK) {
8862-
dp = fl->c.flc_owner;
8865+
struct nfs4_delegation *dp = fl->c.flc_owner;
8866+
88638867
if (dp->dl_recall.cb_clp == *(rqstp->rq_lease_breaker)) {
88648868
spin_unlock(&ctx->flc_lock);
88658869
return 0;
88668870
}
88678871
break_lease:
88688872
nfsd_stats_wdeleg_getattr_inc(nn);
88698873
dp = fl->c.flc_owner;
8874+
refcount_inc(&dp->dl_stid.sc_count);
88708875
ncf = &dp->dl_cb_fattr;
88718876
nfs4_cb_getattr(&dp->dl_cb_fattr);
88728877
spin_unlock(&ctx->flc_lock);
@@ -8876,27 +8881,37 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode,
88768881
/* Recall delegation only if client didn't respond */
88778882
status = nfserrno(nfsd_open_break_lease(inode, NFSD_MAY_READ));
88788883
if (status != nfserr_jukebox ||
8879-
!nfsd_wait_for_delegreturn(rqstp, inode))
8884+
!nfsd_wait_for_delegreturn(rqstp, inode)) {
8885+
nfs4_put_stid(&dp->dl_stid);
88808886
return status;
8887+
}
88818888
}
88828889
if (!ncf->ncf_file_modified &&
88838890
(ncf->ncf_initial_cinfo != ncf->ncf_cb_change ||
88848891
ncf->ncf_cur_fsize != ncf->ncf_cb_fsize))
88858892
ncf->ncf_file_modified = true;
88868893
if (ncf->ncf_file_modified) {
8894+
int err;
8895+
88878896
/*
88888897
* Per section 10.4.3 of RFC 8881, the server would
88898898
* not update the file's metadata with the client's
88908899
* modified size
88918900
*/
88928901
attrs.ia_mtime = attrs.ia_ctime = current_time(inode);
8893-
attrs.ia_valid = ATTR_MTIME | ATTR_CTIME;
8894-
setattr_copy(&nop_mnt_idmap, inode, &attrs);
8895-
mark_inode_dirty(inode);
8902+
attrs.ia_valid = ATTR_MTIME | ATTR_CTIME | ATTR_DELEG;
8903+
inode_lock(inode);
8904+
err = notify_change(&nop_mnt_idmap, dentry, &attrs, NULL);
8905+
inode_unlock(inode);
8906+
if (err) {
8907+
nfs4_put_stid(&dp->dl_stid);
8908+
return nfserrno(err);
8909+
}
88968910
ncf->ncf_cur_fsize = ncf->ncf_cb_fsize;
88978911
*size = ncf->ncf_cur_fsize;
88988912
*modified = true;
88998913
}
8914+
nfs4_put_stid(&dp->dl_stid);
89008915
return 0;
89018916
}
89028917
break;

fs/nfsd/nfs4xdr.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3545,6 +3545,9 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
35453545
args.dentry = dentry;
35463546
args.ignore_crossmnt = (ignore_crossmnt != 0);
35473547
args.acl = NULL;
3548+
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
3549+
args.context = NULL;
3550+
#endif
35483551

35493552
/*
35503553
* Make a local copy of the attribute bitmap that can be modified.
@@ -3562,7 +3565,7 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
35623565
}
35633566
args.size = 0;
35643567
if (attrmask[0] & (FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE)) {
3565-
status = nfsd4_deleg_getattr_conflict(rqstp, d_inode(dentry),
3568+
status = nfsd4_deleg_getattr_conflict(rqstp, dentry,
35663569
&file_modified, &size);
35673570
if (status)
35683571
goto out;
@@ -3617,7 +3620,6 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
36173620
args.contextsupport = false;
36183621

36193622
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
3620-
args.context = NULL;
36213623
if ((attrmask[2] & FATTR4_WORD2_SECURITY_LABEL) ||
36223624
attrmask[0] & FATTR4_WORD0_SUPPORTED_ATTRS) {
36233625
if (exp->ex_flags & NFSEXP_SECURITY_LABEL)

fs/nfsd/state.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -781,5 +781,5 @@ static inline bool try_to_expire_client(struct nfs4_client *clp)
781781
}
782782

783783
extern __be32 nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp,
784-
struct inode *inode, bool *file_modified, u64 *size);
784+
struct dentry *dentry, bool *file_modified, u64 *size);
785785
#endif /* NFSD4_STATE_H */

include/linux/fs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
210210
#define ATTR_OPEN (1 << 15) /* Truncating from open(O_TRUNC) */
211211
#define ATTR_TIMES_SET (1 << 16)
212212
#define ATTR_TOUCH (1 << 17)
213+
#define ATTR_DELEG (1 << 18) /* Delegated attrs. Don't break write delegations */
213214

214215
/*
215216
* Whiteout is represented by a char device. The following constants define the

0 commit comments

Comments
 (0)