add rc patch && chlog
[linux-2.6.22.y-op-patches.git] / review-2.6.22.y / fix-dnotify_close-race.patch
blob415aea9ffa83b73ccaf0ce4e0cc8c440f303b51a
1 From 214b7049a7929f03bbd2786aaef04b8b79db34e2 Mon Sep 17 00:00:00 2001
2 From: Al Viro <viro@ZenIV.linux.org.uk>
3 Date: Thu, 1 May 2008 03:52:22 +0100
4 Subject: [PATCH] Fix dnotify/close race
6 We have a race between fcntl() and close() that can lead to
7 dnotify_struct inserted into inode's list *after* the last descriptor
8 had been gone from current->files.
10 Since that's the only point where dnotify_struct gets evicted, we are
11 screwed - it will stick around indefinitely. Even after struct file in
12 question is gone and freed. Worse, we can trigger send_sigio() on it at
13 any later point, which allows to send an arbitrary signal to arbitrary
14 process if we manage to apply enough memory pressure to get the page
15 that used to host that struct file and fill it with the right pattern...
17 Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
18 Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
19 Signed-off-by: Oliver Pinter <oliver.pntr@gmail.com>
21 diff --git a/fs/dnotify.c b/fs/dnotify.c
22 index 28d01ed..eaecc4c 100644
23 --- a/fs/dnotify.c
24 +++ b/fs/dnotify.c
25 @@ -20,6 +20,7 @@
26 #include <linux/init.h>
27 #include <linux/spinlock.h>
28 #include <linux/slab.h>
29 +#include <linux/file.h>
31 int dir_notify_enable __read_mostly = 1;
33 @@ -66,6 +67,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
34 struct dnotify_struct **prev;
35 struct inode *inode;
36 fl_owner_t id = current->files;
37 + struct file *f;
38 int error = 0;
40 if ((arg & ~DN_MULTISHOT) == 0) {
41 @@ -92,6 +94,15 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
42 prev = &odn->dn_next;
45 + rcu_read_lock();
46 + f = fcheck(fd);
47 + rcu_read_unlock();
48 + /* we'd lost the race with close(), sod off silently */
49 + /* note that inode->i_lock prevents reordering problems
50 + * between accesses to descriptor table and ->i_dnotify */
51 + if (f != filp)
52 + goto out_free;
54 error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
55 if (error)
56 goto out_free;