diff options
author | J. Bruce Fields <bfields@redhat.com> | 2011-04-08 17:00:50 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2011-04-29 20:47:51 -0400 |
commit | 68d93184352f2e723f135b0a9bad93b58f9d120b (patch) | |
tree | edf66ceadd6ce4559a53355b83265dc65a7d7694 /fs/nfsd | |
parent | 29a78a3ed7fc9c4ee49962751eb321b038c190a2 (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')
-rw-r--r-- | fs/nfsd/export.c | 6 | ||||
-rw-r--r-- | fs/nfsd/nfs4proc.c | 59 |
2 files changed, 54 insertions, 11 deletions
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index ad000aeb21a2..b9566e46219f 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c | |||
@@ -1354,12 +1354,6 @@ exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp) | |||
1354 | if (IS_ERR(exp)) | 1354 | if (IS_ERR(exp)) |
1355 | return nfserrno(PTR_ERR(exp)); | 1355 | return nfserrno(PTR_ERR(exp)); |
1356 | rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL); | 1356 | rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL); |
1357 | if (rv) | ||
1358 | goto out; | ||
1359 | rv = check_nfsd_access(exp, rqstp); | ||
1360 | if (rv) | ||
1361 | fh_put(fhp); | ||
1362 | out: | ||
1363 | exp_put(exp); | 1357 | exp_put(exp); |
1364 | return rv; | 1358 | return rv; |
1365 | } | 1359 | } |
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 | ||
409 | static __be32 | 409 | static __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 | ||
994 | struct nfsd4_operation { | 997 | struct 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 | ||
1045 | static 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 | |||
1137 | encode_op: | 1176 | encode_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 | }; |