Skip to content

Commit

Permalink
[PATCH] nfsd4: check lock type against openmode.
Browse files Browse the repository at this point in the history
We shouldn't be allowing, e.g., write locks on files not open for read.  To
enforce this, we add a pointer from the lock stateid back to the open stateid
it came from, so that the check will continue to be correct even after the
open is upgraded or downgraded.

Signed-off-by: Andy Adamson <[email protected]>
Signed-off-by: J. Bruce Fields <[email protected]>
Signed-off-by: Neil Brown <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
NeilBrown authored and Linus Torvalds committed Jul 8, 2005
1 parent 3a4f98b commit 4c4cd22
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 16 deletions.
49 changes: 33 additions & 16 deletions fs/nfsd/nfs4state.c
Original file line number Diff line number Diff line change
Expand Up @@ -1160,6 +1160,7 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *
stp->st_deny_bmap = 0;
__set_bit(open->op_share_access, &stp->st_access_bmap);
__set_bit(open->op_share_deny, &stp->st_deny_bmap);
stp->st_openstp = NULL;
}

static void
Expand Down Expand Up @@ -2158,12 +2159,18 @@ nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int fl
return status;
}

static inline int
setlkflg (int type)
{
return (type == NFS4_READW_LT || type == NFS4_READ_LT) ?
RD_STATE : WR_STATE;
}

/*
* Checks for sequence id mutating operations.
*/
static int
nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, clientid_t *lockclid)
nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, struct nfsd4_lock *lock)
{
struct nfs4_stateid *stp;
struct nfs4_stateowner *sop;
Expand Down Expand Up @@ -2201,21 +2208,31 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
goto check_replay;
}

/* for new lock stateowners:
* check that the lock->v.new.open_stateid
* refers to an open stateowner
*
* check that the lockclid (nfs4_lock->v.new.clientid) is the same
* as the open_stateid->st_stateowner->so_client->clientid
*/
if (lockclid) {
if (lock) {
struct nfs4_stateowner *sop = stp->st_stateowner;
clientid_t *lockclid = &lock->v.new.clientid;
struct nfs4_client *clp = sop->so_client;
int lkflg = 0;
int status;

lkflg = setlkflg(lock->lk_type);

if (lock->lk_is_new) {
if (!sop->so_is_open_owner)
return nfserr_bad_stateid;
if (!cmp_clid(&clp->cl_clientid, lockclid))
return nfserr_bad_stateid;
/* stp is the open stateid */
status = nfs4_check_openmode(stp, lkflg);
if (status)
return status;
} else {
/* stp is the lock stateid */
status = nfs4_check_openmode(stp->st_openstp, lkflg);
if (status)
return status;
}

if (!sop->so_is_open_owner)
return nfserr_bad_stateid;
if (!cmp_clid(&clp->cl_clientid, lockclid))
return nfserr_bad_stateid;
}

if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) {
Expand Down Expand Up @@ -2642,6 +2659,7 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc
stp->st_vfs_file = open_stp->st_vfs_file; /* FIXME refcount?? */
stp->st_access_bmap = open_stp->st_access_bmap;
stp->st_deny_bmap = open_stp->st_deny_bmap;
stp->st_openstp = open_stp;

out:
return stp;
Expand Down Expand Up @@ -2697,8 +2715,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
lock->lk_new_open_seqid,
&lock->lk_new_open_stateid,
CHECK_FH | OPEN_STATE,
&open_sop, &open_stp,
&lock->v.new.clientid);
&open_sop, &open_stp, lock);
if (status)
goto out;
/* create lockowner and lock stateid */
Expand Down Expand Up @@ -2726,7 +2743,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
lock->lk_old_lock_seqid,
&lock->lk_old_lock_stateid,
CHECK_FH | LOCK_STATE,
&lock->lk_stateowner, &lock_stp, NULL);
&lock->lk_stateowner, &lock_stp, lock);
if (status)
goto out;
}
Expand Down
5 changes: 5 additions & 0 deletions include/linux/nfsd/state.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,10 @@ struct nfs4_file {
* st_perlockowner: (open stateid) list of lock nfs4_stateowners
* st_access_bmap: used only for open stateid
* st_deny_bmap: used only for open stateid
* st_openstp: open stateid lock stateid was derived from
*
* XXX: open stateids and lock stateids have diverged sufficiently that
* we should consider defining separate structs for the two cases.
*/

struct nfs4_stateid {
Expand All @@ -250,6 +254,7 @@ struct nfs4_stateid {
struct file * st_vfs_file;
unsigned long st_access_bmap;
unsigned long st_deny_bmap;
struct nfs4_stateid * st_openstp;
};

/* flags for preprocess_seqid_op() */
Expand Down

0 comments on commit 4c4cd22

Please sign in to comment.