aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Adamson <andros@netapp.com>2012-11-27 10:34:19 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-12-12 15:36:02 -0500
commiteb96d5c97b0825d542e9c4ba5e0a22b519355166 (patch)
tree62c98e2bdbcc7334a7043725d1fd81a589a75177
parent620038f6d2304475dce800dc5c75fc335a19613a (diff)
SUNRPC handle EKEYEXPIRED in call_refreshresult
Currently, when an RPCSEC_GSS context has expired or is non-existent and the users (Kerberos) credentials have also expired or are non-existent, the client receives the -EKEYEXPIRED error and tries to refresh the context forever. If an application is performing I/O, or other work against the share, the application hangs, and the user is not prompted to refresh/establish their credentials. This can result in a denial of service for other users. Users are expected to manage their Kerberos credential lifetimes to mitigate this issue. Move the -EKEYEXPIRED handling into the RPC layer. Try tk_cred_retry number of times to refresh the gss_context, and then return -EACCES to the application. Signed-off-by: Andy Adamson <andros@netapp.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--fs/nfs/nfs3proc.c6
-rw-r--r--fs/nfs/nfs4filelayout.c1
-rw-r--r--fs/nfs/nfs4proc.c18
-rw-r--r--fs/nfs/nfs4state.c23
-rw-r--r--fs/nfs/proc.c43
-rw-r--r--net/sunrpc/clnt.c1
6 files changed, 4 insertions, 88 deletions
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 69322096c325..70efb63b1e42 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -24,14 +24,14 @@
24 24
25#define NFSDBG_FACILITY NFSDBG_PROC 25#define NFSDBG_FACILITY NFSDBG_PROC
26 26
27/* A wrapper to handle the EJUKEBOX and EKEYEXPIRED error messages */ 27/* A wrapper to handle the EJUKEBOX error messages */
28static int 28static int
29nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) 29nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
30{ 30{
31 int res; 31 int res;
32 do { 32 do {
33 res = rpc_call_sync(clnt, msg, flags); 33 res = rpc_call_sync(clnt, msg, flags);
34 if (res != -EJUKEBOX && res != -EKEYEXPIRED) 34 if (res != -EJUKEBOX)
35 break; 35 break;
36 freezable_schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME); 36 freezable_schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME);
37 res = -ERESTARTSYS; 37 res = -ERESTARTSYS;
@@ -44,7 +44,7 @@ nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
44static int 44static int
45nfs3_async_handle_jukebox(struct rpc_task *task, struct inode *inode) 45nfs3_async_handle_jukebox(struct rpc_task *task, struct inode *inode)
46{ 46{
47 if (task->tk_status != -EJUKEBOX && task->tk_status != -EKEYEXPIRED) 47 if (task->tk_status != -EJUKEBOX)
48 return 0; 48 return 0;
49 if (task->tk_status == -EJUKEBOX) 49 if (task->tk_status == -EJUKEBOX)
50 nfs_inc_stats(inode, NFSIOS_DELAY); 50 nfs_inc_stats(inode, NFSIOS_DELAY);
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c
index 1e42413fab8f..194c48410336 100644
--- a/fs/nfs/nfs4filelayout.c
+++ b/fs/nfs/nfs4filelayout.c
@@ -179,7 +179,6 @@ static int filelayout_async_handle_error(struct rpc_task *task,
179 break; 179 break;
180 case -NFS4ERR_DELAY: 180 case -NFS4ERR_DELAY:
181 case -NFS4ERR_GRACE: 181 case -NFS4ERR_GRACE:
182 case -EKEYEXPIRED:
183 rpc_delay(task, FILELAYOUT_POLL_RETRY_MAX); 182 rpc_delay(task, FILELAYOUT_POLL_RETRY_MAX);
184 break; 183 break;
185 case -NFS4ERR_RETRY_UNCACHED_REP: 184 case -NFS4ERR_RETRY_UNCACHED_REP:
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index a4692e97bc19..b0963aeceeda 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -333,7 +333,6 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc
333 } 333 }
334 case -NFS4ERR_GRACE: 334 case -NFS4ERR_GRACE:
335 case -NFS4ERR_DELAY: 335 case -NFS4ERR_DELAY:
336 case -EKEYEXPIRED:
337 ret = nfs4_delay(server->client, &exception->timeout); 336 ret = nfs4_delay(server->client, &exception->timeout);
338 if (ret != 0) 337 if (ret != 0)
339 break; 338 break;
@@ -1343,13 +1342,6 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state
1343 nfs_inode_find_state_and_recover(state->inode, 1342 nfs_inode_find_state_and_recover(state->inode,
1344 stateid); 1343 stateid);
1345 nfs4_schedule_stateid_recovery(server, state); 1344 nfs4_schedule_stateid_recovery(server, state);
1346 case -EKEYEXPIRED:
1347 /*
1348 * User RPCSEC_GSS context has expired.
1349 * We cannot recover this stateid now, so
1350 * skip it and allow recovery thread to
1351 * proceed.
1352 */
1353 case -ENOMEM: 1345 case -ENOMEM:
1354 err = 0; 1346 err = 0;
1355 goto out; 1347 goto out;
@@ -3946,7 +3938,6 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
3946 case -NFS4ERR_DELAY: 3938 case -NFS4ERR_DELAY:
3947 nfs_inc_server_stats(server, NFSIOS_DELAY); 3939 nfs_inc_server_stats(server, NFSIOS_DELAY);
3948 case -NFS4ERR_GRACE: 3940 case -NFS4ERR_GRACE:
3949 case -EKEYEXPIRED:
3950 rpc_delay(task, NFS4_POLL_RETRY_MAX); 3941 rpc_delay(task, NFS4_POLL_RETRY_MAX);
3951 task->tk_status = 0; 3942 task->tk_status = 0;
3952 return -EAGAIN; 3943 return -EAGAIN;
@@ -4946,15 +4937,6 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl)
4946 nfs4_schedule_stateid_recovery(server, state); 4937 nfs4_schedule_stateid_recovery(server, state);
4947 err = 0; 4938 err = 0;
4948 goto out; 4939 goto out;
4949 case -EKEYEXPIRED:
4950 /*
4951 * User RPCSEC_GSS context has expired.
4952 * We cannot recover this stateid now, so
4953 * skip it and allow recovery thread to
4954 * proceed.
4955 */
4956 err = 0;
4957 goto out;
4958 case -ENOMEM: 4940 case -ENOMEM:
4959 case -NFS4ERR_DENIED: 4941 case -NFS4ERR_DENIED:
4960 /* kill_proc(fl->fl_pid, SIGLOST, 1); */ 4942 /* kill_proc(fl->fl_pid, SIGLOST, 1); */
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 78e90a80fc3a..8dcbd9a0367d 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -1437,14 +1437,6 @@ restart:
1437 /* Mark the file as being 'closed' */ 1437 /* Mark the file as being 'closed' */
1438 state->state = 0; 1438 state->state = 0;
1439 break; 1439 break;
1440 case -EKEYEXPIRED:
1441 /*
1442 * User RPCSEC_GSS context has expired.
1443 * We cannot recover this stateid now, so
1444 * skip it and allow recovery thread to
1445 * proceed.
1446 */
1447 break;
1448 case -NFS4ERR_ADMIN_REVOKED: 1440 case -NFS4ERR_ADMIN_REVOKED:
1449 case -NFS4ERR_STALE_STATEID: 1441 case -NFS4ERR_STALE_STATEID:
1450 case -NFS4ERR_BAD_STATEID: 1442 case -NFS4ERR_BAD_STATEID:
@@ -1597,14 +1589,6 @@ static void nfs4_state_start_reclaim_nograce(struct nfs_client *clp)
1597 nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_nograce); 1589 nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_nograce);
1598} 1590}
1599 1591
1600static void nfs4_warn_keyexpired(const char *s)
1601{
1602 printk_ratelimited(KERN_WARNING "Error: state manager"
1603 " encountered RPCSEC_GSS session"
1604 " expired against NFSv4 server %s.\n",
1605 s);
1606}
1607
1608static int nfs4_recovery_handle_error(struct nfs_client *clp, int error) 1592static int nfs4_recovery_handle_error(struct nfs_client *clp, int error)
1609{ 1593{
1610 switch (error) { 1594 switch (error) {
@@ -1638,10 +1622,6 @@ static int nfs4_recovery_handle_error(struct nfs_client *clp, int error)
1638 case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: 1622 case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
1639 set_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state); 1623 set_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state);
1640 break; 1624 break;
1641 case -EKEYEXPIRED:
1642 /* Nothing we can do */
1643 nfs4_warn_keyexpired(clp->cl_hostname);
1644 break;
1645 default: 1625 default:
1646 dprintk("%s: failed to handle error %d for server %s\n", 1626 dprintk("%s: failed to handle error %d for server %s\n",
1647 __func__, error, clp->cl_hostname); 1627 __func__, error, clp->cl_hostname);
@@ -1758,8 +1738,6 @@ static int nfs4_handle_reclaim_lease_error(struct nfs_client *clp, int status)
1758 dprintk("%s: exit with error %d for server %s\n", 1738 dprintk("%s: exit with error %d for server %s\n",
1759 __func__, -EPROTONOSUPPORT, clp->cl_hostname); 1739 __func__, -EPROTONOSUPPORT, clp->cl_hostname);
1760 return -EPROTONOSUPPORT; 1740 return -EPROTONOSUPPORT;
1761 case -EKEYEXPIRED:
1762 nfs4_warn_keyexpired(clp->cl_hostname);
1763 case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery 1741 case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
1764 * in nfs4_exchange_id */ 1742 * in nfs4_exchange_id */
1765 default: 1743 default:
@@ -1912,7 +1890,6 @@ again:
1912 break; 1890 break;
1913 1891
1914 case -EKEYEXPIRED: 1892 case -EKEYEXPIRED:
1915 nfs4_warn_keyexpired(clp->cl_hostname);
1916 case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery 1893 case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
1917 * in nfs4_exchange_id */ 1894 * in nfs4_exchange_id */
1918 status = -EKEYEXPIRED; 1895 status = -EKEYEXPIRED;
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 50a88c3546ed..f084dac948e1 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -47,39 +47,6 @@
47#define NFSDBG_FACILITY NFSDBG_PROC 47#define NFSDBG_FACILITY NFSDBG_PROC
48 48
49/* 49/*
50 * wrapper to handle the -EKEYEXPIRED error message. This should generally
51 * only happen if using krb5 auth and a user's TGT expires. NFSv2 doesn't
52 * support the NFSERR_JUKEBOX error code, but we handle this situation in the
53 * same way that we handle that error with NFSv3.
54 */
55static int
56nfs_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
57{
58 int res;
59 do {
60 res = rpc_call_sync(clnt, msg, flags);
61 if (res != -EKEYEXPIRED)
62 break;
63 freezable_schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME);
64 res = -ERESTARTSYS;
65 } while (!fatal_signal_pending(current));
66 return res;
67}
68
69#define rpc_call_sync(clnt, msg, flags) nfs_rpc_wrapper(clnt, msg, flags)
70
71static int
72nfs_async_handle_expired_key(struct rpc_task *task)
73{
74 if (task->tk_status != -EKEYEXPIRED)
75 return 0;
76 task->tk_status = 0;
77 rpc_restart_call(task);
78 rpc_delay(task, NFS_JUKEBOX_RETRY_TIME);
79 return 1;
80}
81
82/*
83 * Bare-bones access to getattr: this is for nfs_read_super. 50 * Bare-bones access to getattr: this is for nfs_read_super.
84 */ 51 */
85static int 52static int
@@ -364,8 +331,6 @@ static void nfs_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlink
364 331
365static int nfs_proc_unlink_done(struct rpc_task *task, struct inode *dir) 332static int nfs_proc_unlink_done(struct rpc_task *task, struct inode *dir)
366{ 333{
367 if (nfs_async_handle_expired_key(task))
368 return 0;
369 nfs_mark_for_revalidate(dir); 334 nfs_mark_for_revalidate(dir);
370 return 1; 335 return 1;
371} 336}
@@ -385,8 +350,6 @@ static int
385nfs_proc_rename_done(struct rpc_task *task, struct inode *old_dir, 350nfs_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
386 struct inode *new_dir) 351 struct inode *new_dir)
387{ 352{
388 if (nfs_async_handle_expired_key(task))
389 return 0;
390 nfs_mark_for_revalidate(old_dir); 353 nfs_mark_for_revalidate(old_dir);
391 nfs_mark_for_revalidate(new_dir); 354 nfs_mark_for_revalidate(new_dir);
392 return 1; 355 return 1;
@@ -642,9 +605,6 @@ static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data)
642{ 605{
643 struct inode *inode = data->header->inode; 606 struct inode *inode = data->header->inode;
644 607
645 if (nfs_async_handle_expired_key(task))
646 return -EAGAIN;
647
648 nfs_invalidate_atime(inode); 608 nfs_invalidate_atime(inode);
649 if (task->tk_status >= 0) { 609 if (task->tk_status >= 0) {
650 nfs_refresh_inode(inode, data->res.fattr); 610 nfs_refresh_inode(inode, data->res.fattr);
@@ -671,9 +631,6 @@ static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data)
671{ 631{
672 struct inode *inode = data->header->inode; 632 struct inode *inode = data->header->inode;
673 633
674 if (nfs_async_handle_expired_key(task))
675 return -EAGAIN;
676
677 if (task->tk_status >= 0) 634 if (task->tk_status >= 0)
678 nfs_post_op_update_inode_force_wcc(inode, data->res.fattr); 635 nfs_post_op_update_inode_force_wcc(inode, data->res.fattr);
679 return 0; 636 return 0;
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index c69e199b1082..55e174f2d02f 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -1381,6 +1381,7 @@ call_refreshresult(struct rpc_task *task)
1381 return; 1381 return;
1382 case -ETIMEDOUT: 1382 case -ETIMEDOUT:
1383 rpc_delay(task, 3*HZ); 1383 rpc_delay(task, 3*HZ);
1384 case -EKEYEXPIRED:
1384 case -EAGAIN: 1385 case -EAGAIN:
1385 status = -EACCES; 1386 status = -EACCES;
1386 if (!task->tk_cred_retry) 1387 if (!task->tk_cred_retry)