aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4proc.c
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2011-04-08 17:00:50 -0400
committerJ. Bruce Fields <bfields@redhat.com>2011-04-29 20:47:51 -0400
commit68d93184352f2e723f135b0a9bad93b58f9d120b (patch)
treeedf66ceadd6ce4559a53355b83265dc65a7d7694 /fs/nfsd/nfs4proc.c
parent29a78a3ed7fc9c4ee49962751eb321b038c190a2 (diff)
nfsd4: fix wrongsec handling for PUTFH + op cases
When PUTFH is followed by an operation that uses the filehandle, and when the current client is using a security flavor that is inconsistent with the given filehandle, we have a choice: we can return WRONGSEC either when the current filehandle is set using the PUTFH, or when the filehandle is first used by the following operation. Follow the recommendations of RFC 5661 in making this choice. (Our current behavior prevented the client from doing security negotiation by returning WRONGSEC on PUTFH+SECINFO_NO_NAME.) Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd/nfs4proc.c')
-rw-r--r--fs/nfsd/nfs4proc.c59
1 files changed, 54 insertions, 5 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 8059adae013b..ad32568a1aa7 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -403,7 +403,7 @@ nfsd4_putfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
403 cstate->current_fh.fh_handle.fh_size = putfh->pf_fhlen; 403 cstate->current_fh.fh_handle.fh_size = putfh->pf_fhlen;
404 memcpy(&cstate->current_fh.fh_handle.fh_base, putfh->pf_fhval, 404 memcpy(&cstate->current_fh.fh_handle.fh_base, putfh->pf_fhval,
405 putfh->pf_fhlen); 405 putfh->pf_fhlen);
406 return fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP); 406 return fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_BYPASS_GSS);
407} 407}
408 408
409static __be32 409static __be32
@@ -989,6 +989,9 @@ enum nfsd4_op_flags {
989 ALLOWED_WITHOUT_FH = 1 << 0, /* No current filehandle required */ 989 ALLOWED_WITHOUT_FH = 1 << 0, /* No current filehandle required */
990 ALLOWED_ON_ABSENT_FS = 1 << 1, /* ops processed on absent fs */ 990 ALLOWED_ON_ABSENT_FS = 1 << 1, /* ops processed on absent fs */
991 ALLOWED_AS_FIRST_OP = 1 << 2, /* ops reqired first in compound */ 991 ALLOWED_AS_FIRST_OP = 1 << 2, /* ops reqired first in compound */
992 /* For rfc 5661 section 2.6.3.1.1: */
993 OP_HANDLES_WRONGSEC = 1 << 3,
994 OP_IS_PUTFH_LIKE = 1 << 4,
992}; 995};
993 996
994struct nfsd4_operation { 997struct nfsd4_operation {
@@ -1039,6 +1042,39 @@ static inline struct nfsd4_operation *OPDESC(struct nfsd4_op *op)
1039 return &nfsd4_ops[op->opnum]; 1042 return &nfsd4_ops[op->opnum];
1040} 1043}
1041 1044
1045static bool need_wrongsec_check(struct svc_rqst *rqstp)
1046{
1047 struct nfsd4_compoundres *resp = rqstp->rq_resp;
1048 struct nfsd4_compoundargs *argp = rqstp->rq_argp;
1049 struct nfsd4_op *this = &argp->ops[resp->opcnt - 1];
1050 struct nfsd4_op *next = &argp->ops[resp->opcnt];
1051 struct nfsd4_operation *thisd;
1052 struct nfsd4_operation *nextd;
1053
1054 thisd = OPDESC(this);
1055 /*
1056 * Most ops check wronsec on our own; only the putfh-like ops
1057 * have special rules.
1058 */
1059 if (!(thisd->op_flags & OP_IS_PUTFH_LIKE))
1060 return false;
1061 /*
1062 * rfc 5661 2.6.3.1.1.6: don't bother erroring out a
1063 * put-filehandle operation if we're not going to use the
1064 * result:
1065 */
1066 if (argp->opcnt == resp->opcnt)
1067 return false;
1068
1069 nextd = OPDESC(next);
1070 /*
1071 * Rest of 2.6.3.1.1: certain operations will return WRONGSEC
1072 * errors themselves as necessary; others should check for them
1073 * now:
1074 */
1075 return !(nextd->op_flags & OP_HANDLES_WRONGSEC);
1076}
1077
1042/* 1078/*
1043 * COMPOUND call. 1079 * COMPOUND call.
1044 */ 1080 */
@@ -1134,6 +1170,9 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
1134 else 1170 else
1135 BUG_ON(op->status == nfs_ok); 1171 BUG_ON(op->status == nfs_ok);
1136 1172
1173 if (!op->status && need_wrongsec_check(rqstp))
1174 op->status = check_nfsd_access(cstate->current_fh.fh_export, rqstp);
1175
1137encode_op: 1176encode_op:
1138 /* Only from SEQUENCE */ 1177 /* Only from SEQUENCE */
1139 if (resp->cstate.status == nfserr_replay_cache) { 1178 if (resp->cstate.status == nfserr_replay_cache) {
@@ -1225,10 +1264,12 @@ static struct nfsd4_operation nfsd4_ops[] = {
1225 }, 1264 },
1226 [OP_LOOKUP] = { 1265 [OP_LOOKUP] = {
1227 .op_func = (nfsd4op_func)nfsd4_lookup, 1266 .op_func = (nfsd4op_func)nfsd4_lookup,
1267 .op_flags = OP_HANDLES_WRONGSEC,
1228 .op_name = "OP_LOOKUP", 1268 .op_name = "OP_LOOKUP",
1229 }, 1269 },
1230 [OP_LOOKUPP] = { 1270 [OP_LOOKUPP] = {
1231 .op_func = (nfsd4op_func)nfsd4_lookupp, 1271 .op_func = (nfsd4op_func)nfsd4_lookupp,
1272 .op_flags = OP_HANDLES_WRONGSEC,
1232 .op_name = "OP_LOOKUPP", 1273 .op_name = "OP_LOOKUPP",
1233 }, 1274 },
1234 [OP_NVERIFY] = { 1275 [OP_NVERIFY] = {
@@ -1237,6 +1278,7 @@ static struct nfsd4_operation nfsd4_ops[] = {
1237 }, 1278 },
1238 [OP_OPEN] = { 1279 [OP_OPEN] = {
1239 .op_func = (nfsd4op_func)nfsd4_open, 1280 .op_func = (nfsd4op_func)nfsd4_open,
1281 .op_flags = OP_HANDLES_WRONGSEC,
1240 .op_name = "OP_OPEN", 1282 .op_name = "OP_OPEN",
1241 }, 1283 },
1242 [OP_OPEN_CONFIRM] = { 1284 [OP_OPEN_CONFIRM] = {
@@ -1249,17 +1291,20 @@ static struct nfsd4_operation nfsd4_ops[] = {
1249 }, 1291 },
1250 [OP_PUTFH] = { 1292 [OP_PUTFH] = {
1251 .op_func = (nfsd4op_func)nfsd4_putfh, 1293 .op_func = (nfsd4op_func)nfsd4_putfh,
1252 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, 1294 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
1295 | OP_IS_PUTFH_LIKE,
1253 .op_name = "OP_PUTFH", 1296 .op_name = "OP_PUTFH",
1254 }, 1297 },
1255 [OP_PUTPUBFH] = { 1298 [OP_PUTPUBFH] = {
1256 .op_func = (nfsd4op_func)nfsd4_putrootfh, 1299 .op_func = (nfsd4op_func)nfsd4_putrootfh,
1257 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, 1300 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
1301 | OP_IS_PUTFH_LIKE,
1258 .op_name = "OP_PUTPUBFH", 1302 .op_name = "OP_PUTPUBFH",
1259 }, 1303 },
1260 [OP_PUTROOTFH] = { 1304 [OP_PUTROOTFH] = {
1261 .op_func = (nfsd4op_func)nfsd4_putrootfh, 1305 .op_func = (nfsd4op_func)nfsd4_putrootfh,
1262 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, 1306 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
1307 | OP_IS_PUTFH_LIKE,
1263 .op_name = "OP_PUTROOTFH", 1308 .op_name = "OP_PUTROOTFH",
1264 }, 1309 },
1265 [OP_READ] = { 1310 [OP_READ] = {
@@ -1289,15 +1334,18 @@ static struct nfsd4_operation nfsd4_ops[] = {
1289 }, 1334 },
1290 [OP_RESTOREFH] = { 1335 [OP_RESTOREFH] = {
1291 .op_func = (nfsd4op_func)nfsd4_restorefh, 1336 .op_func = (nfsd4op_func)nfsd4_restorefh,
1292 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, 1337 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
1338 | OP_IS_PUTFH_LIKE,
1293 .op_name = "OP_RESTOREFH", 1339 .op_name = "OP_RESTOREFH",
1294 }, 1340 },
1295 [OP_SAVEFH] = { 1341 [OP_SAVEFH] = {
1296 .op_func = (nfsd4op_func)nfsd4_savefh, 1342 .op_func = (nfsd4op_func)nfsd4_savefh,
1343 .op_flags = OP_HANDLES_WRONGSEC,
1297 .op_name = "OP_SAVEFH", 1344 .op_name = "OP_SAVEFH",
1298 }, 1345 },
1299 [OP_SECINFO] = { 1346 [OP_SECINFO] = {
1300 .op_func = (nfsd4op_func)nfsd4_secinfo, 1347 .op_func = (nfsd4op_func)nfsd4_secinfo,
1348 .op_flags = OP_HANDLES_WRONGSEC,
1301 .op_name = "OP_SECINFO", 1349 .op_name = "OP_SECINFO",
1302 }, 1350 },
1303 [OP_SETATTR] = { 1351 [OP_SETATTR] = {
@@ -1361,6 +1409,7 @@ static struct nfsd4_operation nfsd4_ops[] = {
1361 }, 1409 },
1362 [OP_SECINFO_NO_NAME] = { 1410 [OP_SECINFO_NO_NAME] = {
1363 .op_func = (nfsd4op_func)nfsd4_secinfo_no_name, 1411 .op_func = (nfsd4op_func)nfsd4_secinfo_no_name,
1412 .op_flags = OP_HANDLES_WRONGSEC,
1364 .op_name = "OP_SECINFO_NO_NAME", 1413 .op_name = "OP_SECINFO_NO_NAME",
1365 }, 1414 },
1366}; 1415};