aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2013-08-21 13:24:47 -0400
committerEric Van Hensbergen <ericvh@gmail.com>2013-08-26 11:28:46 -0400
commit50192abe02929586111fb33f216060a9341875f1 (patch)
treec766629c78fc8410eb452e018b0ba4b629141a3e
parente0d6cb9cd3a3ac8a3b8e5b22b83c4f8619786f22 (diff)
fs/9p: avoid accessing utsname after namespace has been torn down
During trinity fuzzing in a kvmtool guest, I stumbled across the following: Unable to handle kernel NULL pointer dereference at virtual address 00000004 PC is at v9fs_file_do_lock+0xc8/0x1a0 LR is at v9fs_file_do_lock+0x48/0x1a0 [<c01e2ed0>] (v9fs_file_do_lock+0xc8/0x1a0) from [<c0119154>] (locks_remove_flock+0x8c/0x124) [<c0119154>] (locks_remove_flock+0x8c/0x124) from [<c00d9bf0>] (__fput+0x58/0x1e4) [<c00d9bf0>] (__fput+0x58/0x1e4) from [<c0044340>] (task_work_run+0xac/0xe8) [<c0044340>] (task_work_run+0xac/0xe8) from [<c002e36c>] (do_exit+0x6bc/0x8d8) [<c002e36c>] (do_exit+0x6bc/0x8d8) from [<c002e674>] (do_group_exit+0x3c/0xb0) [<c002e674>] (do_group_exit+0x3c/0xb0) from [<c002e6f8>] (__wake_up_parent+0x0/0x18) I believe this is due to an attempt to access utsname()->nodename, after exit_task_namespaces() has been called, leaving current->nsproxy->uts_ns as NULL and causing the above dereference. A similar issue was fixed for lockd in 9a1b6bf818e7 ("LOCKD: Don't call utsname()->nodename from nlmclnt_setlockargs"), so this patch attempts something similar for 9pfs. Cc: Eric Van Hensbergen <ericvh@gmail.com> Cc: Ron Minnich <rminnich@sandia.gov> Cc: Latchesar Ionkov <lucho@ionkov.net> Cc: Trond Myklebust <Trond.Myklebust@netapp.com> Signed-off-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
-rw-r--r--fs/9p/vfs_file.c4
-rw-r--r--include/net/9p/client.h5
-rw-r--r--net/9p/client.c5
3 files changed, 12 insertions, 2 deletions
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index d384a8b77ee8..aa5ecf479a57 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -183,7 +183,7 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
183 else 183 else
184 flock.length = fl->fl_end - fl->fl_start + 1; 184 flock.length = fl->fl_end - fl->fl_start + 1;
185 flock.proc_id = fl->fl_pid; 185 flock.proc_id = fl->fl_pid;
186 flock.client_id = utsname()->nodename; 186 flock.client_id = fid->clnt->name;
187 if (IS_SETLKW(cmd)) 187 if (IS_SETLKW(cmd))
188 flock.flags = P9_LOCK_FLAGS_BLOCK; 188 flock.flags = P9_LOCK_FLAGS_BLOCK;
189 189
@@ -260,7 +260,7 @@ static int v9fs_file_getlock(struct file *filp, struct file_lock *fl)
260 else 260 else
261 glock.length = fl->fl_end - fl->fl_start + 1; 261 glock.length = fl->fl_end - fl->fl_start + 1;
262 glock.proc_id = fl->fl_pid; 262 glock.proc_id = fl->fl_pid;
263 glock.client_id = utsname()->nodename; 263 glock.client_id = fid->clnt->name;
264 264
265 res = p9_client_getlock_dotl(fid, &glock); 265 res = p9_client_getlock_dotl(fid, &glock);
266 if (res < 0) 266 if (res < 0)
diff --git a/include/net/9p/client.h b/include/net/9p/client.h
index 4c7c01a73911..c38a005bd0cf 100644
--- a/include/net/9p/client.h
+++ b/include/net/9p/client.h
@@ -26,6 +26,8 @@
26#ifndef NET_9P_CLIENT_H 26#ifndef NET_9P_CLIENT_H
27#define NET_9P_CLIENT_H 27#define NET_9P_CLIENT_H
28 28
29#include <linux/utsname.h>
30
29/* Number of requests per row */ 31/* Number of requests per row */
30#define P9_ROW_MAXTAG 255 32#define P9_ROW_MAXTAG 255
31 33
@@ -134,6 +136,7 @@ struct p9_req_t {
134 * @tagpool - transaction id accounting for session 136 * @tagpool - transaction id accounting for session
135 * @reqs - 2D array of requests 137 * @reqs - 2D array of requests
136 * @max_tag - current maximum tag id allocated 138 * @max_tag - current maximum tag id allocated
139 * @name - node name used as client id
137 * 140 *
138 * The client structure is used to keep track of various per-client 141 * The client structure is used to keep track of various per-client
139 * state that has been instantiated. 142 * state that has been instantiated.
@@ -164,6 +167,8 @@ struct p9_client {
164 struct p9_idpool *tagpool; 167 struct p9_idpool *tagpool;
165 struct p9_req_t *reqs[P9_ROW_MAXTAG]; 168 struct p9_req_t *reqs[P9_ROW_MAXTAG];
166 int max_tag; 169 int max_tag;
170
171 char name[__NEW_UTS_LEN + 1];
167}; 172};
168 173
169/** 174/**
diff --git a/net/9p/client.c b/net/9p/client.c
index 8b93cae2d11d..0e49b288e574 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -992,6 +992,7 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
992{ 992{
993 int err; 993 int err;
994 struct p9_client *clnt; 994 struct p9_client *clnt;
995 char *client_id;
995 996
996 err = 0; 997 err = 0;
997 clnt = kmalloc(sizeof(struct p9_client), GFP_KERNEL); 998 clnt = kmalloc(sizeof(struct p9_client), GFP_KERNEL);
@@ -1000,6 +1001,10 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
1000 1001
1001 clnt->trans_mod = NULL; 1002 clnt->trans_mod = NULL;
1002 clnt->trans = NULL; 1003 clnt->trans = NULL;
1004
1005 client_id = utsname()->nodename;
1006 memcpy(clnt->name, client_id, strlen(client_id) + 1);
1007
1003 spin_lock_init(&clnt->lock); 1008 spin_lock_init(&clnt->lock);
1004 INIT_LIST_HEAD(&clnt->fidlist); 1009 INIT_LIST_HEAD(&clnt->fidlist);
1005 1010