]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From c78a87d0a1fc885dfdbe21fd5e07787691dfb068 Mon Sep 17 00:00:00 2001 |
2 | From: David Teigland <teigland@redhat.com> | |
3 | Date: Thu, 18 Jun 2009 13:20:24 -0500 | |
4 | Subject: [PATCH] dlm: fix plock use-after-free | |
5 | ||
6 | Fix a regression from the original addition of nfs lock support | |
7 | 586759f03e2e9031ac5589912a51a909ed53c30a. When a synchronous | |
8 | (non-nfs) plock completes, the waiting thread will wake up and | |
9 | free the op struct. This races with the user thread in | |
10 | dev_write() which goes on to read the op's callback field to | |
11 | check if the lock is async and needs a callback. This check | |
12 | can happen on the freed op. The fix is to note the callback | |
13 | value before the op can be freed. | |
14 | ||
15 | Signed-off-by: David Teigland <teigland@redhat.com> | |
16 | Signed-off-by: Coly Li <coly.li@suse.de> | |
17 | --- | |
18 | fs/dlm/plock.c | 17 ++++++++++------- | |
19 | 1 files changed, 10 insertions(+), 7 deletions(-) | |
20 | ||
21 | diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c | |
22 | index 894a32d..16f682e 100644 | |
23 | --- a/fs/dlm/plock.c | |
24 | +++ b/fs/dlm/plock.c | |
25 | @@ -353,7 +353,7 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count, | |
26 | { | |
27 | struct dlm_plock_info info; | |
28 | struct plock_op *op; | |
29 | - int found = 0; | |
30 | + int found = 0, do_callback = 0; | |
31 | ||
32 | if (count != sizeof(info)) | |
33 | return -EINVAL; | |
34 | @@ -366,21 +366,24 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count, | |
35 | ||
36 | spin_lock(&ops_lock); | |
37 | list_for_each_entry(op, &recv_list, list) { | |
38 | - if (op->info.fsid == info.fsid && op->info.number == info.number && | |
39 | + if (op->info.fsid == info.fsid && | |
40 | + op->info.number == info.number && | |
41 | op->info.owner == info.owner) { | |
42 | + struct plock_xop *xop = (struct plock_xop *)op; | |
43 | list_del_init(&op->list); | |
44 | - found = 1; | |
45 | - op->done = 1; | |
46 | memcpy(&op->info, &info, sizeof(info)); | |
47 | + if (xop->callback) | |
48 | + do_callback = 1; | |
49 | + else | |
50 | + op->done = 1; | |
51 | + found = 1; | |
52 | break; | |
53 | } | |
54 | } | |
55 | spin_unlock(&ops_lock); | |
56 | ||
57 | if (found) { | |
58 | - struct plock_xop *xop; | |
59 | - xop = (struct plock_xop *)op; | |
60 | - if (xop->callback) | |
61 | + if (do_callback) | |
62 | dlm_plock_callback(op); | |
63 | else | |
64 | wake_up(&recv_wq); | |
65 | -- | |
66 | 1.6.0.2 | |
67 |