From: Chris Wright Date: Sun, 15 Jan 2006 07:22:25 +0000 (-0800) Subject: Add mqueue double decrement from Al Viro, fwd from Mark Cox X-Git-Tag: v2.6.14.7~13 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c71965b2fb31c9432658a6fe92deba3a3a2dbfa7;p=thirdparty%2Fkernel%2Fstable-queue.git Add mqueue double decrement from Al Viro, fwd from Mark Cox --- diff --git a/queue/fix-double-decrement-of-mqueue_mnt-mnt_count-in-sys_mq_open.patch b/queue/fix-double-decrement-of-mqueue_mnt-mnt_count-in-sys_mq_open.patch new file mode 100644 index 00000000000..b76db03538e --- /dev/null +++ b/queue/fix-double-decrement-of-mqueue_mnt-mnt_count-in-sys_mq_open.patch @@ -0,0 +1,138 @@ +From nobody Mon Sep 17 00:00:00 2001 +Subject: [PATCH] Fix double decrement of mqueue_mnt->mnt_count in sys_mq_open (CVE-2005-3356) +From: Alexander Viro +Date: 1137270595 -0500 + +Fixed the refcounting on failure exits in sys_mq_open() and +cleaned the logics up. Rules are actually pretty simple - dentry_open() +expects vfsmount and dentry to be pinned down and it either transfers +them into created struct file or drops them. Old code had been very +confused in that area - if dentry_open() had failed either in do_open() +or do_create(), we ended up dentry and mqueue_mnt dropped twice, once +by dentry_open() cleanup and then by sys_mq_open(). + +Fix consists of making the rules for do_create() and do_open() +same as for dentry_open() and updating the sys_mq_open() accordingly; +that actually leads to more straightforward code and less work on +normal path. + +Signed-off-by: Al Viro +Signed-off-by: Linus Torvalds +Signed-off-by: Chris Wright +--- + ipc/mqueue.c | 59 +++++++++++++++++++++++++++++++++-------------------------- + 1 files changed, 33 insertions(+), 26 deletions(-) + +--- linux-2.6.15.1.orig/ipc/mqueue.c ++++ linux-2.6.15.1/ipc/mqueue.c +@@ -598,15 +598,16 @@ static int mq_attr_ok(struct mq_attr *at + static struct file *do_create(struct dentry *dir, struct dentry *dentry, + int oflag, mode_t mode, struct mq_attr __user *u_attr) + { +- struct file *filp; + struct mq_attr attr; + int ret; + +- if (u_attr != NULL) { ++ if (u_attr) { ++ ret = -EFAULT; + if (copy_from_user(&attr, u_attr, sizeof(attr))) +- return ERR_PTR(-EFAULT); ++ goto out; ++ ret = -EINVAL; + if (!mq_attr_ok(&attr)) +- return ERR_PTR(-EINVAL); ++ goto out; + /* store for use during create */ + dentry->d_fsdata = &attr; + } +@@ -615,13 +616,14 @@ static struct file *do_create(struct den + ret = vfs_create(dir->d_inode, dentry, mode, NULL); + dentry->d_fsdata = NULL; + if (ret) +- return ERR_PTR(ret); ++ goto out; + +- filp = dentry_open(dentry, mqueue_mnt, oflag); +- if (!IS_ERR(filp)) +- dget(dentry); ++ return dentry_open(dentry, mqueue_mnt, oflag); + +- return filp; ++out: ++ dput(dentry); ++ mntput(mqueue_mnt); ++ return ERR_PTR(ret); + } + + /* Opens existing queue */ +@@ -629,20 +631,20 @@ static struct file *do_open(struct dentr + { + static int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE, + MAY_READ | MAY_WRITE }; +- struct file *filp; + +- if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) ++ if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) { ++ dput(dentry); ++ mntput(mqueue_mnt); + return ERR_PTR(-EINVAL); ++ } + +- if (permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE], NULL)) ++ if (permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE], NULL)) { ++ dput(dentry); ++ mntput(mqueue_mnt); + return ERR_PTR(-EACCES); ++ } + +- filp = dentry_open(dentry, mqueue_mnt, oflag); +- +- if (!IS_ERR(filp)) +- dget(dentry); +- +- return filp; ++ return dentry_open(dentry, mqueue_mnt, oflag); + } + + asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode, +@@ -670,17 +672,20 @@ asmlinkage long sys_mq_open(const char _ + + if (oflag & O_CREAT) { + if (dentry->d_inode) { /* entry already exists */ +- filp = (oflag & O_EXCL) ? ERR_PTR(-EEXIST) : +- do_open(dentry, oflag); ++ error = -EEXIST; ++ if (oflag & O_EXCL) ++ goto out; ++ filp = do_open(dentry, oflag); + } else { + filp = do_create(mqueue_mnt->mnt_root, dentry, + oflag, mode, u_attr); + } +- } else +- filp = (dentry->d_inode) ? do_open(dentry, oflag) : +- ERR_PTR(-ENOENT); +- +- dput(dentry); ++ } else { ++ error = -ENOENT; ++ if (!dentry->d_inode) ++ goto out; ++ filp = do_open(dentry, oflag); ++ } + + if (IS_ERR(filp)) { + error = PTR_ERR(filp); +@@ -691,8 +696,10 @@ asmlinkage long sys_mq_open(const char _ + fd_install(fd, filp); + goto out_upsem; + +-out_putfd: ++out: ++ dput(dentry); + mntput(mqueue_mnt); ++out_putfd: + put_unused_fd(fd); + out_err: + fd = error; diff --git a/queue/series b/queue/series index 40f5e841cbf..0ab8bfa26ef 100644 --- a/queue/series +++ b/queue/series @@ -1,3 +1,4 @@ usb-audio-dont-use-empty-packets-at-start-of-playback.patch kill-blk_attempt_remerge.patch input-hid-fix-an-oops-in-pid-initialization-code.patch +fix-double-decrement-of-mqueue_mnt-mnt_count-in-sys_mq_open.patch