aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorEric Sandeen <sandeen@redhat.com>2007-01-05 19:36:36 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2007-01-06 02:55:23 -0500
commitbe6aab0e9fa6d3c6d75aa1e38ac972d8b4ee82b8 (patch)
tree6601373d683326f034fcce292953673a522db111 /fs
parent2723f9603a8f8bb2cd8c7b581f7c94b8d75e3837 (diff)
[PATCH] fix memory corruption from misinterpreted bad_inode_ops return values
CVE-2006-5753 is for a case where an inode can be marked bad, switching the ops to bad_inode_ops, which are all connected as: static int return_EIO(void) { return -EIO; } #define EIO_ERROR ((void *) (return_EIO)) static struct inode_operations bad_inode_ops = { .create = bad_inode_create ...etc... The problem here is that the void cast causes return types to not be promoted, and for ops such as listxattr which expect more than 32 bits of return value, the 32-bit -EIO is interpreted as a large positive 64-bit number, i.e. 0x00000000fffffffa instead of 0xfffffffa. This goes particularly badly when the return value is taken as a number of bytes to copy into, say, a user's buffer for example... I originally had coded up the fix by creating a return_EIO_<TYPE> macro for each return type, like this: static int return_EIO_int(void) { return -EIO; } #define EIO_ERROR_INT ((void *) (return_EIO_int)) static struct inode_operations bad_inode_ops = { .create = EIO_ERROR_INT, ...etc... but Al felt that it was probably better to create an EIO-returner for each actual op signature. Since so few ops share a signature, I just went ahead & created an EIO function for each individual file & inode op that returns a value. Signed-off-by: Eric Sandeen <sandeen@redhat.com> Cc: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/bad_inode.c330
1 files changed, 289 insertions, 41 deletions
diff --git a/fs/bad_inode.c b/fs/bad_inode.c
index 34e6d7b220c3..869f5193ecc2 100644
--- a/fs/bad_inode.c
+++ b/fs/bad_inode.c
@@ -14,59 +14,307 @@
14#include <linux/time.h> 14#include <linux/time.h>
15#include <linux/smp_lock.h> 15#include <linux/smp_lock.h>
16#include <linux/namei.h> 16#include <linux/namei.h>
17#include <linux/poll.h>
17 18
18static int return_EIO(void) 19
20static loff_t bad_file_llseek(struct file *file, loff_t offset, int origin)
21{
22 return -EIO;
23}
24
25static ssize_t bad_file_read(struct file *filp, char __user *buf,
26 size_t size, loff_t *ppos)
27{
28 return -EIO;
29}
30
31static ssize_t bad_file_write(struct file *filp, const char __user *buf,
32 size_t siz, loff_t *ppos)
33{
34 return -EIO;
35}
36
37static ssize_t bad_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
38 unsigned long nr_segs, loff_t pos)
39{
40 return -EIO;
41}
42
43static ssize_t bad_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
44 unsigned long nr_segs, loff_t pos)
45{
46 return -EIO;
47}
48
49static int bad_file_readdir(struct file *filp, void *dirent, filldir_t filldir)
50{
51 return -EIO;
52}
53
54static unsigned int bad_file_poll(struct file *filp, poll_table *wait)
55{
56 return POLLERR;
57}
58
59static int bad_file_ioctl (struct inode *inode, struct file *filp,
60 unsigned int cmd, unsigned long arg)
61{
62 return -EIO;
63}
64
65static long bad_file_unlocked_ioctl(struct file *file, unsigned cmd,
66 unsigned long arg)
67{
68 return -EIO;
69}
70
71static long bad_file_compat_ioctl(struct file *file, unsigned int cmd,
72 unsigned long arg)
73{
74 return -EIO;
75}
76
77static int bad_file_mmap(struct file *file, struct vm_area_struct *vma)
78{
79 return -EIO;
80}
81
82static int bad_file_open(struct inode *inode, struct file *filp)
83{
84 return -EIO;
85}
86
87static int bad_file_flush(struct file *file, fl_owner_t id)
88{
89 return -EIO;
90}
91
92static int bad_file_release(struct inode *inode, struct file *filp)
93{
94 return -EIO;
95}
96
97static int bad_file_fsync(struct file *file, struct dentry *dentry,
98 int datasync)
99{
100 return -EIO;
101}
102
103static int bad_file_aio_fsync(struct kiocb *iocb, int datasync)
104{
105 return -EIO;
106}
107
108static int bad_file_fasync(int fd, struct file *filp, int on)
109{
110 return -EIO;
111}
112
113static int bad_file_lock(struct file *file, int cmd, struct file_lock *fl)
114{
115 return -EIO;
116}
117
118static ssize_t bad_file_sendfile(struct file *in_file, loff_t *ppos,
119 size_t count, read_actor_t actor, void *target)
120{
121 return -EIO;
122}
123
124static ssize_t bad_file_sendpage(struct file *file, struct page *page,
125 int off, size_t len, loff_t *pos, int more)
126{
127 return -EIO;
128}
129
130static unsigned long bad_file_get_unmapped_area(struct file *file,
131 unsigned long addr, unsigned long len,
132 unsigned long pgoff, unsigned long flags)
133{
134 return -EIO;
135}
136
137static int bad_file_check_flags(int flags)
19{ 138{
20 return -EIO; 139 return -EIO;
21} 140}
22 141
23#define EIO_ERROR ((void *) (return_EIO)) 142static int bad_file_dir_notify(struct file *file, unsigned long arg)
143{
144 return -EIO;
145}
146
147static int bad_file_flock(struct file *filp, int cmd, struct file_lock *fl)
148{
149 return -EIO;
150}
151
152static ssize_t bad_file_splice_write(struct pipe_inode_info *pipe,
153 struct file *out, loff_t *ppos, size_t len,
154 unsigned int flags)
155{
156 return -EIO;
157}
158
159static ssize_t bad_file_splice_read(struct file *in, loff_t *ppos,
160 struct pipe_inode_info *pipe, size_t len,
161 unsigned int flags)
162{
163 return -EIO;
164}
24 165
25static const struct file_operations bad_file_ops = 166static const struct file_operations bad_file_ops =
26{ 167{
27 .llseek = EIO_ERROR, 168 .llseek = bad_file_llseek,
28 .aio_read = EIO_ERROR, 169 .read = bad_file_read,
29 .read = EIO_ERROR, 170 .write = bad_file_write,
30 .write = EIO_ERROR, 171 .aio_read = bad_file_aio_read,
31 .aio_write = EIO_ERROR, 172 .aio_write = bad_file_aio_write,
32 .readdir = EIO_ERROR, 173 .readdir = bad_file_readdir,
33 .poll = EIO_ERROR, 174 .poll = bad_file_poll,
34 .ioctl = EIO_ERROR, 175 .ioctl = bad_file_ioctl,
35 .mmap = EIO_ERROR, 176 .unlocked_ioctl = bad_file_unlocked_ioctl,
36 .open = EIO_ERROR, 177 .compat_ioctl = bad_file_compat_ioctl,
37 .flush = EIO_ERROR, 178 .mmap = bad_file_mmap,
38 .release = EIO_ERROR, 179 .open = bad_file_open,
39 .fsync = EIO_ERROR, 180 .flush = bad_file_flush,
40 .aio_fsync = EIO_ERROR, 181 .release = bad_file_release,
41 .fasync = EIO_ERROR, 182 .fsync = bad_file_fsync,
42 .lock = EIO_ERROR, 183 .aio_fsync = bad_file_aio_fsync,
43 .sendfile = EIO_ERROR, 184 .fasync = bad_file_fasync,
44 .sendpage = EIO_ERROR, 185 .lock = bad_file_lock,
45 .get_unmapped_area = EIO_ERROR, 186 .sendfile = bad_file_sendfile,
187 .sendpage = bad_file_sendpage,
188 .get_unmapped_area = bad_file_get_unmapped_area,
189 .check_flags = bad_file_check_flags,
190 .dir_notify = bad_file_dir_notify,
191 .flock = bad_file_flock,
192 .splice_write = bad_file_splice_write,
193 .splice_read = bad_file_splice_read,
46}; 194};
47 195
196static int bad_inode_create (struct inode *dir, struct dentry *dentry,
197 int mode, struct nameidata *nd)
198{
199 return -EIO;
200}
201
202static struct dentry *bad_inode_lookup(struct inode *dir,
203 struct dentry *dentry, struct nameidata *nd)
204{
205 return ERR_PTR(-EIO);
206}
207
208static int bad_inode_link (struct dentry *old_dentry, struct inode *dir,
209 struct dentry *dentry)
210{
211 return -EIO;
212}
213
214static int bad_inode_unlink(struct inode *dir, struct dentry *dentry)
215{
216 return -EIO;
217}
218
219static int bad_inode_symlink (struct inode *dir, struct dentry *dentry,
220 const char *symname)
221{
222 return -EIO;
223}
224
225static int bad_inode_mkdir(struct inode *dir, struct dentry *dentry,
226 int mode)
227{
228 return -EIO;
229}
230
231static int bad_inode_rmdir (struct inode *dir, struct dentry *dentry)
232{
233 return -EIO;
234}
235
236static int bad_inode_mknod (struct inode *dir, struct dentry *dentry,
237 int mode, dev_t rdev)
238{
239 return -EIO;
240}
241
242static int bad_inode_rename (struct inode *old_dir, struct dentry *old_dentry,
243 struct inode *new_dir, struct dentry *new_dentry)
244{
245 return -EIO;
246}
247
248static int bad_inode_readlink(struct dentry *dentry, char __user *buffer,
249 int buflen)
250{
251 return -EIO;
252}
253
254static int bad_inode_permission(struct inode *inode, int mask,
255 struct nameidata *nd)
256{
257 return -EIO;
258}
259
260static int bad_inode_getattr(struct vfsmount *mnt, struct dentry *dentry,
261 struct kstat *stat)
262{
263 return -EIO;
264}
265
266static int bad_inode_setattr(struct dentry *direntry, struct iattr *attrs)
267{
268 return -EIO;
269}
270
271static int bad_inode_setxattr(struct dentry *dentry, const char *name,
272 const void *value, size_t size, int flags)
273{
274 return -EIO;
275}
276
277static ssize_t bad_inode_getxattr(struct dentry *dentry, const char *name,
278 void *buffer, size_t size)
279{
280 return -EIO;
281}
282
283static ssize_t bad_inode_listxattr(struct dentry *dentry, char *buffer,
284 size_t buffer_size)
285{
286 return -EIO;
287}
288
289static int bad_inode_removexattr(struct dentry *dentry, const char *name)
290{
291 return -EIO;
292}
293
48static struct inode_operations bad_inode_ops = 294static struct inode_operations bad_inode_ops =
49{ 295{
50 .create = EIO_ERROR, 296 .create = bad_inode_create,
51 .lookup = EIO_ERROR, 297 .lookup = bad_inode_lookup,
52 .link = EIO_ERROR, 298 .link = bad_inode_link,
53 .unlink = EIO_ERROR, 299 .unlink = bad_inode_unlink,
54 .symlink = EIO_ERROR, 300 .symlink = bad_inode_symlink,
55 .mkdir = EIO_ERROR, 301 .mkdir = bad_inode_mkdir,
56 .rmdir = EIO_ERROR, 302 .rmdir = bad_inode_rmdir,
57 .mknod = EIO_ERROR, 303 .mknod = bad_inode_mknod,
58 .rename = EIO_ERROR, 304 .rename = bad_inode_rename,
59 .readlink = EIO_ERROR, 305 .readlink = bad_inode_readlink,
60 /* follow_link must be no-op, otherwise unmounting this inode 306 /* follow_link must be no-op, otherwise unmounting this inode
61 won't work */ 307 won't work */
62 .truncate = EIO_ERROR, 308 /* put_link returns void */
63 .permission = EIO_ERROR, 309 /* truncate returns void */
64 .getattr = EIO_ERROR, 310 .permission = bad_inode_permission,
65 .setattr = EIO_ERROR, 311 .getattr = bad_inode_getattr,
66 .setxattr = EIO_ERROR, 312 .setattr = bad_inode_setattr,
67 .getxattr = EIO_ERROR, 313 .setxattr = bad_inode_setxattr,
68 .listxattr = EIO_ERROR, 314 .getxattr = bad_inode_getxattr,
69 .removexattr = EIO_ERROR, 315 .listxattr = bad_inode_listxattr,
316 .removexattr = bad_inode_removexattr,
317 /* truncate_range returns void */
70}; 318};
71 319
72 320
@@ -88,7 +336,7 @@ static struct inode_operations bad_inode_ops =
88 * on it to fail from this point on. 336 * on it to fail from this point on.
89 */ 337 */
90 338
91void make_bad_inode(struct inode * inode) 339void make_bad_inode(struct inode *inode)
92{ 340{
93 remove_inode_hash(inode); 341 remove_inode_hash(inode);
94 342
@@ -113,7 +361,7 @@ EXPORT_SYMBOL(make_bad_inode);
113 * Returns true if the inode in question has been marked as bad. 361 * Returns true if the inode in question has been marked as bad.
114 */ 362 */
115 363
116int is_bad_inode(struct inode * inode) 364int is_bad_inode(struct inode *inode)
117{ 365{
118 return (inode->i_op == &bad_inode_ops); 366 return (inode->i_op == &bad_inode_ops);
119} 367}