[kernel] r15859 - in dists/lenny/linux-2.6/debian: . patches/bugfix/all patches/series
Dann Frazier
dannf at alioth.debian.org
Sat Jun 12 01:39:06 UTC 2010
Author: dannf
Date: Sat Jun 12 01:39:04 2010
New Revision: 15859
Log:
* nsfd: fix vm overcommit crash (CVE-2008-7256, CVE-2010-1643)
* GFS2: Fix writing to non-page aligned gfs2_quota structures (CVE-2010-1436)
Added:
dists/lenny/linux-2.6/debian/patches/bugfix/all/gfs2-clean-up-gfs2_adjust_quota-and-do_glock.patch
dists/lenny/linux-2.6/debian/patches/bugfix/all/gfs2-fix-writing-to-non-page-aligned-gfs2_quota-structures.patch
Modified:
dists/lenny/linux-2.6/debian/changelog
dists/lenny/linux-2.6/debian/patches/series/23
Modified: dists/lenny/linux-2.6/debian/changelog
==============================================================================
--- dists/lenny/linux-2.6/debian/changelog Sat Jun 12 00:47:19 2010 (r15858)
+++ dists/lenny/linux-2.6/debian/changelog Sat Jun 12 01:39:04 2010 (r15859)
@@ -5,8 +5,9 @@
* sunxvr500: Ignore secondary output PCI devices (Closes: #580422)
* sctp: fix append error cause to ERROR chunk correctly
(a further fix for CVE-2010-1173)
- * nsfd: fix vm overcommit crash (CVE-2010-1643)
+ * nsfd: fix vm overcommit crash (CVE-2008-7256, CVE-2010-1643)
* GFS2: Fix permissions checking for setflags ioctl() (CVE-2010-1641)
+ * GFS2: Fix writing to non-page aligned gfs2_quota structures (CVE-2010-1436)
[ Ben Hutchings ]
* [sparc64] Fix definition of VMEMMAP_SIZE (Closes: #509202)
@@ -33,7 +34,7 @@
* backport MIPS FPU emulator: allow Cause bits of FCSR to be writeable
by ctc1. (closes: #580602).
- -- dann frazier <dannf at debian.org> Wed, 10 Mar 2010 23:42:11 -0700
+ -- dann frazier <dannf at debian.org> Fri, 11 Jun 2010 18:33:00 -0600
linux-2.6 (2.6.26-22lenny1) stable-security; urgency=high
Added: dists/lenny/linux-2.6/debian/patches/bugfix/all/gfs2-clean-up-gfs2_adjust_quota-and-do_glock.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/lenny/linux-2.6/debian/patches/bugfix/all/gfs2-clean-up-gfs2_adjust_quota-and-do_glock.patch Sat Jun 12 01:39:04 2010 (r15859)
@@ -0,0 +1,191 @@
+commit 25ad148d8bef9493549b692b6a558799bf14f774
+Author: Steven Whitehouse <swhiteho at redhat.com>
+Date: Tue Sep 15 20:42:56 2009 +0100
+
+ GFS2: Clean up gfs2_adjust_quota() and do_glock()
+
+ Both of these functions contained confusing and in one case
+ duplicate code. This patch adds a new check in do_glock()
+ so that we report -ENOENT if we are asked to sync a quota
+ entry which doesn't exist. Due to the previous patch this is
+ now reported correctly to userspace.
+
+ Also there are a few new comments, and I hope that the code
+ is easier to understand now.
+
+ [Backported to Debian's 2.6.26 by dann frazier <dannf at debian.org>]
+ Signed-off-by: Steven Whitehouse <swhiteho at redhat.com>
+
+diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
+index 56aaf91..1e4d248 100644
+--- a/fs/gfs2/quota.c
++++ b/fs/gfs2/quota.c
+@@ -15,7 +15,7 @@
+ * fuzziness in the current usage value of IDs that are being used on different
+ * nodes in the cluster simultaneously. So, it is possible for a user on
+ * multiple nodes to overrun their quota, but that overrun is controlable.
+- * Since quota tags are part of transactions, there is no need to a quota check
++ * Since quota tags are part of transactions, there is no need for a quota check
+ * program to be run on node crashes or anything like that.
+ *
+ * There are couple of knobs that let the administrator manage the quota
+@@ -65,13 +65,6 @@
+ #define QUOTA_USER 1
+ #define QUOTA_GROUP 0
+
+-struct gfs2_quota_host {
+- u64 qu_limit;
+- u64 qu_warn;
+- s64 qu_value;
+- u32 qu_ll_next;
+-};
+-
+ struct gfs2_quota_change_host {
+ u64 qc_change;
+ u32 qc_flags; /* GFS2_QCF_... */
+@@ -573,33 +566,19 @@ static void do_qc(struct gfs2_quota_data *qd, s64 change)
+ mutex_unlock(&sdp->sd_quota_mutex);
+ }
+
+-static void gfs2_quota_in(struct gfs2_quota_host *qu, const void *buf)
+-{
+- const struct gfs2_quota *str = buf;
+-
+- qu->qu_limit = be64_to_cpu(str->qu_limit);
+- qu->qu_warn = be64_to_cpu(str->qu_warn);
+- qu->qu_value = be64_to_cpu(str->qu_value);
+- qu->qu_ll_next = be32_to_cpu(str->qu_ll_next);
+-}
+-
+-static void gfs2_quota_out(const struct gfs2_quota_host *qu, void *buf)
+-{
+- struct gfs2_quota *str = buf;
+-
+- str->qu_limit = cpu_to_be64(qu->qu_limit);
+- str->qu_warn = cpu_to_be64(qu->qu_warn);
+- str->qu_value = cpu_to_be64(qu->qu_value);
+- str->qu_ll_next = cpu_to_be32(qu->qu_ll_next);
+- memset(&str->qu_reserved, 0, sizeof(str->qu_reserved));
+-}
+-
+ /**
+- * gfs2_adjust_quota
++ * gfs2_adjust_quota - adjust record of current block usage
++ * @ip: The quota inode
++ * @loc: Offset of the entry in the quota file
++ * @change: The amount of change to record
++ * @qd: The quota data
+ *
+ * This function was mostly borrowed from gfs2_block_truncate_page which was
+ * in turn mostly borrowed from ext3
++ *
++ * Returns: 0 or -ve on error
+ */
++
+ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
+ s64 change, struct gfs2_quota_data *qd)
+ {
+@@ -611,8 +590,7 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
+ struct buffer_head *bh;
+ struct page *page;
+ void *kaddr;
+- char *ptr;
+- struct gfs2_quota_host qp;
++ struct gfs2_quota *qp;
+ s64 value;
+ int err = -EIO;
+
+@@ -656,18 +634,13 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
+ gfs2_trans_add_bh(ip->i_gl, bh, 0);
+
+ kaddr = kmap_atomic(page, KM_USER0);
+- ptr = kaddr + offset;
+- gfs2_quota_in(&qp, ptr);
+- qp.qu_value += change;
+- value = qp.qu_value;
+- gfs2_quota_out(&qp, ptr);
++ qp = kaddr + offset;
++ value = (s64)be64_to_cpu(qp->qu_value) + change;
++ qp->qu_value = cpu_to_be64(value);
++ qd->qd_qb.qb_value = qp->qu_value;
+ flush_dcache_page(page);
+ kunmap_atomic(kaddr, KM_USER0);
+ err = 0;
+- qd->qd_qb.qb_magic = cpu_to_be32(GFS2_MAGIC);
+- qd->qd_qb.qb_value = cpu_to_be64(value);
+- ((struct gfs2_quota_lvb*)(qd->qd_gl->gl_lvb))->qb_magic = cpu_to_be32(GFS2_MAGIC);
+- ((struct gfs2_quota_lvb*)(qd->qd_gl->gl_lvb))->qb_value = cpu_to_be64(value);
+ unlock:
+ unlock_page(page);
+ page_cache_release(page);
+@@ -696,8 +669,7 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
+
+ sort(qda, num_qd, sizeof(struct gfs2_quota_data *), sort_qd, NULL);
+ for (qx = 0; qx < num_qd; qx++) {
+- error = gfs2_glock_nq_init(qda[qx]->qd_gl,
+- LM_ST_EXCLUSIVE,
++ error = gfs2_glock_nq_init(qda[qx]->qd_gl, LM_ST_EXCLUSIVE,
+ GL_NOCACHE, &ghs[qx]);
+ if (error)
+ goto out;
+@@ -752,8 +724,7 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
+ qd = qda[x];
+ offset = qd2offset(qd);
+ error = gfs2_adjust_quota(ip, offset, qd->qd_change_sync,
+- (struct gfs2_quota_data *)
+- qd);
++ (struct gfs2_quota_data *)qd);
+ if (error)
+ goto out_end_trans;
+
+@@ -784,8 +755,7 @@ static int do_glock(struct gfs2_quota_data *qd, int force_refresh,
+ struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
+ struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode);
+ struct gfs2_holder i_gh;
+- struct gfs2_quota_host q;
+- char buf[sizeof(struct gfs2_quota)];
++ struct gfs2_quota q;
+ int error;
+ struct gfs2_quota_lvb *qlvb;
+
+@@ -809,23 +779,24 @@ restart:
+ if (error)
+ goto fail;
+
+- memset(buf, 0, sizeof(struct gfs2_quota));
++ memset(&q, 0, sizeof(struct gfs2_quota));
+ pos = qd2offset(qd);
+- error = gfs2_internal_read(ip, NULL, buf, &pos,
+- sizeof(struct gfs2_quota));
++ error = gfs2_internal_read(ip, NULL, (char *)&q, &pos, sizeof(q));
+ if (error < 0)
+ goto fail_gunlock;
+-
++ if ((error < sizeof(q)) && force_refresh) {
++ error = -ENOENT;
++ goto fail_gunlock;
++ }
+ gfs2_glock_dq_uninit(&i_gh);
+
+
+- gfs2_quota_in(&q, buf);
+ qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb;
+ qlvb->qb_magic = cpu_to_be32(GFS2_MAGIC);
+ qlvb->__pad = 0;
+- qlvb->qb_limit = cpu_to_be64(q.qu_limit);
+- qlvb->qb_warn = cpu_to_be64(q.qu_warn);
+- qlvb->qb_value = cpu_to_be64(q.qu_value);
++ qlvb->qb_limit = q.qu_limit;
++ qlvb->qb_warn = q.qu_warn;
++ qlvb->qb_value = q.qu_value;
+ qd->qd_qb = *qlvb;
+
+ if (gfs2_glock_is_blocking(qd->qd_gl)) {
+@@ -1084,7 +1055,6 @@ int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, u32 id)
+ gfs2_glock_dq_uninit(&q_gh);
+
+ qd_put(qd);
+-
+ return error;
+ }
+
Added: dists/lenny/linux-2.6/debian/patches/bugfix/all/gfs2-fix-writing-to-non-page-aligned-gfs2_quota-structures.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/lenny/linux-2.6/debian/patches/bugfix/all/gfs2-fix-writing-to-non-page-aligned-gfs2_quota-structures.patch Sat Jun 12 01:39:04 2010 (r15859)
@@ -0,0 +1,125 @@
+commit 401a4f6656ed755b17e865abe0b0797c17f473c3
+Author: Abhijith Das <adas at redhat.com>
+Date: Fri May 7 17:50:18 2010 -0400
+
+ GFS2: Fix writing to non-page aligned gfs2_quota structures
+
+ This is the upstream fix for this bug. This patch differs
+ from the RHEL5 fix (Red Hat bz #555754) which simply writes to the 8-byte
+ value field of the quota. In upstream quota code, we're
+ required to write the entire quota (88 bytes) which can be split
+ across a page boundary. We check for such quotas, and read/write
+ the two parts from/to the corresponding pages holding these parts.
+
+ With this patch, I don't see the bug anymore using the reproducer
+ in Red Hat bz 555754. I successfully ran a couple of simple tests/mounts/
+ umounts and it doesn't seem like this patch breaks anything else.
+
+ [Backported to Debian's 2.6.26 by dann frazier <dannf at debian.org>]
+ Signed-off-by: Abhi Das <adas at redhat.com>
+ Signed-off-by: Steven Whitehouse <swhiteho at redhat.com>
+
+diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
+index 1e4d248..b366186 100644
+--- a/fs/gfs2/quota.c
++++ b/fs/gfs2/quota.c
+@@ -589,14 +589,29 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
+ unsigned blocksize, iblock, pos;
+ struct buffer_head *bh;
+ struct page *page;
+- void *kaddr;
+- struct gfs2_quota *qp;
+- s64 value;
+- int err = -EIO;
++ void *kaddr, *ptr;
++ struct gfs2_quota q, *qp;
++ int err, nbytes;
+
+ if (gfs2_is_stuffed(ip))
+ gfs2_unstuff_dinode(ip, NULL);
+-
++
++ memset(&q, 0, sizeof(struct gfs2_quota));
++ err = gfs2_internal_read(ip, NULL, (char *)&q, &loc, sizeof(q));
++ if (err < 0)
++ return err;
++
++ err = -EIO;
++ qp = &q;
++ qp->qu_value = be64_to_cpu(qp->qu_value);
++ qp->qu_value += change;
++ qp->qu_value = cpu_to_be64(qp->qu_value);
++ qd->qd_qb.qb_value = qp->qu_value;
++
++ /* Write the quota into the quota file on disk */
++ ptr = qp;
++ nbytes = sizeof(struct gfs2_quota);
++get_a_page:
+ page = grab_cache_page(mapping, index);
+ if (!page)
+ return -ENOMEM;
+@@ -618,7 +633,12 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
+ if (!buffer_mapped(bh)) {
+ gfs2_block_map(inode, iblock, bh, 1);
+ if (!buffer_mapped(bh))
+- goto unlock;
++ goto unlock_out;
++ /* If it's a newly allocated disk block for quota, zero it */
++ if (buffer_new(bh)) {
++ memset(bh->b_data, 0, bh->b_size);
++ set_buffer_uptodate(bh);
++ }
+ }
+
+ if (PageUptodate(page))
+@@ -628,20 +648,31 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
+ ll_rw_block(READ_META, 1, &bh);
+ wait_on_buffer(bh);
+ if (!buffer_uptodate(bh))
+- goto unlock;
++ goto unlock_out;
+ }
+
+ gfs2_trans_add_bh(ip->i_gl, bh, 0);
+
+ kaddr = kmap_atomic(page, KM_USER0);
+- qp = kaddr + offset;
+- value = (s64)be64_to_cpu(qp->qu_value) + change;
+- qp->qu_value = cpu_to_be64(value);
+- qd->qd_qb.qb_value = qp->qu_value;
++ if (offset + sizeof(struct gfs2_quota) > PAGE_CACHE_SIZE)
++ nbytes = PAGE_CACHE_SIZE - offset;
++ memcpy(kaddr + offset, ptr, nbytes);
+ flush_dcache_page(page);
+ kunmap_atomic(kaddr, KM_USER0);
++ unlock_page(page);
++ page_cache_release(page);
++
++ /* If quota straddles page boundary, we need to update the rest of the
++ * quota at the beginning of the next page */
++ if (offset != 0) { /* first page, offset is closer to PAGE_CACHE_SIZE */
++ ptr = ptr + nbytes;
++ nbytes = sizeof(struct gfs2_quota) - nbytes;
++ offset = 0;
++ index++;
++ goto get_a_page;
++ }
+ err = 0;
+-unlock:
++unlock_out:
+ unlock_page(page);
+ page_cache_release(page);
+ return err;
+@@ -704,8 +735,10 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
+ * rgrp since it won't be allocated during the transaction
+ */
+ al->al_requested = 1;
+- /* +1 in the end for block requested above for unstuffing */
+- blocks = num_qd * data_blocks + RES_DINODE + num_qd + 1;
++ /* +3 in the end for unstuffing block, inode size update block
++ * and another block in case quota straddles page boundary and
++ * two blocks need to be updated instead of 1 */
++ blocks = num_qd * data_blocks + RES_DINODE + num_qd + 3;
+
+ if (nalloc)
+ al->al_requested += nalloc * (data_blocks + ind_blocks);
Modified: dists/lenny/linux-2.6/debian/patches/series/23
==============================================================================
--- dists/lenny/linux-2.6/debian/patches/series/23 Sat Jun 12 00:47:19 2010 (r15858)
+++ dists/lenny/linux-2.6/debian/patches/series/23 Sat Jun 12 01:39:04 2010 (r15859)
@@ -16,3 +16,5 @@
+ bugfix/all/nfsd-fix-vm-overcommit-crash.patch
+ bugfix/all/nfsd-fix-vm-overcommit-crash-2.patch
+ bugfix/all/gfs2-fix-perm-checking-for-setflags-ioctl.patch
++ bugfix/all/gfs2-clean-up-gfs2_adjust_quota-and-do_glock.patch
++ bugfix/all/gfs2-fix-writing-to-non-page-aligned-gfs2_quota-structures.patch
More information about the Kernel-svn-changes
mailing list