Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

NeilBrown and committed by
Linus Torvalds
4c4cd222 3a4f98bb

+38 -16
+33 -16
fs/nfsd/nfs4state.c
··· 1160 1160 stp->st_deny_bmap = 0; 1161 1161 __set_bit(open->op_share_access, &stp->st_access_bmap); 1162 1162 __set_bit(open->op_share_deny, &stp->st_deny_bmap); 1163 + stp->st_openstp = NULL; 1163 1164 } 1164 1165 1165 1166 static void ··· 2159 2158 return status; 2160 2159 } 2161 2160 2161 + static inline int 2162 + setlkflg (int type) 2163 + { 2164 + return (type == NFS4_READW_LT || type == NFS4_READ_LT) ? 2165 + RD_STATE : WR_STATE; 2166 + } 2162 2167 2163 2168 /* 2164 2169 * Checks for sequence id mutating operations. 2165 2170 */ 2166 2171 static int 2167 - 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) 2172 + 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) 2168 2173 { 2169 2174 struct nfs4_stateid *stp; 2170 2175 struct nfs4_stateowner *sop; ··· 2208 2201 goto check_replay; 2209 2202 } 2210 2203 2211 - /* for new lock stateowners: 2212 - * check that the lock->v.new.open_stateid 2213 - * refers to an open stateowner 2214 - * 2215 - * check that the lockclid (nfs4_lock->v.new.clientid) is the same 2216 - * as the open_stateid->st_stateowner->so_client->clientid 2217 - */ 2218 - if (lockclid) { 2204 + if (lock) { 2219 2205 struct nfs4_stateowner *sop = stp->st_stateowner; 2206 + clientid_t *lockclid = &lock->v.new.clientid; 2220 2207 struct nfs4_client *clp = sop->so_client; 2208 + int lkflg = 0; 2209 + int status; 2221 2210 2222 - if (!sop->so_is_open_owner) 2223 - return nfserr_bad_stateid; 2224 - if (!cmp_clid(&clp->cl_clientid, lockclid)) 2225 - return nfserr_bad_stateid; 2211 + lkflg = setlkflg(lock->lk_type); 2212 + 2213 + if (lock->lk_is_new) { 2214 + if (!sop->so_is_open_owner) 2215 + return nfserr_bad_stateid; 2216 + if (!cmp_clid(&clp->cl_clientid, lockclid)) 2217 + return nfserr_bad_stateid; 2218 + /* stp is the open stateid */ 2219 + status = nfs4_check_openmode(stp, lkflg); 2220 + if (status) 2221 + return status; 2222 + } else { 2223 + /* stp is the lock stateid */ 2224 + status = nfs4_check_openmode(stp->st_openstp, lkflg); 2225 + if (status) 2226 + return status; 2227 + } 2228 + 2226 2229 } 2227 2230 2228 2231 if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) { ··· 2659 2642 stp->st_vfs_file = open_stp->st_vfs_file; /* FIXME refcount?? */ 2660 2643 stp->st_access_bmap = open_stp->st_access_bmap; 2661 2644 stp->st_deny_bmap = open_stp->st_deny_bmap; 2645 + stp->st_openstp = open_stp; 2662 2646 2663 2647 out: 2664 2648 return stp; ··· 2715 2697 lock->lk_new_open_seqid, 2716 2698 &lock->lk_new_open_stateid, 2717 2699 CHECK_FH | OPEN_STATE, 2718 - &open_sop, &open_stp, 2719 - &lock->v.new.clientid); 2700 + &open_sop, &open_stp, lock); 2720 2701 if (status) 2721 2702 goto out; 2722 2703 /* create lockowner and lock stateid */ ··· 2743 2726 lock->lk_old_lock_seqid, 2744 2727 &lock->lk_old_lock_stateid, 2745 2728 CHECK_FH | LOCK_STATE, 2746 - &lock->lk_stateowner, &lock_stp, NULL); 2729 + &lock->lk_stateowner, &lock_stp, lock); 2747 2730 if (status) 2748 2731 goto out; 2749 2732 }
+5
include/linux/nfsd/state.h
··· 237 237 * st_perlockowner: (open stateid) list of lock nfs4_stateowners 238 238 * st_access_bmap: used only for open stateid 239 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 242 246 struct nfs4_stateid { ··· 254 250 struct file * st_vfs_file; 255 251 unsigned long st_access_bmap; 256 252 unsigned long st_deny_bmap; 253 + struct nfs4_stateid * st_openstp; 257 254 }; 258 255 259 256 /* flags for preprocess_seqid_op() */