Commit 5dd3177ae5012c1e2ad7a9ffdbd0e0d0de2f60e4

Authored by Trond Myklebust
1 parent 275a082fe9

NFSv4: Fix a use-after-free issue with the nfs server.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

Showing 4 changed files with 28 additions and 18 deletions Side-by-side Diff

... ... @@ -164,6 +164,26 @@
164 164 return NULL;
165 165 }
166 166  
  167 +static void nfs4_shutdown_client(struct nfs_client *clp)
  168 +{
  169 +#ifdef CONFIG_NFS_V4
  170 + if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state))
  171 + nfs4_kill_renewd(clp);
  172 + while (!list_empty(&clp->cl_unused)) {
  173 + struct nfs4_state_owner *sp;
  174 +
  175 + sp = list_entry(clp->cl_unused.next,
  176 + struct nfs4_state_owner,
  177 + so_list);
  178 + list_del(&sp->so_list);
  179 + kfree(sp);
  180 + }
  181 + BUG_ON(!list_empty(&clp->cl_state_owners));
  182 + if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state))
  183 + nfs_idmap_delete(clp);
  184 +#endif
  185 +}
  186 +
167 187 /*
168 188 * Destroy a shared client record
169 189 */
... ... @@ -171,21 +191,7 @@
171 191 {
172 192 dprintk("--> nfs_free_client(%d)\n", clp->cl_nfsversion);
173 193  
174   -#ifdef CONFIG_NFS_V4
175   - if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state)) {
176   - while (!list_empty(&clp->cl_unused)) {
177   - struct nfs4_state_owner *sp;
178   -
179   - sp = list_entry(clp->cl_unused.next,
180   - struct nfs4_state_owner,
181   - so_list);
182   - list_del(&sp->so_list);
183   - kfree(sp);
184   - }
185   - BUG_ON(!list_empty(&clp->cl_state_owners));
186   - nfs_idmap_delete(clp);
187   - }
188   -#endif
  194 + nfs4_shutdown_client(clp);
189 195  
190 196 /* -EIO all pending I/O */
191 197 if (!IS_ERR(clp->cl_rpcclient))
... ... @@ -121,6 +121,7 @@
121 121 __FUNCTION__, (timeout + HZ - 1) / HZ);
122 122 cancel_delayed_work(&clp->cl_renewd);
123 123 schedule_delayed_work(&clp->cl_renewd, timeout);
  124 + set_bit(NFS_CS_RENEWD, &clp->cl_res_state);
124 125 spin_unlock(&clp->cl_lock);
125 126 }
126 127  
... ... @@ -883,13 +883,15 @@
883 883 goto out_free;
884 884 }
885 885  
  886 + if (s->s_fs_info != server) {
  887 + nfs_free_server(server);
  888 + server = NULL;
  889 + }
  890 +
886 891 if (!s->s_root) {
887 892 /* initial superblock/root creation */
888 893 s->s_flags = flags;
889   -
890 894 nfs4_fill_super(s);
891   - } else {
892   - nfs_free_server(server);
893 895 }
894 896  
895 897 mntroot = nfs4_get_root(s, &mntfh);
include/linux/nfs_fs_sb.h
... ... @@ -19,6 +19,7 @@
19 19 #define NFS_CS_RPCIOD 0 /* - rpciod started */
20 20 #define NFS_CS_CALLBACK 1 /* - callback started */
21 21 #define NFS_CS_IDMAP 2 /* - idmap started */
  22 +#define NFS_CS_RENEWD 3 /* - renewd started */
22 23 struct sockaddr_in cl_addr; /* server identifier */
23 24 char * cl_hostname; /* hostname of server */
24 25 struct list_head cl_share_link; /* link in global client list */