aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
authorAndy Adamson <andros@netapp.com>2009-04-03 01:28:12 -0400
committerJ. Bruce Fields <bfields@citi.umich.edu>2009-04-03 20:41:16 -0400
commitf9bb94c4c60f6e1d1717077bfddb614f03a607d1 (patch)
tree7f194a6ceca40f3b66e1e0a40b5f39af426269e1 /fs/nfsd
parentb85d4c01b76f6969a085d07a767fa45225cb14be (diff)
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>
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/nfs4proc.c40
-rw-r--r--fs/nfsd/nfs4state.c4
2 files changed, 36 insertions, 8 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index f7be7fabe62c..ec51936d2ce2 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -811,14 +811,15 @@ static inline void nfsd4_increment_op_stats(u32 opnum)
811 811
812typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *, 812typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *,
813 void *); 813 void *);
814enum nfsd4_op_flags {
815 ALLOWED_WITHOUT_FH = 1 << 0, /* No current filehandle required */
816 ALLOWED_ON_ABSENT_FS = 2 << 0, /* ops processed on absent fs */
817 ALLOWED_AS_FIRST_OP = 3 << 0, /* ops reqired first in compound */
818};
814 819
815struct nfsd4_operation { 820struct nfsd4_operation {
816 nfsd4op_func op_func; 821 nfsd4op_func op_func;
817 u32 op_flags; 822 u32 op_flags;
818/* Most ops require a valid current filehandle; a few don't: */
819#define ALLOWED_WITHOUT_FH 1
820/* GETATTR and ops not listed as returning NFS4ERR_MOVED: */
821#define ALLOWED_ON_ABSENT_FS 2
822 char *op_name; 823 char *op_name;
823}; 824};
824 825
@@ -827,6 +828,23 @@ static struct nfsd4_operation nfsd4_ops[];
827static const char *nfsd4_op_name(unsigned opnum); 828static const char *nfsd4_op_name(unsigned opnum);
828 829
829/* 830/*
831 * Enforce NFSv4.1 COMPOUND ordering rules.
832 *
833 * TODO:
834 * - enforce NFS4ERR_NOT_ONLY_OP,
835 * - DESTROY_SESSION MUST be the final operation in the COMPOUND request.
836 */
837static bool nfs41_op_ordering_ok(struct nfsd4_compoundargs *args)
838{
839 if (args->minorversion && args->opcnt > 0) {
840 struct nfsd4_op *op = &args->ops[0];
841 return (op->status == nfserr_op_illegal) ||
842 (nfsd4_ops[op->opnum].op_flags & ALLOWED_AS_FIRST_OP);
843 }
844 return true;
845}
846
847/*
830 * COMPOUND call. 848 * COMPOUND call.
831 */ 849 */
832static __be32 850static __be32
@@ -864,6 +882,12 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
864 if (args->minorversion > NFSD_SUPPORTED_MINOR_VERSION) 882 if (args->minorversion > NFSD_SUPPORTED_MINOR_VERSION)
865 goto out; 883 goto out;
866 884
885 if (!nfs41_op_ordering_ok(args)) {
886 op = &args->ops[0];
887 op->status = nfserr_sequence_pos;
888 goto encode_op;
889 }
890
867 status = nfs_ok; 891 status = nfs_ok;
868 while (!status && resp->opcnt < args->opcnt) { 892 while (!status && resp->opcnt < args->opcnt) {
869 op = &args->ops[resp->opcnt++]; 893 op = &args->ops[resp->opcnt++];
@@ -1105,22 +1129,22 @@ static struct nfsd4_operation nfsd4_ops[] = {
1105 /* NFSv4.1 operations */ 1129 /* NFSv4.1 operations */
1106 [OP_EXCHANGE_ID] = { 1130 [OP_EXCHANGE_ID] = {
1107 .op_func = (nfsd4op_func)nfsd4_exchange_id, 1131 .op_func = (nfsd4op_func)nfsd4_exchange_id,
1108 .op_flags = ALLOWED_WITHOUT_FH, 1132 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
1109 .op_name = "OP_EXCHANGE_ID", 1133 .op_name = "OP_EXCHANGE_ID",
1110 }, 1134 },
1111 [OP_CREATE_SESSION] = { 1135 [OP_CREATE_SESSION] = {
1112 .op_func = (nfsd4op_func)nfsd4_create_session, 1136 .op_func = (nfsd4op_func)nfsd4_create_session,
1113 .op_flags = ALLOWED_WITHOUT_FH, 1137 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
1114 .op_name = "OP_CREATE_SESSION", 1138 .op_name = "OP_CREATE_SESSION",
1115 }, 1139 },
1116 [OP_DESTROY_SESSION] = { 1140 [OP_DESTROY_SESSION] = {
1117 .op_func = (nfsd4op_func)nfsd4_destroy_session, 1141 .op_func = (nfsd4op_func)nfsd4_destroy_session,
1118 .op_flags = ALLOWED_WITHOUT_FH, 1142 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
1119 .op_name = "OP_DESTROY_SESSION", 1143 .op_name = "OP_DESTROY_SESSION",
1120 }, 1144 },
1121 [OP_SEQUENCE] = { 1145 [OP_SEQUENCE] = {
1122 .op_func = (nfsd4op_func)nfsd4_sequence, 1146 .op_func = (nfsd4op_func)nfsd4_sequence,
1123 .op_flags = ALLOWED_WITHOUT_FH, 1147 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
1124 .op_name = "OP_SEQUENCE", 1148 .op_name = "OP_SEQUENCE",
1125 }, 1149 },
1126}; 1150};
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 24b6e0593184..9243dca3576c 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1047,10 +1047,14 @@ nfsd4_sequence(struct svc_rqst *rqstp,
1047 struct nfsd4_compound_state *cstate, 1047 struct nfsd4_compound_state *cstate,
1048 struct nfsd4_sequence *seq) 1048 struct nfsd4_sequence *seq)
1049{ 1049{
1050 struct nfsd4_compoundres *resp = rqstp->rq_resp;
1050 struct nfsd4_session *session; 1051 struct nfsd4_session *session;
1051 struct nfsd4_slot *slot; 1052 struct nfsd4_slot *slot;
1052 int status; 1053 int status;
1053 1054
1055 if (resp->opcnt != 1)
1056 return nfserr_sequence_pos;
1057
1054 spin_lock(&sessionid_lock); 1058 spin_lock(&sessionid_lock);
1055 status = nfserr_badsession; 1059 status = nfserr_badsession;
1056 session = find_in_sessionid_hashtbl(&seq->sessionid); 1060 session = find_in_sessionid_hashtbl(&seq->sessionid);