/[linux-patches]/genpatches-2.6/trunk/2.6.31/1500_pipe-c-null-ptr-dref.patch
Gentoo

Contents of /genpatches-2.6/trunk/2.6.31/1500_pipe-c-null-ptr-dref.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1626 - (show annotations) (download)
Fri Nov 6 01:25:22 2009 UTC (8 years, 11 months ago) by mpagano
File size: 3733 byte(s)
Fix for the null pointer exception in pipe_rdwr_open (CVE-2009-3547)
1 From: Earl Chew <earl_chew@agilent.com>
2 Date: Mon, 19 Oct 2009 22:55:41 +0000 (-0700)
3 Subject: fs: pipe.c null pointer dereference
4 X-Git-Tag: v2.6.32-rc6~124
5 X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=ad3960243e55320d74195fb85c975e0a8cc4466c
6
7 fs: pipe.c null pointer dereference
8
9 This patch fixes a null pointer exception in pipe_rdwr_open() which
10 generates the stack trace:
11
12 > Unable to handle kernel NULL pointer dereference at 0000000000000028 RIP:
13 > [<ffffffff802899a5>] pipe_rdwr_open+0x35/0x70
14 > [<ffffffff8028125c>] __dentry_open+0x13c/0x230
15 > [<ffffffff8028143d>] do_filp_open+0x2d/0x40
16 > [<ffffffff802814aa>] do_sys_open+0x5a/0x100
17 > [<ffffffff8021faf3>] sysenter_do_call+0x1b/0x67
18
19 The failure mode is triggered by an attempt to open an anonymous
20 pipe via /proc/pid/fd/* as exemplified by this script:
21
22 =============================================================
23 while : ; do
24 { echo y ; sleep 1 ; } | { while read ; do echo z$REPLY; done ; } &
25 PID=$!
26 OUT=$(ps -efl | grep 'sleep 1' | grep -v grep |
27 { read PID REST ; echo $PID; } )
28 OUT="${OUT%% *}"
29 DELAY=$((RANDOM * 1000 / 32768))
30 usleep $((DELAY * 1000 + RANDOM % 1000 ))
31 echo n > /proc/$OUT/fd/1 # Trigger defect
32 done
33 =============================================================
34
35 Note that the failure window is quite small and I could only
36 reliably reproduce the defect by inserting a small delay
37 in pipe_rdwr_open(). For example:
38
39 static int
40 pipe_rdwr_open(struct inode *inode, struct file *filp)
41 {
42 msleep(100);
43 mutex_lock(&inode->i_mutex);
44
45 Although the defect was observed in pipe_rdwr_open(), I think it
46 makes sense to replicate the change through all the pipe_*_open()
47 functions.
48
49 The core of the change is to verify that inode->i_pipe has not
50 been released before attempting to manipulate it. If inode->i_pipe
51 is no longer present, return ENOENT to indicate so.
52
53 The comment about potentially using atomic_t for i_pipe->readers
54 and i_pipe->writers has also been removed because it is no longer
55 relevant in this context. The inode->i_mutex lock must be used so
56 that inode->i_pipe can be dealt with correctly.
57
58 Signed-off-by: Earl Chew <earl_chew@agilent.com>
59 Cc: stable@kernel.org
60 Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
61 ---
62
63 diff --git a/fs/pipe.c b/fs/pipe.c
64 index 52c4151..ae17d02 100644
65 --- a/fs/pipe.c
66 +++ b/fs/pipe.c
67 @@ -777,36 +777,55 @@ pipe_rdwr_release(struct inode *inode, struct file *filp)
68 static int
69 pipe_read_open(struct inode *inode, struct file *filp)
70 {
71 - /* We could have perhaps used atomic_t, but this and friends
72 - below are the only places. So it doesn't seem worthwhile. */
73 + int ret = -ENOENT;
74 +
75 mutex_lock(&inode->i_mutex);
76 - inode->i_pipe->readers++;
77 +
78 + if (inode->i_pipe) {
79 + ret = 0;
80 + inode->i_pipe->readers++;
81 + }
82 +
83 mutex_unlock(&inode->i_mutex);
84
85 - return 0;
86 + return ret;
87 }
88
89 static int
90 pipe_write_open(struct inode *inode, struct file *filp)
91 {
92 + int ret = -ENOENT;
93 +
94 mutex_lock(&inode->i_mutex);
95 - inode->i_pipe->writers++;
96 +
97 + if (inode->i_pipe) {
98 + ret = 0;
99 + inode->i_pipe->writers++;
100 + }
101 +
102 mutex_unlock(&inode->i_mutex);
103
104 - return 0;
105 + return ret;
106 }
107
108 static int
109 pipe_rdwr_open(struct inode *inode, struct file *filp)
110 {
111 + int ret = -ENOENT;
112 +
113 mutex_lock(&inode->i_mutex);
114 - if (filp->f_mode & FMODE_READ)
115 - inode->i_pipe->readers++;
116 - if (filp->f_mode & FMODE_WRITE)
117 - inode->i_pipe->writers++;
118 +
119 + if (inode->i_pipe) {
120 + ret = 0;
121 + if (filp->f_mode & FMODE_READ)
122 + inode->i_pipe->readers++;
123 + if (filp->f_mode & FMODE_WRITE)
124 + inode->i_pipe->writers++;
125 + }
126 +
127 mutex_unlock(&inode->i_mutex);
128
129 - return 0;
130 + return ret;
131 }
132
133 /*
134

  ViewVC Help
Powered by ViewVC 1.1.20