]> err.no Git - linux-2.6/commitdiff
NFSv4: Fix a use-after-free issue with the nfs server.
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Thu, 24 Aug 2006 05:03:05 +0000 (01:03 -0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Sat, 23 Sep 2006 03:24:54 +0000 (23:24 -0400)
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
fs/nfs/client.c
fs/nfs/nfs4renewd.c
fs/nfs/super.c
include/linux/nfs_fs_sb.h

index 12941a8a6d75245134fff12fa8e33acd7ce0dd13..f1ff2aec2ca53678b425266cc9e56b3afb52638c 100644 (file)
@@ -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))
index f2c893690ac49a861d38851c92dc03c611adcb9c..7b6df1852e7590043540cf9c65d3dca963826b20 100644 (file)
@@ -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);
 }
 
index 97cfb143e09fe507aa01039b30d0b53653ef2e5d..665949d277981eac7d5df2394717b6e0a2fa4e9e 100644 (file)
@@ -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);
index 6d0be0efd1b5221ea5ae1499f74d832c1b15add0..7ccfc7ef0a83afd2a58193ddcaa103f442e051cb 100644 (file)
@@ -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 */