summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2006-08-24 01:03:05 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2006-09-22 23:24:54 -0400
commit5dd3177ae5012c1e2ad7a9ffdbd0e0d0de2f60e4 (patch)
tree2a8730d6443f6d33e8879cfc323396f9a570b97b
parent275a082fe9308e710324e26ccb5363c53d8fd45f (diff)
downloadlinux-3.10-5dd3177ae5012c1e2ad7a9ffdbd0e0d0de2f60e4.tar.gz
linux-3.10-5dd3177ae5012c1e2ad7a9ffdbd0e0d0de2f60e4.tar.bz2
linux-3.10-5dd3177ae5012c1e2ad7a9ffdbd0e0d0de2f60e4.zip
NFSv4: Fix a use-after-free issue with the nfs server.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--fs/nfs/client.c36
-rw-r--r--fs/nfs/nfs4renewd.c1
-rw-r--r--fs/nfs/super.c8
-rw-r--r--include/linux/nfs_fs_sb.h1
4 files changed, 28 insertions, 18 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 12941a8a6d7..f1ff2aec2ca 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -164,6 +164,26 @@ error_0:
return NULL;
}
+static void nfs4_shutdown_client(struct nfs_client *clp)
+{
+#ifdef CONFIG_NFS_V4
+ if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state))
+ nfs4_kill_renewd(clp);
+ while (!list_empty(&clp->cl_unused)) {
+ struct nfs4_state_owner *sp;
+
+ sp = list_entry(clp->cl_unused.next,
+ struct nfs4_state_owner,
+ so_list);
+ list_del(&sp->so_list);
+ kfree(sp);
+ }
+ BUG_ON(!list_empty(&clp->cl_state_owners));
+ if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state))
+ nfs_idmap_delete(clp);
+#endif
+}
+
/*
* Destroy a shared client record
*/
@@ -171,21 +191,7 @@ static void nfs_free_client(struct nfs_client *clp)
{
dprintk("--> nfs_free_client(%d)\n", clp->cl_nfsversion);
-#ifdef CONFIG_NFS_V4
- if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state)) {
- while (!list_empty(&clp->cl_unused)) {
- struct nfs4_state_owner *sp;
-
- sp = list_entry(clp->cl_unused.next,
- struct nfs4_state_owner,
- so_list);
- list_del(&sp->so_list);
- kfree(sp);
- }
- BUG_ON(!list_empty(&clp->cl_state_owners));
- nfs_idmap_delete(clp);
- }
-#endif
+ nfs4_shutdown_client(clp);
/* -EIO all pending I/O */
if (!IS_ERR(clp->cl_rpcclient))
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c
index f2c893690ac..7b6df1852e7 100644
--- a/fs/nfs/nfs4renewd.c
+++ b/fs/nfs/nfs4renewd.c
@@ -121,6 +121,7 @@ nfs4_schedule_state_renewal(struct nfs_client *clp)
__FUNCTION__, (timeout + HZ - 1) / HZ);
cancel_delayed_work(&clp->cl_renewd);
schedule_delayed_work(&clp->cl_renewd, timeout);
+ set_bit(NFS_CS_RENEWD, &clp->cl_res_state);
spin_unlock(&clp->cl_lock);
}
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 97cfb143e09..665949d2779 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -883,13 +883,15 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
goto out_free;
}
+ if (s->s_fs_info != server) {
+ nfs_free_server(server);
+ server = NULL;
+ }
+
if (!s->s_root) {
/* initial superblock/root creation */
s->s_flags = flags;
-
nfs4_fill_super(s);
- } else {
- nfs_free_server(server);
}
mntroot = nfs4_get_root(s, &mntfh);
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 6d0be0efd1b..7ccfc7ef0a8 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -19,6 +19,7 @@ struct nfs_client {
#define NFS_CS_RPCIOD 0 /* - rpciod started */
#define NFS_CS_CALLBACK 1 /* - callback started */
#define NFS_CS_IDMAP 2 /* - idmap started */
+#define NFS_CS_RENEWD 3 /* - renewd started */
struct sockaddr_in cl_addr; /* server identifier */
char * cl_hostname; /* hostname of server */
struct list_head cl_share_link; /* link in global client list */