]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/2.6.15.2/fix-double-decrement-of-mqueue_mnt-mnt_count-in-sys_mq_open.patch
Fixes for 4.19
[thirdparty/kernel/stable-queue.git] / releases / 2.6.15.2 / fix-double-decrement-of-mqueue_mnt-mnt_count-in-sys_mq_open.patch
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>
4 Date: 1137270595 -0500
5
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().
13
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
17 normal path.
18
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>
23 ---
24 ipc/mqueue.c | 59 +++++++++++++++++++++++++++++++++--------------------------
25 1 file changed, 33 insertions(+), 26 deletions(-)
26
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)
32 {
33 - struct file *filp;
34 struct mq_attr attr;
35 int ret;
36
37 - if (u_attr != NULL) {
38 + if (u_attr) {
39 + ret = -EFAULT;
40 if (copy_from_user(&attr, u_attr, sizeof(attr)))
41 - return ERR_PTR(-EFAULT);
42 + goto out;
43 + ret = -EINVAL;
44 if (!mq_attr_ok(&attr))
45 - return ERR_PTR(-EINVAL);
46 + goto out;
47 /* store for use during create */
48 dentry->d_fsdata = &attr;
49 }
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;
53 if (ret)
54 - return ERR_PTR(ret);
55 + goto out;
56
57 - filp = dentry_open(dentry, mqueue_mnt, oflag);
58 - if (!IS_ERR(filp))
59 - dget(dentry);
60 + return dentry_open(dentry, mqueue_mnt, oflag);
61
62 - return filp;
63 +out:
64 + dput(dentry);
65 + mntput(mqueue_mnt);
66 + return ERR_PTR(ret);
67 }
68
69 /* Opens existing queue */
70 @@ -629,20 +631,20 @@ static struct file *do_open(struct dentr
71 {
72 static int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE,
73 MAY_READ | MAY_WRITE };
74 - struct file *filp;
75
76 - if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY))
77 + if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) {
78 + dput(dentry);
79 + mntput(mqueue_mnt);
80 return ERR_PTR(-EINVAL);
81 + }
82
83 - if (permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE], NULL))
84 + if (permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE], NULL)) {
85 + dput(dentry);
86 + mntput(mqueue_mnt);
87 return ERR_PTR(-EACCES);
88 + }
89
90 - filp = dentry_open(dentry, mqueue_mnt, oflag);
91 -
92 - if (!IS_ERR(filp))
93 - dget(dentry);
94 -
95 - return filp;
96 + return dentry_open(dentry, mqueue_mnt, oflag);
97 }
98
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 _
101
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);
106 + error = -EEXIST;
107 + if (oflag & O_EXCL)
108 + goto out;
109 + filp = do_open(dentry, oflag);
110 } else {
111 filp = do_create(mqueue_mnt->mnt_root, dentry,
112 oflag, mode, u_attr);
113 }
114 - } else
115 - filp = (dentry->d_inode) ? do_open(dentry, oflag) :
116 - ERR_PTR(-ENOENT);
117 -
118 - dput(dentry);
119 + } else {
120 + error = -ENOENT;
121 + if (!dentry->d_inode)
122 + goto out;
123 + filp = do_open(dentry, oflag);
124 + }
125
126 if (IS_ERR(filp)) {
127 error = PTR_ERR(filp);
128 @@ -691,8 +696,10 @@ asmlinkage long sys_mq_open(const char _
129 fd_install(fd, filp);
130 goto out_upsem;
131
132 -out_putfd:
133 +out:
134 + dput(dentry);
135 mntput(mqueue_mnt);
136 +out_putfd:
137 put_unused_fd(fd);
138 out_err:
139 fd = error;