diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-08-24 01:03:05 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-09-22 23:24:54 -0400 |
commit | 5dd3177ae5012c1e2ad7a9ffdbd0e0d0de2f60e4 (patch) | |
tree | 2a8730d6443f6d33e8879cfc323396f9a570b97b | |
parent | 275a082fe9308e710324e26ccb5363c53d8fd45f (diff) |
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.c | 36 | ||||
-rw-r--r-- | fs/nfs/nfs4renewd.c | 1 | ||||
-rw-r--r-- | fs/nfs/super.c | 8 | ||||
-rw-r--r-- | include/linux/nfs_fs_sb.h | 1 |
4 files changed, 28 insertions, 18 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 12941a8a6d75..f1ff2aec2ca5 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -164,6 +164,26 @@ error_0: | |||
164 | return NULL; | 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 | * Destroy a shared client record | 188 | * Destroy a shared client record |
169 | */ | 189 | */ |
@@ -171,21 +191,7 @@ static void nfs_free_client(struct nfs_client *clp) | |||
171 | { | 191 | { |
172 | dprintk("--> nfs_free_client(%d)\n", clp->cl_nfsversion); | 192 | dprintk("--> nfs_free_client(%d)\n", clp->cl_nfsversion); |
173 | 193 | ||
174 | #ifdef CONFIG_NFS_V4 | 194 | nfs4_shutdown_client(clp); |
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 | ||
189 | 195 | ||
190 | /* -EIO all pending I/O */ | 196 | /* -EIO all pending I/O */ |
191 | if (!IS_ERR(clp->cl_rpcclient)) | 197 | if (!IS_ERR(clp->cl_rpcclient)) |
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c index f2c893690ac4..7b6df1852e75 100644 --- a/fs/nfs/nfs4renewd.c +++ b/fs/nfs/nfs4renewd.c | |||
@@ -121,6 +121,7 @@ nfs4_schedule_state_renewal(struct nfs_client *clp) | |||
121 | __FUNCTION__, (timeout + HZ - 1) / HZ); | 121 | __FUNCTION__, (timeout + HZ - 1) / HZ); |
122 | cancel_delayed_work(&clp->cl_renewd); | 122 | cancel_delayed_work(&clp->cl_renewd); |
123 | schedule_delayed_work(&clp->cl_renewd, timeout); | 123 | schedule_delayed_work(&clp->cl_renewd, timeout); |
124 | set_bit(NFS_CS_RENEWD, &clp->cl_res_state); | ||
124 | spin_unlock(&clp->cl_lock); | 125 | spin_unlock(&clp->cl_lock); |
125 | } | 126 | } |
126 | 127 | ||
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 97cfb143e09f..665949d27798 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, | |||
883 | goto out_free; | 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 | if (!s->s_root) { | 891 | if (!s->s_root) { |
887 | /* initial superblock/root creation */ | 892 | /* initial superblock/root creation */ |
888 | s->s_flags = flags; | 893 | s->s_flags = flags; |
889 | |||
890 | nfs4_fill_super(s); | 894 | nfs4_fill_super(s); |
891 | } else { | ||
892 | nfs_free_server(server); | ||
893 | } | 895 | } |
894 | 896 | ||
895 | mntroot = nfs4_get_root(s, &mntfh); | 897 | mntroot = nfs4_get_root(s, &mntfh); |
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 6d0be0efd1b5..7ccfc7ef0a83 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h | |||
@@ -19,6 +19,7 @@ struct nfs_client { | |||
19 | #define NFS_CS_RPCIOD 0 /* - rpciod started */ | 19 | #define NFS_CS_RPCIOD 0 /* - rpciod started */ |
20 | #define NFS_CS_CALLBACK 1 /* - callback started */ | 20 | #define NFS_CS_CALLBACK 1 /* - callback started */ |
21 | #define NFS_CS_IDMAP 2 /* - idmap started */ | 21 | #define NFS_CS_IDMAP 2 /* - idmap started */ |
22 | #define NFS_CS_RENEWD 3 /* - renewd started */ | ||
22 | struct sockaddr_in cl_addr; /* server identifier */ | 23 | struct sockaddr_in cl_addr; /* server identifier */ |
23 | char * cl_hostname; /* hostname of server */ | 24 | char * cl_hostname; /* hostname of server */ |
24 | struct list_head cl_share_link; /* link in global client list */ | 25 | struct list_head cl_share_link; /* link in global client list */ |