Skip to content

Commit

Permalink
nfsd41: enforce NFS4ERR_SEQUENCE_POS operation order rules for minorv…
Browse files Browse the repository at this point in the history
…ersion != 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>
  • Loading branch information
Andy Adamson authored and J. Bruce Fields committed Apr 4, 2009
1 parent b85d4c0 commit f9bb94c
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 8 deletions.
40 changes: 32 additions & 8 deletions fs/nfsd/nfs4proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -811,21 +811,39 @@ 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;
};

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.
*/
Expand Down Expand Up @@ -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++];
Expand Down Expand Up @@ -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",
},
};
Expand Down
4 changes: 4 additions & 0 deletions fs/nfsd/nfs4state.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit f9bb94c

Please sign in to comment.