diff options
author | J. Bruce Fields <bfields@redhat.com> | 2012-09-13 16:19:31 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2012-10-01 17:39:58 -0400 |
commit | d15c077e442d3c4167aaac87b3b7fe8ccad67a1f (patch) | |
tree | 3eae78b73c895ebb818307b406f7a18800cbc6a1 /fs | |
parent | c116a0af76424c72d91ebff7646639cb1287bf63 (diff) |
nfsd4: enforce per-client sessions/no-sessions distinction
Something like creating a client with setclientid and then trying to
confirm it with create_session may not crash the server, but I'm not
completely positive of that, and in any case it's obviously bad client
behavior.
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfsd/nfs4proc.c | 2 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 49 | ||||
-rw-r--r-- | fs/nfsd/state.h | 2 |
3 files changed, 31 insertions, 22 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index f2bb0ef67b2a..6c9a4b291dba 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -370,7 +370,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
370 | break; | 370 | break; |
371 | case NFS4_OPEN_CLAIM_PREVIOUS: | 371 | case NFS4_OPEN_CLAIM_PREVIOUS: |
372 | open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; | 372 | open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; |
373 | status = nfs4_check_open_reclaim(&open->op_clientid); | 373 | status = nfs4_check_open_reclaim(&open->op_clientid, cstate->minorversion); |
374 | if (status) | 374 | if (status) |
375 | goto out; | 375 | goto out; |
376 | case NFS4_OPEN_CLAIM_FH: | 376 | case NFS4_OPEN_CLAIM_FH: |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 73029cd0c5b6..550784219030 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -1356,13 +1356,15 @@ move_to_confirmed(struct nfs4_client *clp) | |||
1356 | } | 1356 | } |
1357 | 1357 | ||
1358 | static struct nfs4_client * | 1358 | static struct nfs4_client * |
1359 | find_confirmed_client(clientid_t *clid) | 1359 | find_confirmed_client(clientid_t *clid, bool sessions) |
1360 | { | 1360 | { |
1361 | struct nfs4_client *clp; | 1361 | struct nfs4_client *clp; |
1362 | unsigned int idhashval = clientid_hashval(clid->cl_id); | 1362 | unsigned int idhashval = clientid_hashval(clid->cl_id); |
1363 | 1363 | ||
1364 | list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) { | 1364 | list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) { |
1365 | if (same_clid(&clp->cl_clientid, clid)) { | 1365 | if (same_clid(&clp->cl_clientid, clid)) { |
1366 | if ((bool)clp->cl_minorversion != sessions) | ||
1367 | return NULL; | ||
1366 | renew_client(clp); | 1368 | renew_client(clp); |
1367 | return clp; | 1369 | return clp; |
1368 | } | 1370 | } |
@@ -1371,14 +1373,17 @@ find_confirmed_client(clientid_t *clid) | |||
1371 | } | 1373 | } |
1372 | 1374 | ||
1373 | static struct nfs4_client * | 1375 | static struct nfs4_client * |
1374 | find_unconfirmed_client(clientid_t *clid) | 1376 | find_unconfirmed_client(clientid_t *clid, bool sessions) |
1375 | { | 1377 | { |
1376 | struct nfs4_client *clp; | 1378 | struct nfs4_client *clp; |
1377 | unsigned int idhashval = clientid_hashval(clid->cl_id); | 1379 | unsigned int idhashval = clientid_hashval(clid->cl_id); |
1378 | 1380 | ||
1379 | list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) { | 1381 | list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) { |
1380 | if (same_clid(&clp->cl_clientid, clid)) | 1382 | if (same_clid(&clp->cl_clientid, clid)) { |
1383 | if ((bool)clp->cl_minorversion != sessions) | ||
1384 | return NULL; | ||
1381 | return clp; | 1385 | return clp; |
1386 | } | ||
1382 | } | 1387 | } |
1383 | return NULL; | 1388 | return NULL; |
1384 | } | 1389 | } |
@@ -1768,8 +1773,8 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1768 | return nfserr_inval; | 1773 | return nfserr_inval; |
1769 | 1774 | ||
1770 | nfs4_lock_state(); | 1775 | nfs4_lock_state(); |
1771 | unconf = find_unconfirmed_client(&cr_ses->clientid); | 1776 | unconf = find_unconfirmed_client(&cr_ses->clientid, true); |
1772 | conf = find_confirmed_client(&cr_ses->clientid); | 1777 | conf = find_confirmed_client(&cr_ses->clientid, true); |
1773 | 1778 | ||
1774 | if (conf) { | 1779 | if (conf) { |
1775 | cs_slot = &conf->cl_cs_slot; | 1780 | cs_slot = &conf->cl_cs_slot; |
@@ -2096,8 +2101,8 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta | |||
2096 | __be32 status = 0; | 2101 | __be32 status = 0; |
2097 | 2102 | ||
2098 | nfs4_lock_state(); | 2103 | nfs4_lock_state(); |
2099 | unconf = find_unconfirmed_client(&dc->clientid); | 2104 | unconf = find_unconfirmed_client(&dc->clientid, true); |
2100 | conf = find_confirmed_client(&dc->clientid); | 2105 | conf = find_confirmed_client(&dc->clientid, true); |
2101 | 2106 | ||
2102 | if (conf) { | 2107 | if (conf) { |
2103 | clp = conf; | 2108 | clp = conf; |
@@ -2239,8 +2244,8 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
2239 | return nfserr_stale_clientid; | 2244 | return nfserr_stale_clientid; |
2240 | nfs4_lock_state(); | 2245 | nfs4_lock_state(); |
2241 | 2246 | ||
2242 | conf = find_confirmed_client(clid); | 2247 | conf = find_confirmed_client(clid, false); |
2243 | unconf = find_unconfirmed_client(clid); | 2248 | unconf = find_unconfirmed_client(clid, false); |
2244 | /* | 2249 | /* |
2245 | * We try hard to give out unique clientid's, so if we get an | 2250 | * We try hard to give out unique clientid's, so if we get an |
2246 | * attempt to confirm the same clientid with a different cred, | 2251 | * attempt to confirm the same clientid with a different cred, |
@@ -2454,16 +2459,20 @@ same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner, | |||
2454 | } | 2459 | } |
2455 | 2460 | ||
2456 | static struct nfs4_openowner * | 2461 | static struct nfs4_openowner * |
2457 | find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open) | 2462 | find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, bool sessions) |
2458 | { | 2463 | { |
2459 | struct nfs4_stateowner *so; | 2464 | struct nfs4_stateowner *so; |
2460 | struct nfs4_openowner *oo; | 2465 | struct nfs4_openowner *oo; |
2466 | struct nfs4_client *clp; | ||
2461 | 2467 | ||
2462 | list_for_each_entry(so, &ownerstr_hashtbl[hashval], so_strhash) { | 2468 | list_for_each_entry(so, &ownerstr_hashtbl[hashval], so_strhash) { |
2463 | if (!so->so_is_open_owner) | 2469 | if (!so->so_is_open_owner) |
2464 | continue; | 2470 | continue; |
2465 | if (same_owner_str(so, &open->op_owner, &open->op_clientid)) { | 2471 | if (same_owner_str(so, &open->op_owner, &open->op_clientid)) { |
2466 | oo = openowner(so); | 2472 | oo = openowner(so); |
2473 | clp = oo->oo_owner.so_client; | ||
2474 | if ((bool)clp->cl_minorversion != sessions) | ||
2475 | return NULL; | ||
2467 | renew_client(oo->oo_owner.so_client); | 2476 | renew_client(oo->oo_owner.so_client); |
2468 | return oo; | 2477 | return oo; |
2469 | } | 2478 | } |
@@ -2607,10 +2616,10 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate, | |||
2607 | return nfserr_jukebox; | 2616 | return nfserr_jukebox; |
2608 | 2617 | ||
2609 | strhashval = ownerstr_hashval(clientid->cl_id, &open->op_owner); | 2618 | strhashval = ownerstr_hashval(clientid->cl_id, &open->op_owner); |
2610 | oo = find_openstateowner_str(strhashval, open); | 2619 | oo = find_openstateowner_str(strhashval, open, cstate->minorversion); |
2611 | open->op_openowner = oo; | 2620 | open->op_openowner = oo; |
2612 | if (!oo) { | 2621 | if (!oo) { |
2613 | clp = find_confirmed_client(clientid); | 2622 | clp = find_confirmed_client(clientid, cstate->minorversion); |
2614 | if (clp == NULL) | 2623 | if (clp == NULL) |
2615 | return nfserr_expired; | 2624 | return nfserr_expired; |
2616 | goto new_owner; | 2625 | goto new_owner; |
@@ -3107,7 +3116,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3107 | status = nfserr_stale_clientid; | 3116 | status = nfserr_stale_clientid; |
3108 | if (STALE_CLIENTID(clid, nn)) | 3117 | if (STALE_CLIENTID(clid, nn)) |
3109 | goto out; | 3118 | goto out; |
3110 | clp = find_confirmed_client(clid); | 3119 | clp = find_confirmed_client(clid, cstate->minorversion); |
3111 | status = nfserr_expired; | 3120 | status = nfserr_expired; |
3112 | if (clp == NULL) { | 3121 | if (clp == NULL) { |
3113 | /* We assume the client took too long to RENEW. */ | 3122 | /* We assume the client took too long to RENEW. */ |
@@ -3375,7 +3384,7 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) | |||
3375 | return nfs_ok; | 3384 | return nfs_ok; |
3376 | } | 3385 | } |
3377 | 3386 | ||
3378 | static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, struct nfs4_stid **s) | 3387 | static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, struct nfs4_stid **s, bool sessions) |
3379 | { | 3388 | { |
3380 | struct nfs4_client *cl; | 3389 | struct nfs4_client *cl; |
3381 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); | 3390 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); |
@@ -3384,7 +3393,7 @@ static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, s | |||
3384 | return nfserr_bad_stateid; | 3393 | return nfserr_bad_stateid; |
3385 | if (STALE_STATEID(stateid, nn)) | 3394 | if (STALE_STATEID(stateid, nn)) |
3386 | return nfserr_stale_stateid; | 3395 | return nfserr_stale_stateid; |
3387 | cl = find_confirmed_client(&stateid->si_opaque.so_clid); | 3396 | cl = find_confirmed_client(&stateid->si_opaque.so_clid, sessions); |
3388 | if (!cl) | 3397 | if (!cl) |
3389 | return nfserr_expired; | 3398 | return nfserr_expired; |
3390 | *s = find_stateid_by_type(cl, stateid, typemask); | 3399 | *s = find_stateid_by_type(cl, stateid, typemask); |
@@ -3417,7 +3426,7 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, | |||
3417 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) | 3426 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) |
3418 | return check_special_stateids(net, current_fh, stateid, flags); | 3427 | return check_special_stateids(net, current_fh, stateid, flags); |
3419 | 3428 | ||
3420 | status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, &s); | 3429 | status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, &s, cstate->minorversion); |
3421 | if (status) | 3430 | if (status) |
3422 | return status; | 3431 | return status; |
3423 | status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate)); | 3432 | status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate)); |
@@ -3567,7 +3576,7 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, | |||
3567 | seqid, STATEID_VAL(stateid)); | 3576 | seqid, STATEID_VAL(stateid)); |
3568 | 3577 | ||
3569 | *stpp = NULL; | 3578 | *stpp = NULL; |
3570 | status = nfsd4_lookup_stateid(stateid, typemask, &s); | 3579 | status = nfsd4_lookup_stateid(stateid, typemask, &s, cstate->minorversion); |
3571 | if (status) | 3580 | if (status) |
3572 | return status; | 3581 | return status; |
3573 | *stpp = openlockstateid(s); | 3582 | *stpp = openlockstateid(s); |
@@ -3805,7 +3814,7 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3805 | inode = cstate->current_fh.fh_dentry->d_inode; | 3814 | inode = cstate->current_fh.fh_dentry->d_inode; |
3806 | 3815 | ||
3807 | nfs4_lock_state(); | 3816 | nfs4_lock_state(); |
3808 | status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s); | 3817 | status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s, cstate->minorversion); |
3809 | if (status) | 3818 | if (status) |
3810 | goto out; | 3819 | goto out; |
3811 | dp = delegstateid(s); | 3820 | dp = delegstateid(s); |
@@ -4533,12 +4542,12 @@ nfsd4_find_reclaim_client(struct nfs4_client *clp) | |||
4533 | * Called from OPEN. Look for clientid in reclaim list. | 4542 | * Called from OPEN. Look for clientid in reclaim list. |
4534 | */ | 4543 | */ |
4535 | __be32 | 4544 | __be32 |
4536 | nfs4_check_open_reclaim(clientid_t *clid) | 4545 | nfs4_check_open_reclaim(clientid_t *clid, bool sessions) |
4537 | { | 4546 | { |
4538 | struct nfs4_client *clp; | 4547 | struct nfs4_client *clp; |
4539 | 4548 | ||
4540 | /* find clientid in conf_id_hashtbl */ | 4549 | /* find clientid in conf_id_hashtbl */ |
4541 | clp = find_confirmed_client(clid); | 4550 | clp = find_confirmed_client(clid, sessions); |
4542 | if (clp == NULL) | 4551 | if (clp == NULL) |
4543 | return nfserr_reclaim_bad; | 4552 | return nfserr_reclaim_bad; |
4544 | 4553 | ||
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index ec513fd4bae9..e036894bce57 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
@@ -455,7 +455,7 @@ extern void nfs4_unlock_state(void); | |||
455 | extern int nfs4_in_grace(void); | 455 | extern int nfs4_in_grace(void); |
456 | extern void nfs4_release_reclaim(void); | 456 | extern void nfs4_release_reclaim(void); |
457 | extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(struct nfs4_client *crp); | 457 | extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(struct nfs4_client *crp); |
458 | extern __be32 nfs4_check_open_reclaim(clientid_t *clid); | 458 | extern __be32 nfs4_check_open_reclaim(clientid_t *clid, bool sessions); |
459 | extern void nfs4_free_openowner(struct nfs4_openowner *); | 459 | extern void nfs4_free_openowner(struct nfs4_openowner *); |
460 | extern void nfs4_free_lockowner(struct nfs4_lockowner *); | 460 | extern void nfs4_free_lockowner(struct nfs4_lockowner *); |
461 | extern int set_callback_cred(void); | 461 | extern int set_callback_cred(void); |