1 From nobody Mon Sep 17 00:00:00 2001
2 Subject: [PATCH] Fix double decrement of mqueue_mnt->mnt_count in sys_mq_open (CVE-2005-3356)
3 From: Alexander Viro <aviro@redhat.com>
6 Fixed the refcounting on failure exits in sys_mq_open() and
7 cleaned the logics up. Rules are actually pretty simple - dentry_open()
8 expects vfsmount and dentry to be pinned down and it either transfers
9 them into created struct file or drops them. Old code had been very
10 confused in that area - if dentry_open() had failed either in do_open()
11 or do_create(), we ended up dentry and mqueue_mnt dropped twice, once
12 by dentry_open() cleanup and then by sys_mq_open().
14 Fix consists of making the rules for do_create() and do_open()
15 same as for dentry_open() and updating the sys_mq_open() accordingly;
16 that actually leads to more straightforward code and less work on
19 Signed-off-by: Al Viro <aviro@redhat.com>
20 Signed-off-by: Linus Torvalds <torvalds@osdl.org>
21 Signed-off-by: Chris Wright <chrisw@sous-sol.org>
22 Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
24 ipc/mqueue.c | 59 +++++++++++++++++++++++++++++++++--------------------------
25 1 file changed, 33 insertions(+), 26 deletions(-)
27 --- linux-2.6.15.1.orig/ipc/mqueue.c
28 +++ linux-2.6.15.1/ipc/mqueue.c
29 @@ -598,15 +598,16 @@ static int mq_attr_ok(struct mq_attr *at
30 static struct file *do_create(struct dentry *dir, struct dentry *dentry,
31 int oflag, mode_t mode, struct mq_attr __user *u_attr)
37 - if (u_attr != NULL) {
40 if (copy_from_user(&attr, u_attr, sizeof(attr)))
41 - return ERR_PTR(-EFAULT);
44 if (!mq_attr_ok(&attr))
45 - return ERR_PTR(-EINVAL);
47 /* store for use during create */
48 dentry->d_fsdata = &attr;
50 @@ -615,13 +616,14 @@ static struct file *do_create(struct den
51 ret = vfs_create(dir->d_inode, dentry, mode, NULL);
52 dentry->d_fsdata = NULL;
54 - return ERR_PTR(ret);
57 - filp = dentry_open(dentry, mqueue_mnt, oflag);
60 + return dentry_open(dentry, mqueue_mnt, oflag);
66 + return ERR_PTR(ret);
69 /* Opens existing queue */
70 @@ -629,20 +631,20 @@ static struct file *do_open(struct dentr
72 static int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE,
73 MAY_READ | MAY_WRITE };
76 - if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY))
77 + if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) {
80 return ERR_PTR(-EINVAL);
83 - if (permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE], NULL))
84 + if (permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE], NULL)) {
87 return ERR_PTR(-EACCES);
90 - filp = dentry_open(dentry, mqueue_mnt, oflag);
96 + return dentry_open(dentry, mqueue_mnt, oflag);
99 asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode,
100 @@ -670,17 +672,20 @@ asmlinkage long sys_mq_open(const char _
102 if (oflag & O_CREAT) {
103 if (dentry->d_inode) { /* entry already exists */
104 - filp = (oflag & O_EXCL) ? ERR_PTR(-EEXIST) :
105 - do_open(dentry, oflag);
107 + if (oflag & O_EXCL)
109 + filp = do_open(dentry, oflag);
111 filp = do_create(mqueue_mnt->mnt_root, dentry,
112 oflag, mode, u_attr);
115 - filp = (dentry->d_inode) ? do_open(dentry, oflag) :
121 + if (!dentry->d_inode)
123 + filp = do_open(dentry, oflag);
127 error = PTR_ERR(filp);
128 @@ -691,8 +696,10 @@ asmlinkage long sys_mq_open(const char _
129 fd_install(fd, filp);