[kernel] r16844 - in dists/sid/linux-2.6/debian: . patches/bugfix/all patches/features/all/vserver patches/series
Dann Frazier
dannf at alioth.debian.org
Sun Jan 23 17:44:54 UTC 2011
Author: dannf
Date: Sun Jan 23 17:44:49 2011
New Revision: 16844
Log:
xfs: fix information leak using stale NFS handle (CVE-2010-2943)
Added:
dists/sid/linux-2.6/debian/patches/bugfix/all/xfs-always-use-iget-in-bulkstat.patch
dists/sid/linux-2.6/debian/patches/bugfix/all/xfs-fix-untrusted-inode-number-lookup.patch
dists/sid/linux-2.6/debian/patches/bugfix/all/xfs-remove-block-number-from-inode-lookup-code.patch
dists/sid/linux-2.6/debian/patches/bugfix/all/xfs-rename-XFS_IGET_BULKSTAT-to-XFS_IGET_UNTRUSTED.patch
dists/sid/linux-2.6/debian/patches/bugfix/all/xfs-validate-untrusted-inode-numbers-during-lookup.patch
Modified:
dists/sid/linux-2.6/debian/changelog
dists/sid/linux-2.6/debian/patches/features/all/vserver/vs2.3.0.36.29.6.patch
dists/sid/linux-2.6/debian/patches/series/31
Modified: dists/sid/linux-2.6/debian/changelog
==============================================================================
--- dists/sid/linux-2.6/debian/changelog Sun Jan 23 07:46:48 2011 (r16843)
+++ dists/sid/linux-2.6/debian/changelog Sun Jan 23 17:44:49 2011 (r16844)
@@ -12,6 +12,9 @@
* bonding: Ensure that we unshare skbs prior to calling pskb_may_pull
(Closes: #610838)
+ [ dann frazier ]
+ * xfs: fix information leak using stale NFS handle (CVE-2010-2943)
+
-- Ian Campbell <ijc at hellion.org.uk> Thu, 13 Jan 2011 07:07:54 +0000
linux-2.6 (2.6.32-30) unstable; urgency=high
Added: dists/sid/linux-2.6/debian/patches/bugfix/all/xfs-always-use-iget-in-bulkstat.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/bugfix/all/xfs-always-use-iget-in-bulkstat.patch Sun Jan 23 17:44:49 2011 (r16844)
@@ -0,0 +1,578 @@
+commit 7dce11dbac54fce777eea0f5fb25b2694ccd7900
+Author: Christoph Hellwig <hch at lst.de>
+Date: Wed Jun 23 18:11:11 2010 +1000
+
+ xfs: always use iget in bulkstat
+
+ The non-coherent bulkstat versionsthat look directly at the inode
+ buffers causes various problems with performance optimizations that
+ make increased use of just logging inodes. This patch makes bulkstat
+ always use iget, which should be fast enough for normal use with the
+ radix-tree based inode cache introduced a while ago.
+
+ Signed-off-by: Christoph Hellwig <hch at lst.de>
+ Reviewed-by: Dave Chinner <dchinner at redhat.com>
+ [dannf: backported Debian's 2.6.32]
+
+diff -urpN a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c
+--- a/fs/xfs/linux-2.6/xfs_ioctl32.c 2009-12-02 20:51:21.000000000 -0700
++++ b/fs/xfs/linux-2.6/xfs_ioctl32.c 2011-01-06 23:21:18.179043006 -0700
+@@ -235,15 +235,13 @@ xfs_bulkstat_one_compat(
+ xfs_ino_t ino, /* inode number to get data for */
+ void __user *buffer, /* buffer to place output in */
+ int ubsize, /* size of buffer */
+- void *private_data, /* my private data */
+ xfs_daddr_t bno, /* starting bno of inode cluster */
+ int *ubused, /* bytes used by me */
+- void *dibuff, /* on-disk inode buffer */
+ int *stat) /* BULKSTAT_RV_... */
+ {
+ return xfs_bulkstat_one_int(mp, ino, buffer, ubsize,
+ xfs_bulkstat_one_fmt_compat, bno,
+- ubused, dibuff, stat);
++ ubused, stat);
+ }
+
+ /* copied from xfs_ioctl.c */
+@@ -296,13 +294,11 @@ xfs_compat_ioc_bulkstat(
+ int res;
+
+ error = xfs_bulkstat_one_compat(mp, inlast, bulkreq.ubuffer,
+- sizeof(compat_xfs_bstat_t),
+- NULL, 0, NULL, NULL, &res);
++ sizeof(compat_xfs_bstat_t), 0, NULL, &res);
+ } else if (cmd == XFS_IOC_FSBULKSTAT_32) {
+ error = xfs_bulkstat(mp, &inlast, &count,
+- xfs_bulkstat_one_compat, NULL,
+- sizeof(compat_xfs_bstat_t), bulkreq.ubuffer,
+- BULKSTAT_FG_QUICK, &done);
++ xfs_bulkstat_one_compat, sizeof(compat_xfs_bstat_t),
++ bulkreq.ubuffer, &done);
+ } else
+ error = XFS_ERROR(EINVAL);
+ if (error)
+diff -urpN a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c
+--- a/fs/xfs/linux-2.6/xfs_ioctl.c 2010-12-09 23:03:20.000000000 -0700
++++ b/fs/xfs/linux-2.6/xfs_ioctl.c 2011-01-06 23:21:18.179043006 -0700
+@@ -673,10 +673,9 @@ xfs_ioc_bulkstat(
+ error = xfs_bulkstat_single(mp, &inlast,
+ bulkreq.ubuffer, &done);
+ else /* XFS_IOC_FSBULKSTAT */
+- error = xfs_bulkstat(mp, &inlast, &count,
+- (bulkstat_one_pf)xfs_bulkstat_one, NULL,
+- sizeof(xfs_bstat_t), bulkreq.ubuffer,
+- BULKSTAT_FG_QUICK, &done);
++ error = xfs_bulkstat(mp, &inlast, &count, xfs_bulkstat_one,
++ sizeof(xfs_bstat_t), bulkreq.ubuffer,
++ &done);
+
+ if (error)
+ return -error;
+diff -urpN a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c
+--- a/fs/xfs/quota/xfs_qm.c 2009-12-02 20:51:21.000000000 -0700
++++ b/fs/xfs/quota/xfs_qm.c 2011-01-06 23:21:18.191181368 -0700
+@@ -1606,10 +1606,8 @@ xfs_qm_dqusage_adjust(
+ xfs_ino_t ino, /* inode number to get data for */
+ void __user *buffer, /* not used */
+ int ubsize, /* not used */
+- void *private_data, /* not used */
+ xfs_daddr_t bno, /* starting block of inode cluster */
+ int *ubused, /* not used */
+- void *dip, /* on-disk inode pointer (not used) */
+ int *res) /* result code value */
+ {
+ xfs_inode_t *ip;
+@@ -1766,12 +1764,13 @@ xfs_qm_quotacheck(
+ * Iterate thru all the inodes in the file system,
+ * adjusting the corresponding dquot counters in core.
+ */
+- if ((error = xfs_bulkstat(mp, &lastino, &count,
+- xfs_qm_dqusage_adjust, NULL,
+- structsz, NULL, BULKSTAT_FG_IGET, &done)))
++ error = xfs_bulkstat(mp, &lastino, &count,
++ xfs_qm_dqusage_adjust,
++ structsz, NULL, &done);
++ if (error)
+ break;
+
+- } while (! done);
++ } while (!done);
+
+ /*
+ * We've made all the changes that we need to make incore.
+diff -urpN a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/quota/xfs_qm_syscalls.c
+--- a/fs/xfs/quota/xfs_qm_syscalls.c 2010-12-09 23:02:43.000000000 -0700
++++ b/fs/xfs/quota/xfs_qm_syscalls.c 2011-01-06 23:21:18.202690146 -0700
+@@ -1114,10 +1114,8 @@ xfs_qm_internalqcheck_adjust(
+ xfs_ino_t ino, /* inode number to get data for */
+ void __user *buffer, /* not used */
+ int ubsize, /* not used */
+- void *private_data, /* not used */
+ xfs_daddr_t bno, /* starting block of inode cluster */
+ int *ubused, /* not used */
+- void *dip, /* not used */
+ int *res) /* bulkstat result code */
+ {
+ xfs_inode_t *ip;
+@@ -1212,15 +1210,15 @@ xfs_qm_internalqcheck(
+ * Iterate thru all the inodes in the file system,
+ * adjusting the corresponding dquot counters
+ */
+- if ((error = xfs_bulkstat(mp, &lastino, &count,
+- xfs_qm_internalqcheck_adjust, NULL,
+- 0, NULL, BULKSTAT_FG_IGET, &done))) {
++ error = xfs_bulkstat(mp, &lastino, &count,
++ xfs_qm_internalqcheck_adjust,
++ 0, NULL, &done);
++ if (error) {
++ cmn_err(CE_DEBUG, "Bulkstat returned error 0x%x", error);
+ break;
+ }
+- } while (! done);
+- if (error) {
+- cmn_err(CE_DEBUG, "Bulkstat returned error 0x%x", error);
+- }
++ } while (!done);
++
+ cmn_err(CE_DEBUG, "Checking results against system dquots");
+ for (i = 0; i < qmtest_hashmask; i++) {
+ h1 = &qmtest_udqtab[i];
+diff -urpN a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
+--- a/fs/xfs/xfs_itable.c 2009-12-02 20:51:21.000000000 -0700
++++ b/fs/xfs/xfs_itable.c 2011-01-06 23:23:53.162769761 -0700
+@@ -49,24 +49,41 @@ xfs_internal_inum(
+ (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino)));
+ }
+
+-STATIC int
+-xfs_bulkstat_one_iget(
+- xfs_mount_t *mp, /* mount point for filesystem */
+- xfs_ino_t ino, /* inode number to get data for */
+- xfs_daddr_t bno, /* starting bno of inode cluster */
+- xfs_bstat_t *buf, /* return buffer */
+- int *stat) /* BULKSTAT_RV_... */
++/*
++ * Return stat information for one inode.
++ * Return 0 if ok, else errno.
++ */
++int
++xfs_bulkstat_one_int(
++ struct xfs_mount *mp, /* mount point for filesystem */
++ xfs_ino_t ino, /* inode to get data for */
++ void __user *buffer, /* buffer to place output in */
++ int ubsize, /* size of buffer */
++ bulkstat_one_fmt_pf formatter, /* formatter, copy to user */
++ xfs_daddr_t bno, /* starting bno of cluster */
++ int *ubused, /* bytes used by me */
++ int *stat) /* BULKSTAT_RV_... */
+ {
+- xfs_icdinode_t *dic; /* dinode core info pointer */
+- xfs_inode_t *ip; /* incore inode pointer */
+- struct inode *inode;
+- int error;
++ struct xfs_icdinode *dic; /* dinode core info pointer */
++ struct xfs_inode *ip; /* incore inode pointer */
++ struct inode *inode;
++ struct xfs_bstat *buf; /* return buffer */
++ int error = 0; /* error value */
++
++ *stat = BULKSTAT_RV_NOTHING;
++
++ if (!buffer || xfs_internal_inum(mp, ino))
++ return XFS_ERROR(EINVAL);
++
++ buf = kmem_alloc(sizeof(*buf), KM_SLEEP | KM_MAYFAIL);
++ if (!buf)
++ return XFS_ERROR(ENOMEM);
+
+ error = xfs_iget(mp, NULL, ino,
+ XFS_IGET_BULKSTAT, XFS_ILOCK_SHARED, &ip, bno);
+ if (error) {
+ *stat = BULKSTAT_RV_NOTHING;
+- return error;
++ goto out_free;
+ }
+
+ ASSERT(ip != NULL);
+@@ -126,76 +143,16 @@ xfs_bulkstat_one_iget(
+ buf->bs_blocks = dic->di_nblocks + ip->i_delayed_blks;
+ break;
+ }
+-
+ xfs_iput(ip, XFS_ILOCK_SHARED);
+- return error;
+-}
+
+-STATIC void
+-xfs_bulkstat_one_dinode(
+- xfs_mount_t *mp, /* mount point for filesystem */
+- xfs_ino_t ino, /* inode number to get data for */
+- xfs_dinode_t *dic, /* dinode inode pointer */
+- xfs_bstat_t *buf) /* return buffer */
+-{
+- /*
+- * The inode format changed when we moved the link count and
+- * made it 32 bits long. If this is an old format inode,
+- * convert it in memory to look like a new one. If it gets
+- * flushed to disk we will convert back before flushing or
+- * logging it. We zero out the new projid field and the old link
+- * count field. We'll handle clearing the pad field (the remains
+- * of the old uuid field) when we actually convert the inode to
+- * the new format. We don't change the version number so that we
+- * can distinguish this from a real new format inode.
+- */
+- if (dic->di_version == 1) {
+- buf->bs_nlink = be16_to_cpu(dic->di_onlink);
+- buf->bs_projid = 0;
+- } else {
+- buf->bs_nlink = be32_to_cpu(dic->di_nlink);
+- buf->bs_projid = be16_to_cpu(dic->di_projid);
+- }
++ error = formatter(buffer, ubsize, ubused, buf);
+
+- buf->bs_ino = ino;
+- buf->bs_mode = be16_to_cpu(dic->di_mode);
+- buf->bs_uid = be32_to_cpu(dic->di_uid);
+- buf->bs_gid = be32_to_cpu(dic->di_gid);
+- buf->bs_size = be64_to_cpu(dic->di_size);
+- buf->bs_atime.tv_sec = be32_to_cpu(dic->di_atime.t_sec);
+- buf->bs_atime.tv_nsec = be32_to_cpu(dic->di_atime.t_nsec);
+- buf->bs_mtime.tv_sec = be32_to_cpu(dic->di_mtime.t_sec);
+- buf->bs_mtime.tv_nsec = be32_to_cpu(dic->di_mtime.t_nsec);
+- buf->bs_ctime.tv_sec = be32_to_cpu(dic->di_ctime.t_sec);
+- buf->bs_ctime.tv_nsec = be32_to_cpu(dic->di_ctime.t_nsec);
+- buf->bs_xflags = xfs_dic2xflags(dic);
+- buf->bs_extsize = be32_to_cpu(dic->di_extsize) << mp->m_sb.sb_blocklog;
+- buf->bs_extents = be32_to_cpu(dic->di_nextents);
+- buf->bs_gen = be32_to_cpu(dic->di_gen);
+- memset(buf->bs_pad, 0, sizeof(buf->bs_pad));
+- buf->bs_dmevmask = be32_to_cpu(dic->di_dmevmask);
+- buf->bs_dmstate = be16_to_cpu(dic->di_dmstate);
+- buf->bs_aextents = be16_to_cpu(dic->di_anextents);
++ if (!error)
++ *stat = BULKSTAT_RV_DIDONE;
+
+- switch (dic->di_format) {
+- case XFS_DINODE_FMT_DEV:
+- buf->bs_rdev = xfs_dinode_get_rdev(dic);
+- buf->bs_blksize = BLKDEV_IOSIZE;
+- buf->bs_blocks = 0;
+- break;
+- case XFS_DINODE_FMT_LOCAL:
+- case XFS_DINODE_FMT_UUID:
+- buf->bs_rdev = 0;
+- buf->bs_blksize = mp->m_sb.sb_blocksize;
+- buf->bs_blocks = 0;
+- break;
+- case XFS_DINODE_FMT_EXTENTS:
+- case XFS_DINODE_FMT_BTREE:
+- buf->bs_rdev = 0;
+- buf->bs_blksize = mp->m_sb.sb_blocksize;
+- buf->bs_blocks = be64_to_cpu(dic->di_nblocks);
+- break;
+- }
++ out_free:
++ kmem_free(buf);
++ return error;
+ }
+
+ /* Return 0 on success or positive error */
+@@ -215,118 +172,19 @@ xfs_bulkstat_one_fmt(
+ return 0;
+ }
+
+-/*
+- * Return stat information for one inode.
+- * Return 0 if ok, else errno.
+- */
+-int /* error status */
+-xfs_bulkstat_one_int(
+- xfs_mount_t *mp, /* mount point for filesystem */
+- xfs_ino_t ino, /* inode number to get data for */
+- void __user *buffer, /* buffer to place output in */
+- int ubsize, /* size of buffer */
+- bulkstat_one_fmt_pf formatter, /* formatter, copy to user */
+- xfs_daddr_t bno, /* starting bno of inode cluster */
+- int *ubused, /* bytes used by me */
+- void *dibuff, /* on-disk inode buffer */
+- int *stat) /* BULKSTAT_RV_... */
+-{
+- xfs_bstat_t *buf; /* return buffer */
+- int error = 0; /* error value */
+- xfs_dinode_t *dip; /* dinode inode pointer */
+-
+- dip = (xfs_dinode_t *)dibuff;
+- *stat = BULKSTAT_RV_NOTHING;
+-
+- if (!buffer || xfs_internal_inum(mp, ino))
+- return XFS_ERROR(EINVAL);
+-
+- buf = kmem_alloc(sizeof(*buf), KM_SLEEP);
+-
+- if (dip == NULL) {
+- /* We're not being passed a pointer to a dinode. This happens
+- * if BULKSTAT_FG_IGET is selected. Do the iget.
+- */
+- error = xfs_bulkstat_one_iget(mp, ino, bno, buf, stat);
+- if (error)
+- goto out_free;
+- } else {
+- xfs_bulkstat_one_dinode(mp, ino, dip, buf);
+- }
+-
+- error = formatter(buffer, ubsize, ubused, buf);
+- if (error)
+- goto out_free;
+-
+- *stat = BULKSTAT_RV_DIDONE;
+-
+- out_free:
+- kmem_free(buf);
+- return error;
+-}
+-
+ int
+ xfs_bulkstat_one(
+ xfs_mount_t *mp, /* mount point for filesystem */
+ xfs_ino_t ino, /* inode number to get data for */
+ void __user *buffer, /* buffer to place output in */
+ int ubsize, /* size of buffer */
+- void *private_data, /* my private data */
+ xfs_daddr_t bno, /* starting bno of inode cluster */
+ int *ubused, /* bytes used by me */
+- void *dibuff, /* on-disk inode buffer */
+ int *stat) /* BULKSTAT_RV_... */
+ {
+ return xfs_bulkstat_one_int(mp, ino, buffer, ubsize,
+ xfs_bulkstat_one_fmt, bno,
+- ubused, dibuff, stat);
+-}
+-
+-/*
+- * Test to see whether we can use the ondisk inode directly, based
+- * on the given bulkstat flags, filling in dipp accordingly.
+- * Returns zero if the inode is dodgey.
+- */
+-STATIC int
+-xfs_bulkstat_use_dinode(
+- xfs_mount_t *mp,
+- int flags,
+- xfs_buf_t *bp,
+- int clustidx,
+- xfs_dinode_t **dipp)
+-{
+- xfs_dinode_t *dip;
+- unsigned int aformat;
+-
+- *dipp = NULL;
+- if (!bp || (flags & BULKSTAT_FG_IGET))
+- return 1;
+- dip = (xfs_dinode_t *)
+- xfs_buf_offset(bp, clustidx << mp->m_sb.sb_inodelog);
+- /*
+- * Check the buffer containing the on-disk inode for di_mode == 0.
+- * This is to prevent xfs_bulkstat from picking up just reclaimed
+- * inodes that have their in-core state initialized but not flushed
+- * to disk yet. This is a temporary hack that would require a proper
+- * fix in the future.
+- */
+- if (be16_to_cpu(dip->di_magic) != XFS_DINODE_MAGIC ||
+- !XFS_DINODE_GOOD_VERSION(dip->di_version) ||
+- !dip->di_mode)
+- return 0;
+- if (flags & BULKSTAT_FG_QUICK) {
+- *dipp = dip;
+- return 1;
+- }
+- /* BULKSTAT_FG_INLINE: if attr fork is local, or not there, use it */
+- aformat = dip->di_aformat;
+- if ((XFS_DFORK_Q(dip) == 0) ||
+- (aformat == XFS_DINODE_FMT_LOCAL) ||
+- (aformat == XFS_DINODE_FMT_EXTENTS && !dip->di_anextents)) {
+- *dipp = dip;
+- return 1;
+- }
+- return 1;
++ ubused, stat);
+ }
+
+ #define XFS_BULKSTAT_UBLEFT(ubleft) ((ubleft) >= statstruct_size)
+@@ -340,10 +198,8 @@ xfs_bulkstat(
+ xfs_ino_t *lastinop, /* last inode returned */
+ int *ubcountp, /* size of buffer/count returned */
+ bulkstat_one_pf formatter, /* func that'd fill a single buf */
+- void *private_data,/* private data for formatter */
+ size_t statstruct_size, /* sizeof struct filling */
+ char __user *ubuffer, /* buffer with inode stats */
+- int flags, /* defined in xfs_itable.h */
+ int *done) /* 1 if there are more stats to get */
+ {
+ xfs_agblock_t agbno=0;/* allocation group block number */
+@@ -378,14 +234,12 @@ xfs_bulkstat(
+ int ubelem; /* spaces used in user's buffer */
+ int ubused; /* bytes used by formatter */
+ xfs_buf_t *bp; /* ptr to on-disk inode cluster buf */
+- xfs_dinode_t *dip; /* ptr into bp for specific inode */
+
+ /*
+ * Get the last inode value, see if there's nothing to do.
+ */
+ ino = (xfs_ino_t)*lastinop;
+ lastino = ino;
+- dip = NULL;
+ agno = XFS_INO_TO_AGNO(mp, ino);
+ agino = XFS_INO_TO_AGINO(mp, ino);
+ if (agno >= mp->m_sb.sb_agcount ||
+@@ -610,37 +464,6 @@ xfs_bulkstat(
+ irbp->ir_startino) +
+ ((chunkidx & nimask) >>
+ mp->m_sb.sb_inopblog);
+-
+- if (flags & (BULKSTAT_FG_QUICK |
+- BULKSTAT_FG_INLINE)) {
+- int offset;
+-
+- ino = XFS_AGINO_TO_INO(mp, agno,
+- agino);
+- bno = XFS_AGB_TO_DADDR(mp, agno,
+- agbno);
+-
+- /*
+- * Get the inode cluster buffer
+- */
+- if (bp)
+- xfs_buf_relse(bp);
+-
+- error = xfs_inotobp(mp, NULL, ino, &dip,
+- &bp, &offset,
+- XFS_IGET_BULKSTAT);
+-
+- if (!error)
+- clustidx = offset / mp->m_sb.sb_inodesize;
+- if (XFS_TEST_ERROR(error != 0,
+- mp, XFS_ERRTAG_BULKSTAT_READ_CHUNK,
+- XFS_RANDOM_BULKSTAT_READ_CHUNK)) {
+- bp = NULL;
+- ubleft = 0;
+- rval = error;
+- break;
+- }
+- }
+ }
+ ino = XFS_AGINO_TO_INO(mp, agno, agino);
+ bno = XFS_AGB_TO_DADDR(mp, agno, agbno);
+@@ -656,35 +479,13 @@ xfs_bulkstat(
+ * when the chunk is used up.
+ */
+ irbp->ir_freecount++;
+- if (!xfs_bulkstat_use_dinode(mp, flags, bp,
+- clustidx, &dip)) {
+- lastino = ino;
+- continue;
+- }
+- /*
+- * If we need to do an iget, cannot hold bp.
+- * Drop it, until starting the next cluster.
+- */
+- if ((flags & BULKSTAT_FG_INLINE) && !dip) {
+- if (bp)
+- xfs_buf_relse(bp);
+- bp = NULL;
+- }
+
+ /*
+ * Get the inode and fill in a single buffer.
+- * BULKSTAT_FG_QUICK uses dip to fill it in.
+- * BULKSTAT_FG_IGET uses igets.
+- * BULKSTAT_FG_INLINE uses dip if we have an
+- * inline attr fork, else igets.
+- * See: xfs_bulkstat_one & xfs_dm_bulkstat_one.
+- * This is also used to count inodes/blks, etc
+- * in xfs_qm_quotacheck.
+ */
+ ubused = statstruct_size;
+- error = formatter(mp, ino, ubufp,
+- ubleft, private_data,
+- bno, &ubused, dip, &fmterror);
++ error = formatter(mp, ino, ubufp, ubleft, bno,
++ &ubused, &fmterror);
+ if (fmterror == BULKSTAT_RV_NOTHING) {
+ if (error && error != ENOENT &&
+ error != EINVAL) {
+@@ -777,7 +578,7 @@ xfs_bulkstat_single(
+
+ ino = (xfs_ino_t)*lastinop;
+ error = xfs_bulkstat_one(mp, ino, buffer, sizeof(xfs_bstat_t),
+- NULL, 0, NULL, NULL, &res);
++ 0, NULL, &res);
+ if (error) {
+ /*
+ * Special case way failed, do it the "long" way
+@@ -786,8 +587,7 @@ xfs_bulkstat_single(
+ (*lastinop)--;
+ count = 1;
+ if (xfs_bulkstat(mp, lastinop, &count, xfs_bulkstat_one,
+- NULL, sizeof(xfs_bstat_t), buffer,
+- BULKSTAT_FG_IGET, done))
++ sizeof(xfs_bstat_t), buffer, done))
+ return error;
+ if (count == 0 || (xfs_ino_t)*lastinop != ino)
+ return error == EFSCORRUPTED ?
+diff -urpN a/fs/xfs/xfs_itable.h b/fs/xfs/xfs_itable.h
+--- a/fs/xfs/xfs_itable.h 2009-12-02 20:51:21.000000000 -0700
++++ b/fs/xfs/xfs_itable.h 2011-01-06 23:21:18.215182315 -0700
+@@ -27,10 +27,8 @@ typedef int (*bulkstat_one_pf)(struct xf
+ xfs_ino_t ino,
+ void __user *buffer,
+ int ubsize,
+- void *private_data,
+ xfs_daddr_t bno,
+ int *ubused,
+- void *dip,
+ int *stat);
+
+ /*
+@@ -41,13 +39,6 @@ typedef int (*bulkstat_one_pf)(struct xf
+ #define BULKSTAT_RV_GIVEUP 2
+
+ /*
+- * Values for bulkstat flag argument.
+- */
+-#define BULKSTAT_FG_IGET 0x1 /* Go through the buffer cache */
+-#define BULKSTAT_FG_QUICK 0x2 /* No iget, walk the dinode cluster */
+-#define BULKSTAT_FG_INLINE 0x4 /* No iget if inline attrs */
+-
+-/*
+ * Return stat information in bulk (by-inode) for the filesystem.
+ */
+ int /* error status */
+@@ -56,10 +47,8 @@ xfs_bulkstat(
+ xfs_ino_t *lastino, /* last inode returned */
+ int *count, /* size of buffer/count returned */
+ bulkstat_one_pf formatter, /* func that'd fill a single buf */
+- void *private_data, /* private data for formatter */
+ size_t statstruct_size,/* sizeof struct that we're filling */
+ char __user *ubuffer,/* buffer with inode stats */
+- int flags, /* flag to control access method */
+ int *done); /* 1 if there are more stats to get */
+
+ int
+@@ -84,7 +73,6 @@ xfs_bulkstat_one_int(
+ bulkstat_one_fmt_pf formatter,
+ xfs_daddr_t bno,
+ int *ubused,
+- void *dibuff,
+ int *stat);
+
+ int
+@@ -93,10 +81,8 @@ xfs_bulkstat_one(
+ xfs_ino_t ino,
+ void __user *buffer,
+ int ubsize,
+- void *private_data,
+ xfs_daddr_t bno,
+ int *ubused,
+- void *dibuff,
+ int *stat);
+
+ typedef int (*inumbers_fmt_pf)(
Added: dists/sid/linux-2.6/debian/patches/bugfix/all/xfs-fix-untrusted-inode-number-lookup.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/bugfix/all/xfs-fix-untrusted-inode-number-lookup.patch Sun Jan 23 17:44:49 2011 (r16844)
@@ -0,0 +1,69 @@
+commit 4536f2ad8b330453d7ebec0746c4374eadd649b1
+Author: Dave Chinner <dchinner at redhat.com>
+Date: Tue Aug 24 11:42:30 2010 +1000
+
+ xfs: fix untrusted inode number lookup
+
+ Commit 7124fe0a5b619d65b739477b3b55a20bf805b06d ("xfs: validate untrusted inode
+ numbers during lookup") changes the inode lookup code to do btree lookups for
+ untrusted inode numbers. This change made an invalid assumption about the
+ alignment of inodes and hence incorrectly calculated the first inode in the
+ cluster. As a result, some inode numbers were being incorrectly considered
+ invalid when they were actually valid.
+
+ The issue was not picked up by the xfstests suite because it always runs fsr
+ and dump (the two utilities that utilise the bulkstat interface) on cache hot
+ inodes and hence the lookup code in the cold cache path was not sufficiently
+ exercised to uncover this intermittent problem.
+
+ Fix the issue by relaxing the btree lookup criteria and then checking if the
+ record returned contains the inode number we are lookup for. If it we get an
+ incorrect record, then the inode number is invalid.
+
+ Cc: <stable at kernel.org>
+ Signed-off-by: Dave Chinner <dchinner at redhat.com>
+ Reviewed-by: Christoph Hellwig <hch at lst.de>
+ [dannf: adjusted to apply to Debian's 2.6.32]
+
+diff -urpN a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c
+--- a/fs/xfs/xfs_ialloc.c 2011-01-06 23:33:35.978687390 -0700
++++ b/fs/xfs/xfs_ialloc.c 2011-01-06 23:34:37.414682825 -0700
+@@ -1220,7 +1220,6 @@ xfs_imap_lookup(
+ struct xfs_inobt_rec_incore rec;
+ struct xfs_btree_cur *cur;
+ struct xfs_buf *agbp;
+- xfs_agino_t startino;
+ int error;
+ int i;
+
+@@ -1236,13 +1235,13 @@ xfs_imap_lookup(
+ }
+
+ /*
+- * derive and lookup the exact inode record for the given agino. If the
+- * record cannot be found, then it's an invalid inode number and we
+- * should abort.
++ * Lookup the inode record for the given agino. If the record cannot be
++ * found, then it's an invalid inode number and we should abort. Once
++ * we have a record, we need to ensure it contains the inode number
++ * we are looking up.
+ */
+ cur = xfs_inobt_init_cursor(mp, tp, agbp, agno);
+- startino = agino & ~(XFS_IALLOC_INODES(mp) - 1);
+- error = xfs_inobt_lookup(cur, startino, XFS_LOOKUP_EQ, &i);
++ error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &i);
+ if (!error) {
+ if (i)
+ error = xfs_inobt_get_rec(cur, &rec, &i);
+@@ -1255,6 +1254,11 @@ xfs_imap_lookup(
+ if (error)
+ return error;
+
++ /* check that the returned record contains the required inode */
++ if (rec.ir_startino > agino ||
++ rec.ir_startino + XFS_IALLOC_INODES(mp) <= agino)
++ return EINVAL;
++
+ /* for untrusted inodes check it is allocated first */
+ if ((flags & XFS_IGET_UNTRUSTED) &&
+ (rec.ir_free & XFS_INOBT_MASK(agino - rec.ir_startino)))
Added: dists/sid/linux-2.6/debian/patches/bugfix/all/xfs-remove-block-number-from-inode-lookup-code.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/bugfix/all/xfs-remove-block-number-from-inode-lookup-code.patch Sun Jan 23 17:44:49 2011 (r16844)
@@ -0,0 +1,408 @@
+commit 7b6259e7a83647948fa33a736cc832310c8d85aa
+Author: Dave Chinner <dchinner at redhat.com>
+Date: Thu Jun 24 11:35:17 2010 +1000
+
+ xfs: remove block number from inode lookup code
+
+ The block number comes from bulkstat based inode lookups to shortcut
+ the mapping calculations. We ar enot able to trust anything from
+ bulkstat, so drop the block number as well so that the correct
+ lookups and mappings are always done.
+
+ Signed-off-by: Dave Chinner <dchinner at redhat.com>
+ Reviewed-by: Christoph Hellwig <hch at lst.de>
+ [dannf: adjusted to apply to Debian's 2.6.32]
+
+diff -urpN a/fs/xfs/linux-2.6/xfs_export.c b/fs/xfs/linux-2.6/xfs_export.c
+--- a/fs/xfs/linux-2.6/xfs_export.c 2011-01-07 14:34:13.641212103 -0700
++++ b/fs/xfs/linux-2.6/xfs_export.c 2011-01-06 23:33:35.975182479 -0700
+@@ -132,7 +132,7 @@ xfs_nfs_get_inode(
+ * send invalid file handles and we have to handle it gracefully..
+ */
+ error = xfs_iget(mp, NULL, ino, XFS_IGET_UNTRUSTED,
+- XFS_ILOCK_SHARED, &ip, 0);
++ XFS_ILOCK_SHARED, &ip);
+ if (error) {
+ /*
+ * EINVAL means the inode cluster doesn't exist anymore.
+diff -urpN a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c
+--- a/fs/xfs/linux-2.6/xfs_ioctl32.c 2011-01-07 14:34:13.641212103 -0700
++++ b/fs/xfs/linux-2.6/xfs_ioctl32.c 2011-01-06 23:33:35.975182479 -0700
+@@ -235,12 +235,11 @@ xfs_bulkstat_one_compat(
+ xfs_ino_t ino, /* inode number to get data for */
+ void __user *buffer, /* buffer to place output in */
+ int ubsize, /* size of buffer */
+- xfs_daddr_t bno, /* starting bno of inode cluster */
+ int *ubused, /* bytes used by me */
+ int *stat) /* BULKSTAT_RV_... */
+ {
+ return xfs_bulkstat_one_int(mp, ino, buffer, ubsize,
+- xfs_bulkstat_one_fmt_compat, bno,
++ xfs_bulkstat_one_fmt_compat,
+ ubused, stat);
+ }
+
+@@ -294,7 +293,7 @@ xfs_compat_ioc_bulkstat(
+ int res;
+
+ error = xfs_bulkstat_one_compat(mp, inlast, bulkreq.ubuffer,
+- sizeof(compat_xfs_bstat_t), 0, NULL, &res);
++ sizeof(compat_xfs_bstat_t), 0, &res);
+ } else if (cmd == XFS_IOC_FSBULKSTAT_32) {
+ error = xfs_bulkstat(mp, &inlast, &count,
+ xfs_bulkstat_one_compat, sizeof(compat_xfs_bstat_t),
+diff -urpN a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c
+--- a/fs/xfs/quota/xfs_qm.c 2011-01-07 14:34:13.650271761 -0700
++++ b/fs/xfs/quota/xfs_qm.c 2011-01-06 23:33:35.978687390 -0700
+@@ -1606,7 +1606,6 @@ xfs_qm_dqusage_adjust(
+ xfs_ino_t ino, /* inode number to get data for */
+ void __user *buffer, /* not used */
+ int ubsize, /* not used */
+- xfs_daddr_t bno, /* starting block of inode cluster */
+ int *ubused, /* not used */
+ int *res) /* result code value */
+ {
+@@ -1632,7 +1631,7 @@ xfs_qm_dqusage_adjust(
+ * the case in all other instances. It's OK that we do this because
+ * quotacheck is done only at mount time.
+ */
+- if ((error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_EXCL, &ip, bno))) {
++ if ((error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_EXCL, &ip))) {
+ *res = BULKSTAT_RV_NOTHING;
+ return error;
+ }
+@@ -1858,14 +1857,14 @@ xfs_qm_init_quotainos(
+ mp->m_sb.sb_uquotino != NULLFSINO) {
+ ASSERT(mp->m_sb.sb_uquotino > 0);
+ if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
+- 0, 0, &uip, 0)))
++ 0, 0, &uip)))
+ return XFS_ERROR(error);
+ }
+ if (XFS_IS_OQUOTA_ON(mp) &&
+ mp->m_sb.sb_gquotino != NULLFSINO) {
+ ASSERT(mp->m_sb.sb_gquotino > 0);
+ if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
+- 0, 0, &gip, 0))) {
++ 0, 0, &gip))) {
+ if (uip)
+ IRELE(uip);
+ return XFS_ERROR(error);
+diff -urpN a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/quota/xfs_qm_syscalls.c
+--- a/fs/xfs/quota/xfs_qm_syscalls.c 2011-01-07 14:34:13.658211313 -0700
++++ b/fs/xfs/quota/xfs_qm_syscalls.c 2011-01-06 23:33:35.978687390 -0700
+@@ -266,7 +266,7 @@ xfs_qm_scall_trunc_qfiles(
+ }
+
+ if ((flags & XFS_DQ_USER) && mp->m_sb.sb_uquotino != NULLFSINO) {
+- error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, 0, 0, &qip, 0);
++ error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, 0, 0, &qip);
+ if (!error) {
+ error = xfs_truncate_file(mp, qip);
+ IRELE(qip);
+@@ -275,7 +275,7 @@ xfs_qm_scall_trunc_qfiles(
+
+ if ((flags & (XFS_DQ_GROUP|XFS_DQ_PROJ)) &&
+ mp->m_sb.sb_gquotino != NULLFSINO) {
+- error2 = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, 0, &qip, 0);
++ error2 = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, 0, &qip);
+ if (!error2) {
+ error2 = xfs_truncate_file(mp, qip);
+ IRELE(qip);
+@@ -420,12 +420,12 @@ xfs_qm_scall_getqstat(
+ }
+ if (!uip && mp->m_sb.sb_uquotino != NULLFSINO) {
+ if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
+- 0, 0, &uip, 0) == 0)
++ 0, 0, &uip) == 0)
+ tempuqip = B_TRUE;
+ }
+ if (!gip && mp->m_sb.sb_gquotino != NULLFSINO) {
+ if (xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
+- 0, 0, &gip, 0) == 0)
++ 0, 0, &gip) == 0)
+ tempgqip = B_TRUE;
+ }
+ if (uip) {
+@@ -1114,7 +1114,6 @@ xfs_qm_internalqcheck_adjust(
+ xfs_ino_t ino, /* inode number to get data for */
+ void __user *buffer, /* not used */
+ int ubsize, /* not used */
+- xfs_daddr_t bno, /* starting block of inode cluster */
+ int *ubused, /* not used */
+ int *res) /* bulkstat result code */
+ {
+@@ -1137,7 +1136,7 @@ xfs_qm_internalqcheck_adjust(
+ ipreleased = B_FALSE;
+ again:
+ lock_flags = XFS_ILOCK_SHARED;
+- if ((error = xfs_iget(mp, NULL, ino, 0, lock_flags, &ip, bno))) {
++ if ((error = xfs_iget(mp, NULL, ino, 0, lock_flags, &ip))) {
+ *res = BULKSTAT_RV_NOTHING;
+ return (error);
+ }
+diff -urpN a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c
+--- a/fs/xfs/xfs_ialloc.c 2011-01-07 14:34:13.661829343 -0700
++++ b/fs/xfs/xfs_ialloc.c 2011-01-07 14:33:32.849017988 -0700
+@@ -1360,22 +1360,6 @@ xfs_imap(
+ }
+
+ /*
+- * If we get a block number passed we can use it to
+- * find the buffer easily.
+- */
+- if (imap->im_blkno) {
+- offset = XFS_INO_TO_OFFSET(mp, ino);
+- ASSERT(offset < mp->m_sb.sb_inopblock);
+-
+- cluster_agbno = xfs_daddr_to_agbno(mp, imap->im_blkno);
+- offset += (agbno - cluster_agbno) * mp->m_sb.sb_inopblock;
+-
+- imap->im_len = XFS_FSB_TO_BB(mp, blks_per_cluster);
+- imap->im_boffset = (ushort)(offset << mp->m_sb.sb_inodelog);
+- return 0;
+- }
+-
+- /*
+ * If the inode chunks are aligned then use simple maths to
+ * find the location. Otherwise we have to do a btree
+ * lookup to find the location.
+diff -urpN a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c
+--- a/fs/xfs/xfs_iget.c 2011-01-07 14:34:13.666214425 -0700
++++ b/fs/xfs/xfs_iget.c 2011-01-06 23:33:35.983182739 -0700
+@@ -295,7 +295,6 @@ xfs_iget_cache_miss(
+ xfs_trans_t *tp,
+ xfs_ino_t ino,
+ struct xfs_inode **ipp,
+- xfs_daddr_t bno,
+ int flags,
+ int lock_flags) __releases(pag->pag_ici_lock)
+ {
+@@ -308,7 +307,7 @@ xfs_iget_cache_miss(
+ if (!ip)
+ return ENOMEM;
+
+- error = xfs_iread(mp, tp, ip, bno, flags);
++ error = xfs_iread(mp, tp, ip, flags);
+ if (error)
+ goto out_destroy;
+
+@@ -392,8 +391,6 @@ out_destroy:
+ * within the file system for the inode being requested.
+ * lock_flags -- flags indicating how to lock the inode. See the comment
+ * for xfs_ilock() for a list of valid values.
+- * bno -- the block number starting the buffer containing the inode,
+- * if known (as by bulkstat), else 0.
+ */
+ int
+ xfs_iget(
+@@ -402,8 +399,7 @@ xfs_iget(
+ xfs_ino_t ino,
+ uint flags,
+ uint lock_flags,
+- xfs_inode_t **ipp,
+- xfs_daddr_t bno)
++ xfs_inode_t **ipp)
+ {
+ xfs_inode_t *ip;
+ int error;
+@@ -434,7 +430,7 @@ again:
+ read_unlock(&pag->pag_ici_lock);
+ XFS_STATS_INC(xs_ig_missed);
+
+- error = xfs_iget_cache_miss(mp, pag, tp, ino, &ip, bno,
++ error = xfs_iget_cache_miss(mp, pag, tp, ino, &ip,
+ flags, lock_flags);
+ if (error)
+ goto out_error_or_again;
+diff -urpN a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
+--- a/fs/xfs/xfs_inode.c 2011-01-07 14:34:13.670211963 -0700
++++ b/fs/xfs/xfs_inode.c 2011-01-06 23:33:35.987182164 -0700
+@@ -787,7 +787,6 @@ xfs_iread(
+ xfs_mount_t *mp,
+ xfs_trans_t *tp,
+ xfs_inode_t *ip,
+- xfs_daddr_t bno,
+ uint iget_flags)
+ {
+ xfs_buf_t *bp;
+@@ -797,11 +796,9 @@ xfs_iread(
+ /*
+ * Fill in the location information in the in-core inode.
+ */
+- ip->i_imap.im_blkno = bno;
+ error = xfs_imap(mp, tp, ip->i_ino, &ip->i_imap, iget_flags);
+ if (error)
+ return error;
+- ASSERT(bno == 0 || bno == ip->i_imap.im_blkno);
+
+ /*
+ * Get pointers to the on-disk inode and the buffer containing it.
+diff -urpN a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
+--- a/fs/xfs/xfs_inode.h 2011-01-07 14:34:13.674212698 -0700
++++ b/fs/xfs/xfs_inode.h 2011-01-06 23:33:35.987182164 -0700
+@@ -468,7 +468,7 @@ static inline void xfs_ifunlock(xfs_inod
+ * xfs_iget.c prototypes.
+ */
+ int xfs_iget(struct xfs_mount *, struct xfs_trans *, xfs_ino_t,
+- uint, uint, xfs_inode_t **, xfs_daddr_t);
++ uint, uint, xfs_inode_t **);
+ void xfs_iput(xfs_inode_t *, uint);
+ void xfs_iput_new(xfs_inode_t *, uint);
+ void xfs_ilock(xfs_inode_t *, uint);
+@@ -567,7 +567,7 @@ int xfs_itobp(struct xfs_mount *, struc
+ struct xfs_inode *, struct xfs_dinode **,
+ struct xfs_buf **, uint);
+ int xfs_iread(struct xfs_mount *, struct xfs_trans *,
+- struct xfs_inode *, xfs_daddr_t, uint);
++ struct xfs_inode *, uint);
+ void xfs_dinode_to_disk(struct xfs_dinode *,
+ struct xfs_icdinode *);
+ void xfs_idestroy_fork(struct xfs_inode *, int);
+diff -urpN a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
+--- a/fs/xfs/xfs_itable.c 2011-01-07 14:34:13.682212854 -0700
++++ b/fs/xfs/xfs_itable.c 2011-01-06 23:33:35.991182694 -0700
+@@ -60,7 +60,6 @@ xfs_bulkstat_one_int(
+ void __user *buffer, /* buffer to place output in */
+ int ubsize, /* size of buffer */
+ bulkstat_one_fmt_pf formatter, /* formatter, copy to user */
+- xfs_daddr_t bno, /* starting bno of cluster */
+ int *ubused, /* bytes used by me */
+ int *stat) /* BULKSTAT_RV_... */
+ {
+@@ -80,7 +79,7 @@ xfs_bulkstat_one_int(
+ return XFS_ERROR(ENOMEM);
+
+ error = xfs_iget(mp, NULL, ino,
+- XFS_IGET_UNTRUSTED, XFS_ILOCK_SHARED, &ip, bno);
++ XFS_IGET_UNTRUSTED, XFS_ILOCK_SHARED, &ip);
+ if (error) {
+ *stat = BULKSTAT_RV_NOTHING;
+ goto out_free;
+@@ -178,13 +177,11 @@ xfs_bulkstat_one(
+ xfs_ino_t ino, /* inode number to get data for */
+ void __user *buffer, /* buffer to place output in */
+ int ubsize, /* size of buffer */
+- xfs_daddr_t bno, /* starting bno of inode cluster */
+ int *ubused, /* bytes used by me */
+ int *stat) /* BULKSTAT_RV_... */
+ {
+ return xfs_bulkstat_one_int(mp, ino, buffer, ubsize,
+- xfs_bulkstat_one_fmt, bno,
+- ubused, stat);
++ xfs_bulkstat_one_fmt, ubused, stat);
+ }
+
+ #define XFS_BULKSTAT_UBLEFT(ubleft) ((ubleft) >= statstruct_size)
+@@ -484,7 +481,7 @@ xfs_bulkstat(
+ * Get the inode and fill in a single buffer.
+ */
+ ubused = statstruct_size;
+- error = formatter(mp, ino, ubufp, ubleft, bno,
++ error = formatter(mp, ino, ubufp, ubleft,
+ &ubused, &fmterror);
+ if (fmterror == BULKSTAT_RV_NOTHING) {
+ if (error && error != ENOENT &&
+@@ -577,8 +574,7 @@ xfs_bulkstat_single(
+ */
+
+ ino = (xfs_ino_t)*lastinop;
+- error = xfs_bulkstat_one(mp, ino, buffer, sizeof(xfs_bstat_t),
+- 0, NULL, &res);
++ error = xfs_bulkstat_one(mp, ino, buffer, sizeof(xfs_bstat_t), 0, &res);
+ if (error) {
+ /*
+ * Special case way failed, do it the "long" way
+diff -urpN a/fs/xfs/xfs_itable.h b/fs/xfs/xfs_itable.h
+--- a/fs/xfs/xfs_itable.h 2011-01-07 14:34:13.686212948 -0700
++++ b/fs/xfs/xfs_itable.h 2011-01-06 23:33:35.991182694 -0700
+@@ -27,7 +27,6 @@ typedef int (*bulkstat_one_pf)(struct xf
+ xfs_ino_t ino,
+ void __user *buffer,
+ int ubsize,
+- xfs_daddr_t bno,
+ int *ubused,
+ int *stat);
+
+@@ -71,7 +70,6 @@ xfs_bulkstat_one_int(
+ void __user *buffer,
+ int ubsize,
+ bulkstat_one_fmt_pf formatter,
+- xfs_daddr_t bno,
+ int *ubused,
+ int *stat);
+
+@@ -81,7 +79,6 @@ xfs_bulkstat_one(
+ xfs_ino_t ino,
+ void __user *buffer,
+ int ubsize,
+- xfs_daddr_t bno,
+ int *ubused,
+ int *stat);
+
+diff -urpN a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
+--- a/fs/xfs/xfs_log_recover.c 2011-01-07 14:34:14.173401609 -0700
++++ b/fs/xfs/xfs_log_recover.c 2011-01-06 23:33:35.995184460 -0700
+@@ -3209,7 +3209,7 @@ xlog_recover_process_one_iunlink(
+ int error;
+
+ ino = XFS_AGINO_TO_INO(mp, agno, agino);
+- error = xfs_iget(mp, NULL, ino, 0, 0, &ip, 0);
++ error = xfs_iget(mp, NULL, ino, 0, 0, &ip);
+ if (error)
+ goto fail;
+
+diff -urpN a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
+--- a/fs/xfs/xfs_mount.c 2011-01-07 14:34:14.176712962 -0700
++++ b/fs/xfs/xfs_mount.c 2011-01-06 23:33:35.995184460 -0700
+@@ -1207,7 +1207,7 @@ xfs_mountfs(
+ * Get and sanity-check the root inode.
+ * Save the pointer to it in the mount structure.
+ */
+- error = xfs_iget(mp, NULL, sbp->sb_rootino, 0, XFS_ILOCK_EXCL, &rip, 0);
++ error = xfs_iget(mp, NULL, sbp->sb_rootino, 0, XFS_ILOCK_EXCL, &rip);
+ if (error) {
+ cmn_err(CE_WARN, "XFS: failed to read root inode");
+ goto out_log_dealloc;
+diff -urpN a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c
+--- a/fs/xfs/xfs_rtalloc.c 2011-01-07 14:34:14.185296965 -0700
++++ b/fs/xfs/xfs_rtalloc.c 2011-01-06 23:33:35.999182641 -0700
+@@ -2274,12 +2274,12 @@ xfs_rtmount_inodes(
+ sbp = &mp->m_sb;
+ if (sbp->sb_rbmino == NULLFSINO)
+ return 0;
+- error = xfs_iget(mp, NULL, sbp->sb_rbmino, 0, 0, &mp->m_rbmip, 0);
++ error = xfs_iget(mp, NULL, sbp->sb_rbmino, 0, 0, &mp->m_rbmip);
+ if (error)
+ return error;
+ ASSERT(mp->m_rbmip != NULL);
+ ASSERT(sbp->sb_rsumino != NULLFSINO);
+- error = xfs_iget(mp, NULL, sbp->sb_rsumino, 0, 0, &mp->m_rsumip, 0);
++ error = xfs_iget(mp, NULL, sbp->sb_rsumino, 0, 0, &mp->m_rsumip);
+ if (error) {
+ IRELE(mp->m_rbmip);
+ return error;
+diff -urpN a/fs/xfs/xfs_trans_inode.c b/fs/xfs/xfs_trans_inode.c
+--- a/fs/xfs/xfs_trans_inode.c 2011-01-07 14:34:14.185296965 -0700
++++ b/fs/xfs/xfs_trans_inode.c 2011-01-06 23:33:35.999182641 -0700
+@@ -62,7 +62,7 @@ xfs_trans_iget(
+ {
+ int error;
+
+- error = xfs_iget(mp, tp, ino, flags, lock_flags, ipp, 0);
++ error = xfs_iget(mp, tp, ino, flags, lock_flags, ipp);
+ if (!error && tp)
+ xfs_trans_ijoin(tp, *ipp, lock_flags);
+ return error;
+diff -urpN a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
+--- a/fs/xfs/xfs_vnodeops.c 2011-01-07 14:34:14.189771350 -0700
++++ b/fs/xfs/xfs_vnodeops.c 2011-01-06 23:33:36.003182095 -0700
+@@ -1371,7 +1371,7 @@ xfs_lookup(
+ if (error)
+ goto out;
+
+- error = xfs_iget(dp->i_mount, NULL, inum, 0, 0, ipp, 0);
++ error = xfs_iget(dp->i_mount, NULL, inum, 0, 0, ipp);
+ if (error)
+ goto out_free_name;
+
Added: dists/sid/linux-2.6/debian/patches/bugfix/all/xfs-rename-XFS_IGET_BULKSTAT-to-XFS_IGET_UNTRUSTED.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/bugfix/all/xfs-rename-XFS_IGET_BULKSTAT-to-XFS_IGET_UNTRUSTED.patch Sun Jan 23 17:44:49 2011 (r16844)
@@ -0,0 +1,107 @@
+commit 1920779e67cbf5ea8afef317777c5bf2b8096188
+Author: Dave Chinner <dchinner at redhat.com>
+Date: Thu Jun 24 11:15:47 2010 +1000
+
+ xfs: rename XFS_IGET_BULKSTAT to XFS_IGET_UNTRUSTED
+
+ Inode numbers may come from somewhere external to the filesystem
+ (e.g. file handles, bulkstat information) and so are inherently
+ untrusted. Rename the flag we use for these lookups to make it
+ obvious we are doing a lookup of an untrusted inode number and need
+ to verify it completely before trying to read it from disk.
+
+ Signed-off-by: Dave Chinner <dchinner at redhat.com>
+ Reviewed-by: Christoph Hellwig <hch at lst.de>
+ [dannf: adjusted to apply to Debian's 2.6.32]
+
+diff -urpN a/fs/xfs/linux-2.6/xfs_export.c b/fs/xfs/linux-2.6/xfs_export.c
+--- a/fs/xfs/linux-2.6/xfs_export.c 2009-12-02 20:51:21.000000000 -0700
++++ b/fs/xfs/linux-2.6/xfs_export.c 2011-01-06 23:31:51.398682747 -0700
+@@ -127,12 +127,11 @@ xfs_nfs_get_inode(
+ return ERR_PTR(-ESTALE);
+
+ /*
+- * The XFS_IGET_BULKSTAT means that an invalid inode number is just
+- * fine and not an indication of a corrupted filesystem. Because
+- * clients can send any kind of invalid file handle, e.g. after
+- * a restore on the server we have to deal with this case gracefully.
++ * The XFS_IGET_UNTRUSTED means that an invalid inode number is just
++ * fine and not an indication of a corrupted filesystem as clients can
++ * send invalid file handles and we have to handle it gracefully..
+ */
+- error = xfs_iget(mp, NULL, ino, XFS_IGET_BULKSTAT,
++ error = xfs_iget(mp, NULL, ino, XFS_IGET_UNTRUSTED,
+ XFS_ILOCK_SHARED, &ip, 0);
+ if (error) {
+ /*
+diff -urpN a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c
+--- a/fs/xfs/xfs_ialloc.c 2011-01-06 23:29:55.166682941 -0700
++++ b/fs/xfs/xfs_ialloc.c 2011-01-06 23:31:51.398682747 -0700
+@@ -1256,7 +1256,7 @@ xfs_imap_lookup(
+ return error;
+
+ /* for untrusted inodes check it is allocated first */
+- if ((flags & XFS_IGET_BULKSTAT) &&
++ if ((flags & XFS_IGET_UNTRUSTED) &&
+ (rec.ir_free & XFS_INOBT_MASK(agino - rec.ir_startino)))
+ return EINVAL;
+
+@@ -1297,8 +1297,11 @@ xfs_imap(
+ if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks ||
+ ino != XFS_AGINO_TO_INO(mp, agno, agino)) {
+ #ifdef DEBUG
+- /* no diagnostics for bulkstat, ino comes from userspace */
+- if (flags & XFS_IGET_BULKSTAT)
++ /*
++ * Don't output diagnostic information for untrusted inodes
++ * as they can be invalid without implying corruption.
++ */
++ if (flags & XFS_IGET_UNTRUSTED)
+ return XFS_ERROR(EINVAL);
+ if (agno >= mp->m_sb.sb_agcount) {
+ xfs_fs_cmn_err(CE_ALERT, mp,
+@@ -1334,7 +1337,7 @@ xfs_imap(
+ * inodes in stale state on disk. Hence we have to do a btree lookup
+ * in all cases where an untrusted inode number is passed.
+ */
+- if (flags & XFS_IGET_BULKSTAT) {
++ if (flags & XFS_IGET_UNTRUSTED) {
+ error = xfs_imap_lookup(mp, tp, agno, agino, agbno,
+ &chunk_agbno, &offset_agbno, flags);
+ if (error)
+diff -urpN a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
+--- a/fs/xfs/xfs_inode.c 2010-12-09 23:02:30.000000000 -0700
++++ b/fs/xfs/xfs_inode.c 2011-01-06 23:31:51.403182060 -0700
+@@ -177,7 +177,7 @@ xfs_imap_to_bp(
+ if (unlikely(XFS_TEST_ERROR(!di_ok, mp,
+ XFS_ERRTAG_ITOBP_INOTOBP,
+ XFS_RANDOM_ITOBP_INOTOBP))) {
+- if (iget_flags & XFS_IGET_BULKSTAT) {
++ if (iget_flags & XFS_IGET_UNTRUSTED) {
+ xfs_trans_brelse(tp, bp);
+ return XFS_ERROR(EINVAL);
+ }
+diff -urpN a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
+--- a/fs/xfs/xfs_inode.h 2009-12-02 20:51:21.000000000 -0700
++++ b/fs/xfs/xfs_inode.h 2011-01-06 23:31:51.403182060 -0700
+@@ -558,7 +558,7 @@ do { \
+ * Flags for xfs_iget()
+ */
+ #define XFS_IGET_CREATE 0x1
+-#define XFS_IGET_BULKSTAT 0x2
++#define XFS_IGET_UNTRUSTED 0x2
+
+ int xfs_inotobp(struct xfs_mount *, struct xfs_trans *,
+ xfs_ino_t, struct xfs_dinode **,
+diff -urpN a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
+--- a/fs/xfs/xfs_itable.c 2011-01-06 23:23:53.162769761 -0700
++++ b/fs/xfs/xfs_itable.c 2011-01-06 23:31:51.407185129 -0700
+@@ -80,7 +80,7 @@ xfs_bulkstat_one_int(
+ return XFS_ERROR(ENOMEM);
+
+ error = xfs_iget(mp, NULL, ino,
+- XFS_IGET_BULKSTAT, XFS_ILOCK_SHARED, &ip, bno);
++ XFS_IGET_UNTRUSTED, XFS_ILOCK_SHARED, &ip, bno);
+ if (error) {
+ *stat = BULKSTAT_RV_NOTHING;
+ goto out_free;
Added: dists/sid/linux-2.6/debian/patches/bugfix/all/xfs-validate-untrusted-inode-numbers-during-lookup.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/bugfix/all/xfs-validate-untrusted-inode-numbers-during-lookup.patch Sun Jan 23 17:44:49 2011 (r16844)
@@ -0,0 +1,197 @@
+commit 7124fe0a5b619d65b739477b3b55a20bf805b06d
+Author: Dave Chinner <dchinner at redhat.com>
+Date: Thu Jun 24 11:15:33 2010 +1000
+
+ xfs: validate untrusted inode numbers during lookup
+
+ When we decode a handle or do a bulkstat lookup, we are using an
+ inode number we cannot trust to be valid. If we are deleting inode
+ chunks from disk (default noikeep mode), then we cannot trust the on
+ disk inode buffer for any given inode number to correctly reflect
+ whether the inode has been unlinked as the di_mode nor the
+ generation number may have been updated on disk.
+
+ This is due to the fact that when we delete an inode chunk, we do
+ not write the clusters back to disk when they are removed - instead
+ we mark them stale to avoid them being written back potentially over
+ the top of something that has been subsequently allocated at that
+ location. The result is that we can have locations of disk that look
+ like they contain valid inodes but in reality do not. Hence we
+ cannot simply convert the inode number to a block number and read
+ the location from disk to determine if the inode is valid or not.
+
+ As a result, and XFS_IGET_BULKSTAT lookup needs to actually look the
+ inode up in the inode allocation btree to determine if the inode
+ number is valid or not.
+
+ It should be noted even on ikeep filesystems, there is the
+ possibility that blocks on disk may look like valid inode clusters.
+ e.g. if there are filesystem images hosted on the filesystem. Hence
+ even for ikeep filesystems we really need to validate that the inode
+ number is valid before issuing the inode buffer read.
+
+ Signed-off-by: Dave Chinner <dchinner at redhat.com>
+ Reviewed-by: Christoph Hellwig <hch at lst.de>
+ [dannf: backported to Debian's 2.6.32]
+
+diff -urpN a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c
+--- a/fs/xfs/xfs_ialloc.c 2009-12-02 20:51:21.000000000 -0700
++++ b/fs/xfs/xfs_ialloc.c 2011-01-06 23:29:55.166682941 -0700
+@@ -1206,6 +1206,65 @@ error0:
+ return error;
+ }
+
++STATIC int
++xfs_imap_lookup(
++ struct xfs_mount *mp,
++ struct xfs_trans *tp,
++ xfs_agnumber_t agno,
++ xfs_agino_t agino,
++ xfs_agblock_t agbno,
++ xfs_agblock_t *chunk_agbno,
++ xfs_agblock_t *offset_agbno,
++ int flags)
++{
++ struct xfs_inobt_rec_incore rec;
++ struct xfs_btree_cur *cur;
++ struct xfs_buf *agbp;
++ xfs_agino_t startino;
++ int error;
++ int i;
++
++ down_read(&mp->m_peraglock);
++ error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
++ up_read(&mp->m_peraglock);
++ if (error) {
++ xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
++ "xfs_ialloc_read_agi() returned "
++ "error %d, agno %d",
++ error, agno);
++ return error;
++ }
++
++ /*
++ * derive and lookup the exact inode record for the given agino. If the
++ * record cannot be found, then it's an invalid inode number and we
++ * should abort.
++ */
++ cur = xfs_inobt_init_cursor(mp, tp, agbp, agno);
++ startino = agino & ~(XFS_IALLOC_INODES(mp) - 1);
++ error = xfs_inobt_lookup(cur, startino, XFS_LOOKUP_EQ, &i);
++ if (!error) {
++ if (i)
++ error = xfs_inobt_get_rec(cur, &rec, &i);
++ if (!error && i == 0)
++ error = EINVAL;
++ }
++
++ xfs_trans_brelse(tp, agbp);
++ xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
++ if (error)
++ return error;
++
++ /* for untrusted inodes check it is allocated first */
++ if ((flags & XFS_IGET_BULKSTAT) &&
++ (rec.ir_free & XFS_INOBT_MASK(agino - rec.ir_startino)))
++ return EINVAL;
++
++ *chunk_agbno = XFS_AGINO_TO_AGBNO(mp, rec.ir_startino);
++ *offset_agbno = agbno - *chunk_agbno;
++ return 0;
++}
++
+ /*
+ * Return the location of the inode in imap, for mapping it into a buffer.
+ */
+@@ -1266,6 +1325,23 @@ xfs_imap(
+ return XFS_ERROR(EINVAL);
+ }
+
++ blks_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_blocklog;
++
++ /*
++ * For bulkstat and handle lookups, we have an untrusted inode number
++ * that we have to verify is valid. We cannot do this just by reading
++ * the inode buffer as it may have been unlinked and removed leaving
++ * inodes in stale state on disk. Hence we have to do a btree lookup
++ * in all cases where an untrusted inode number is passed.
++ */
++ if (flags & XFS_IGET_BULKSTAT) {
++ error = xfs_imap_lookup(mp, tp, agno, agino, agbno,
++ &chunk_agbno, &offset_agbno, flags);
++ if (error)
++ return error;
++ goto out_map;
++ }
++
+ /*
+ * If the inode cluster size is the same as the blocksize or
+ * smaller we get to the buffer by simple arithmetics.
+@@ -1280,10 +1356,8 @@ xfs_imap(
+ return 0;
+ }
+
+- blks_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_blocklog;
+-
+ /*
+- * If we get a block number passed from bulkstat we can use it to
++ * If we get a block number passed we can use it to
+ * find the buffer easily.
+ */
+ if (imap->im_blkno) {
+@@ -1307,52 +1381,13 @@ xfs_imap(
+ offset_agbno = agbno & mp->m_inoalign_mask;
+ chunk_agbno = agbno - offset_agbno;
+ } else {
+- xfs_btree_cur_t *cur; /* inode btree cursor */
+- xfs_inobt_rec_incore_t chunk_rec;
+- xfs_buf_t *agbp; /* agi buffer */
+- int i; /* temp state */
+-
+- down_read(&mp->m_peraglock);
+- error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
+- up_read(&mp->m_peraglock);
+- if (error) {
+- xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
+- "xfs_ialloc_read_agi() returned "
+- "error %d, agno %d",
+- error, agno);
+- return error;
+- }
+-
+- cur = xfs_inobt_init_cursor(mp, tp, agbp, agno);
+- error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &i);
+- if (error) {
+- xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
+- "xfs_inobt_lookup() failed");
+- goto error0;
+- }
+-
+- error = xfs_inobt_get_rec(cur, &chunk_rec, &i);
+- if (error) {
+- xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
+- "xfs_inobt_get_rec() failed");
+- goto error0;
+- }
+- if (i == 0) {
+-#ifdef DEBUG
+- xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
+- "xfs_inobt_get_rec() failed");
+-#endif /* DEBUG */
+- error = XFS_ERROR(EINVAL);
+- }
+- error0:
+- xfs_trans_brelse(tp, agbp);
+- xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
++ error = xfs_imap_lookup(mp, tp, agno, agino, agbno,
++ &chunk_agbno, &offset_agbno, flags);
+ if (error)
+ return error;
+- chunk_agbno = XFS_AGINO_TO_AGBNO(mp, chunk_rec.ir_startino);
+- offset_agbno = agbno - chunk_agbno;
+ }
+
++out_map:
+ ASSERT(agbno >= chunk_agbno);
+ cluster_agbno = chunk_agbno +
+ ((offset_agbno / blks_per_cluster) * blks_per_cluster);
Modified: dists/sid/linux-2.6/debian/patches/features/all/vserver/vs2.3.0.36.29.6.patch
==============================================================================
--- dists/sid/linux-2.6/debian/patches/features/all/vserver/vs2.3.0.36.29.6.patch Sun Jan 23 07:46:48 2011 (r16843)
+++ dists/sid/linux-2.6/debian/patches/features/all/vserver/vs2.3.0.36.29.6.patch Sun Jan 23 17:44:49 2011 (r16844)
@@ -8221,7 +8221,7 @@
xfs_ictimestamp_t di_mtime; /* time last modified */
@@ -569,7 +571,7 @@ int xfs_itobp(struct xfs_mount *, struc
int xfs_iread(struct xfs_mount *, struct xfs_trans *,
- struct xfs_inode *, xfs_daddr_t, uint);
+ struct xfs_inode *, uint);
void xfs_dinode_to_disk(struct xfs_dinode *,
- struct xfs_icdinode *);
+ struct xfs_icdinode *, int);
Modified: dists/sid/linux-2.6/debian/patches/series/31
==============================================================================
--- dists/sid/linux-2.6/debian/patches/series/31 Sun Jan 23 07:46:48 2011 (r16843)
+++ dists/sid/linux-2.6/debian/patches/series/31 Sun Jan 23 17:44:49 2011 (r16844)
@@ -4,3 +4,8 @@
+ bugfix/all/tty-fix-warning-in-synclink-driver.patch
+ debian/tty-Avoid-ABI-change-for-addition-of-get_icount.patch
+ bugfix/all/bonding-Ensure-that-we-unshare-skbs-prior-to-calling.patch
++ bugfix/all/xfs-always-use-iget-in-bulkstat.patch
++ bugfix/all/xfs-validate-untrusted-inode-numbers-during-lookup.patch
++ bugfix/all/xfs-rename-XFS_IGET_BULKSTAT-to-XFS_IGET_UNTRUSTED.patch
++ bugfix/all/xfs-remove-block-number-from-inode-lookup-code.patch
++ bugfix/all/xfs-fix-untrusted-inode-number-lookup.patch
More information about the Kernel-svn-changes
mailing list