diff options
author | Will Deacon <will.deacon@arm.com> | 2013-08-21 13:24:47 -0400 |
---|---|---|
committer | Eric Van Hensbergen <ericvh@gmail.com> | 2013-08-26 11:28:46 -0400 |
commit | 50192abe02929586111fb33f216060a9341875f1 (patch) | |
tree | c766629c78fc8410eb452e018b0ba4b629141a3e | |
parent | e0d6cb9cd3a3ac8a3b8e5b22b83c4f8619786f22 (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.c | 4 | ||||
-rw-r--r-- | include/net/9p/client.h | 5 | ||||
-rw-r--r-- | net/9p/client.c | 5 |
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 | ||