mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	nfsd41: enforce NFS4ERR_SEQUENCE_POS operation order rules for minorversion != 0 only.
Signed-off-by: Andy Adamson<andros@netapp.com> [nfsd41: do not verify nfserr_sequence_pos for minorversion 0] Signed-off-by: Benny Halevy <bhalevy@panasas.com> Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
This commit is contained in:
		
							parent
							
								
									b85d4c01b7
								
							
						
					
					
						commit
						f9bb94c4c6
					
				
					 2 changed files with 36 additions and 8 deletions
				
			
		| 
						 | 
				
			
			@ -811,14 +811,15 @@ static inline void nfsd4_increment_op_stats(u32 opnum)
 | 
			
		|||
 | 
			
		||||
typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *,
 | 
			
		||||
			      void *);
 | 
			
		||||
enum nfsd4_op_flags {
 | 
			
		||||
	ALLOWED_WITHOUT_FH = 1 << 0,	/* No current filehandle required */
 | 
			
		||||
	ALLOWED_ON_ABSENT_FS = 2 << 0,	/* ops processed on absent fs */
 | 
			
		||||
	ALLOWED_AS_FIRST_OP = 3 << 0,	/* ops reqired first in compound */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct nfsd4_operation {
 | 
			
		||||
	nfsd4op_func op_func;
 | 
			
		||||
	u32 op_flags;
 | 
			
		||||
/* Most ops require a valid current filehandle; a few don't: */
 | 
			
		||||
#define ALLOWED_WITHOUT_FH 1
 | 
			
		||||
/* GETATTR and ops not listed as returning NFS4ERR_MOVED: */
 | 
			
		||||
#define ALLOWED_ON_ABSENT_FS 2
 | 
			
		||||
	char *op_name;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -826,6 +827,23 @@ static struct nfsd4_operation nfsd4_ops[];
 | 
			
		|||
 | 
			
		||||
static const char *nfsd4_op_name(unsigned opnum);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Enforce NFSv4.1 COMPOUND ordering rules.
 | 
			
		||||
 *
 | 
			
		||||
 * TODO:
 | 
			
		||||
 * - enforce NFS4ERR_NOT_ONLY_OP,
 | 
			
		||||
 * - DESTROY_SESSION MUST be the final operation in the COMPOUND request.
 | 
			
		||||
 */
 | 
			
		||||
static bool nfs41_op_ordering_ok(struct nfsd4_compoundargs *args)
 | 
			
		||||
{
 | 
			
		||||
	if (args->minorversion && args->opcnt > 0) {
 | 
			
		||||
		struct nfsd4_op *op = &args->ops[0];
 | 
			
		||||
		return (op->status == nfserr_op_illegal) ||
 | 
			
		||||
		       (nfsd4_ops[op->opnum].op_flags & ALLOWED_AS_FIRST_OP);
 | 
			
		||||
	}
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * COMPOUND call.
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -864,6 +882,12 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
 | 
			
		|||
	if (args->minorversion > NFSD_SUPPORTED_MINOR_VERSION)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	if (!nfs41_op_ordering_ok(args)) {
 | 
			
		||||
		op = &args->ops[0];
 | 
			
		||||
		op->status = nfserr_sequence_pos;
 | 
			
		||||
		goto encode_op;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	status = nfs_ok;
 | 
			
		||||
	while (!status && resp->opcnt < args->opcnt) {
 | 
			
		||||
		op = &args->ops[resp->opcnt++];
 | 
			
		||||
| 
						 | 
				
			
			@ -1105,22 +1129,22 @@ static struct nfsd4_operation nfsd4_ops[] = {
 | 
			
		|||
	/* NFSv4.1 operations */
 | 
			
		||||
	[OP_EXCHANGE_ID] = {
 | 
			
		||||
		.op_func = (nfsd4op_func)nfsd4_exchange_id,
 | 
			
		||||
		.op_flags = ALLOWED_WITHOUT_FH,
 | 
			
		||||
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
 | 
			
		||||
		.op_name = "OP_EXCHANGE_ID",
 | 
			
		||||
	},
 | 
			
		||||
	[OP_CREATE_SESSION] = {
 | 
			
		||||
		.op_func = (nfsd4op_func)nfsd4_create_session,
 | 
			
		||||
		.op_flags = ALLOWED_WITHOUT_FH,
 | 
			
		||||
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
 | 
			
		||||
		.op_name = "OP_CREATE_SESSION",
 | 
			
		||||
	},
 | 
			
		||||
	[OP_DESTROY_SESSION] = {
 | 
			
		||||
		.op_func = (nfsd4op_func)nfsd4_destroy_session,
 | 
			
		||||
		.op_flags = ALLOWED_WITHOUT_FH,
 | 
			
		||||
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
 | 
			
		||||
		.op_name = "OP_DESTROY_SESSION",
 | 
			
		||||
	},
 | 
			
		||||
	[OP_SEQUENCE] = {
 | 
			
		||||
		.op_func = (nfsd4op_func)nfsd4_sequence,
 | 
			
		||||
		.op_flags = ALLOWED_WITHOUT_FH,
 | 
			
		||||
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
 | 
			
		||||
		.op_name = "OP_SEQUENCE",
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1047,10 +1047,14 @@ nfsd4_sequence(struct svc_rqst *rqstp,
 | 
			
		|||
	       struct nfsd4_compound_state *cstate,
 | 
			
		||||
	       struct nfsd4_sequence *seq)
 | 
			
		||||
{
 | 
			
		||||
	struct nfsd4_compoundres *resp = rqstp->rq_resp;
 | 
			
		||||
	struct nfsd4_session *session;
 | 
			
		||||
	struct nfsd4_slot *slot;
 | 
			
		||||
	int status;
 | 
			
		||||
 | 
			
		||||
	if (resp->opcnt != 1)
 | 
			
		||||
		return nfserr_sequence_pos;
 | 
			
		||||
 | 
			
		||||
	spin_lock(&sessionid_lock);
 | 
			
		||||
	status = nfserr_badsession;
 | 
			
		||||
	session = find_in_sessionid_hashtbl(&seq->sessionid);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue