Skip to content

Commit

Permalink
nfsd: Fix another OPEN stateid race
Browse files Browse the repository at this point in the history
If nfsd4_process_open2() is initialising a new stateid, and yet the
call to nfs4_get_vfs_file() fails for some reason, then we must
declare the stateid closed, and unhash it before dropping the mutex.

Right now, we unhash the stateid after dropping the mutex, and without
changing the stateid type, meaning that another OPEN could theoretically
look it up and attempt to use it.

Reported-by: Andrew W Elble <[email protected]>
Signed-off-by: Trond Myklebust <[email protected]>
Cc: [email protected]
Signed-off-by: J. Bruce Fields <[email protected]>
  • Loading branch information
trondmypd authored and J. Bruce Fields committed Nov 27, 2017
1 parent 15ca08d commit d8a1a00
Showing 1 changed file with 13 additions and 15 deletions.
28 changes: 13 additions & 15 deletions fs/nfsd/nfs4state.c
Original file line number Diff line number Diff line change
Expand Up @@ -4502,6 +4502,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
struct nfs4_ol_stateid *stp = NULL;
struct nfs4_delegation *dp = NULL;
__be32 status;
bool new_stp = false;

/*
* Lookup file; if found, lookup stateid and check open request,
Expand All @@ -4521,34 +4522,31 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
goto out;
}

if (!stp) {
stp = init_open_stateid(fp, open);
if (!open->op_stp)
new_stp = true;
}

/*
* OPEN the file, or upgrade an existing OPEN.
* If truncate fails, the OPEN fails.
*
* stp is already locked.
*/
if (stp) {
if (!new_stp) {
/* Stateid was found, this is an OPEN upgrade */
status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open);
if (status) {
mutex_unlock(&stp->st_mutex);
goto out;
}
} else {
/* stp is returned locked. */
stp = init_open_stateid(fp, open);
/* See if we lost the race to some other thread */
if (stp->st_access_bmap != 0) {
status = nfs4_upgrade_open(rqstp, fp, current_fh,
stp, open);
if (status) {
mutex_unlock(&stp->st_mutex);
goto out;
}
goto upgrade_out;
}
status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open);
if (status) {
mutex_unlock(&stp->st_mutex);
stp->st_stid.sc_type = NFS4_CLOSED_STID;
release_open_stateid(stp);
mutex_unlock(&stp->st_mutex);
goto out;
}

Expand All @@ -4557,7 +4555,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
if (stp->st_clnt_odstate == open->op_odstate)
open->op_odstate = NULL;
}
upgrade_out:

nfs4_inc_and_copy_stateid(&open->op_stateid, &stp->st_stid);
mutex_unlock(&stp->st_mutex);

Expand Down

0 comments on commit d8a1a00

Please sign in to comment.