aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@cse.unsw.edu.au>2005-07-07 20:59:27 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-07-07 21:24:11 -0400
commit4c4cd222ee329025840bc2f8cebf71d36c62440c (patch)
tree70d1d8e754e7ab7226a6eee6afeab8b892072600
parent3a4f98bbf481cb9f755005ac569ceb5303e1b69f (diff)
[PATCH] nfsd4: check lock type against openmode.
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 <andros@citi.umich.edu> Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu> Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--fs/nfsd/nfs4state.c49
-rw-r--r--include/linux/nfsd/state.h5
2 files changed, 38 insertions, 16 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 59b214f01b6d..b83f8fb441e1 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1160,6 +1160,7 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *
1160 stp->st_deny_bmap = 0; 1160 stp->st_deny_bmap = 0;
1161 __set_bit(open->op_share_access, &stp->st_access_bmap); 1161 __set_bit(open->op_share_access, &stp->st_access_bmap);
1162 __set_bit(open->op_share_deny, &stp->st_deny_bmap); 1162 __set_bit(open->op_share_deny, &stp->st_deny_bmap);
1163 stp->st_openstp = NULL;
1163} 1164}
1164 1165
1165static void 1166static void
@@ -2158,12 +2159,18 @@ out:
2158 return status; 2159 return status;
2159} 2160}
2160 2161
2162static inline int
2163setlkflg (int type)
2164{
2165 return (type == NFS4_READW_LT || type == NFS4_READ_LT) ?
2166 RD_STATE : WR_STATE;
2167}
2161 2168
2162/* 2169/*
2163 * Checks for sequence id mutating operations. 2170 * Checks for sequence id mutating operations.
2164 */ 2171 */
2165static int 2172static int
2166nfs4_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) 2173nfs4_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)
2167{ 2174{
2168 struct nfs4_stateid *stp; 2175 struct nfs4_stateid *stp;
2169 struct nfs4_stateowner *sop; 2176 struct nfs4_stateowner *sop;
@@ -2201,21 +2208,31 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
2201 goto check_replay; 2208 goto check_replay;
2202 } 2209 }
2203 2210
2204 /* for new lock stateowners: 2211 if (lock) {
2205 * check that the lock->v.new.open_stateid
2206 * refers to an open stateowner
2207 *
2208 * check that the lockclid (nfs4_lock->v.new.clientid) is the same
2209 * as the open_stateid->st_stateowner->so_client->clientid
2210 */
2211 if (lockclid) {
2212 struct nfs4_stateowner *sop = stp->st_stateowner; 2212 struct nfs4_stateowner *sop = stp->st_stateowner;
2213 clientid_t *lockclid = &lock->v.new.clientid;
2213 struct nfs4_client *clp = sop->so_client; 2214 struct nfs4_client *clp = sop->so_client;
2215 int lkflg = 0;
2216 int status;
2217
2218 lkflg = setlkflg(lock->lk_type);
2219
2220 if (lock->lk_is_new) {
2221 if (!sop->so_is_open_owner)
2222 return nfserr_bad_stateid;
2223 if (!cmp_clid(&clp->cl_clientid, lockclid))
2224 return nfserr_bad_stateid;
2225 /* stp is the open stateid */
2226 status = nfs4_check_openmode(stp, lkflg);
2227 if (status)
2228 return status;
2229 } else {
2230 /* stp is the lock stateid */
2231 status = nfs4_check_openmode(stp->st_openstp, lkflg);
2232 if (status)
2233 return status;
2234 }
2214 2235
2215 if (!sop->so_is_open_owner)
2216 return nfserr_bad_stateid;
2217 if (!cmp_clid(&clp->cl_clientid, lockclid))
2218 return nfserr_bad_stateid;
2219 } 2236 }
2220 2237
2221 if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) { 2238 if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) {
@@ -2642,6 +2659,7 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc
2642 stp->st_vfs_file = open_stp->st_vfs_file; /* FIXME refcount?? */ 2659 stp->st_vfs_file = open_stp->st_vfs_file; /* FIXME refcount?? */
2643 stp->st_access_bmap = open_stp->st_access_bmap; 2660 stp->st_access_bmap = open_stp->st_access_bmap;
2644 stp->st_deny_bmap = open_stp->st_deny_bmap; 2661 stp->st_deny_bmap = open_stp->st_deny_bmap;
2662 stp->st_openstp = open_stp;
2645 2663
2646out: 2664out:
2647 return stp; 2665 return stp;
@@ -2697,8 +2715,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
2697 lock->lk_new_open_seqid, 2715 lock->lk_new_open_seqid,
2698 &lock->lk_new_open_stateid, 2716 &lock->lk_new_open_stateid,
2699 CHECK_FH | OPEN_STATE, 2717 CHECK_FH | OPEN_STATE,
2700 &open_sop, &open_stp, 2718 &open_sop, &open_stp, lock);
2701 &lock->v.new.clientid);
2702 if (status) 2719 if (status)
2703 goto out; 2720 goto out;
2704 /* create lockowner and lock stateid */ 2721 /* create lockowner and lock stateid */
@@ -2726,7 +2743,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
2726 lock->lk_old_lock_seqid, 2743 lock->lk_old_lock_seqid,
2727 &lock->lk_old_lock_stateid, 2744 &lock->lk_old_lock_stateid,
2728 CHECK_FH | LOCK_STATE, 2745 CHECK_FH | LOCK_STATE,
2729 &lock->lk_stateowner, &lock_stp, NULL); 2746 &lock->lk_stateowner, &lock_stp, lock);
2730 if (status) 2747 if (status)
2731 goto out; 2748 goto out;
2732 } 2749 }
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h
index 2d19431f47ea..8bf23cf8b603 100644
--- a/include/linux/nfsd/state.h
+++ b/include/linux/nfsd/state.h
@@ -237,6 +237,10 @@ struct nfs4_file {
237* st_perlockowner: (open stateid) list of lock nfs4_stateowners 237* st_perlockowner: (open stateid) list of lock nfs4_stateowners
238* st_access_bmap: used only for open stateid 238* st_access_bmap: used only for open stateid
239* st_deny_bmap: used only for open stateid 239* st_deny_bmap: used only for open stateid
240* st_openstp: open stateid lock stateid was derived from
241*
242* XXX: open stateids and lock stateids have diverged sufficiently that
243* we should consider defining separate structs for the two cases.
240*/ 244*/
241 245
242struct nfs4_stateid { 246struct nfs4_stateid {
@@ -250,6 +254,7 @@ struct nfs4_stateid {
250 struct file * st_vfs_file; 254 struct file * st_vfs_file;
251 unsigned long st_access_bmap; 255 unsigned long st_access_bmap;
252 unsigned long st_deny_bmap; 256 unsigned long st_deny_bmap;
257 struct nfs4_stateid * st_openstp;
253}; 258};
254 259
255/* flags for preprocess_seqid_op() */ 260/* flags for preprocess_seqid_op() */