From: Greg Kroah-Hartman Date: Thu, 15 Jan 2009 21:06:06 +0000 (-0800) Subject: one more .28 patch to sneak in. X-Git-Tag: v2.6.27.12~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=8bb039da48c88e6f43dd275fbd21180d9de5a022;p=thirdparty%2Fkernel%2Fstable-queue.git one more .28 patch to sneak in. --- diff --git a/review-2.6.28/series b/review-2.6.28/series index ea80dbc5f33..6857bd37ed3 100644 --- a/review-2.6.28/series +++ b/review-2.6.28/series @@ -92,3 +92,4 @@ ibmvfc-improve-async-event-handling.patch getrusage-rusage_thread-should-return-ru_utime-and-ru_stime.patch ath5k-ignore-the-return-value-of-ath5k_hw_noise_floor_calibration.patch mm-fix-assertion.patch +xfs-truncate-readdir-offsets-to-signed-32-bit-values.patch diff --git a/review-2.6.28/xfs-truncate-readdir-offsets-to-signed-32-bit-values.patch b/review-2.6.28/xfs-truncate-readdir-offsets-to-signed-32-bit-values.patch new file mode 100644 index 00000000000..3754055db5a --- /dev/null +++ b/review-2.6.28/xfs-truncate-readdir-offsets-to-signed-32-bit-values.patch @@ -0,0 +1,130 @@ +From 15440319767942a363f282d6585303d3d75088ba Mon Sep 17 00:00:00 2001 +From: Christoph Hellwig +Date: Thu, 8 Jan 2009 14:00:00 -0500 +Subject: XFS: truncate readdir offsets to signed 32 bit values + +From: Christoph Hellwig + +commit 15440319767942a363f282d6585303d3d75088ba upstream. + +John Stanley reported EOVERFLOW errors in readdir from his self-build +glibc. I traced this down to glibc enabling d_off overflow checks +in one of the about five million different getdents implementations. + +In 2.6.28 Dave Woodhouse moved our readdir double buffering required +for NFS4 readdirplus into nfsd and at that point we lost the capping +of the directory offsets to 32 bit signed values. Johns glibc used +getdents64 to even implement readdir for normal 32 bit offset dirents, +and failed with EOVERFLOW only if this happens on the first dirent in +a getdents call. I managed to come up with a testcase that uses +raw getdents and does the EOVERFLOW check manually. We always hit +it with our last entry due to the special end of directory marker. + +The patch below is a dumb version of just putting back the masking, +to make sure we have the same behavior as in 2.6.27 and earlier. + +I will work on a better and cleaner fix for 2.6.30. + +Reported-by: John Stanley +Tested-by: John Stanley +Signed-off-by: Christoph Hellwig +Reviewed-by: Dave Chinner +Signed-off-by: Lachlan McIlroy +Signed-off-by: Greg Kroah-Hartman + +--- + fs/xfs/xfs_dir2_block.c | 7 ++++--- + fs/xfs/xfs_dir2_leaf.c | 6 +++--- + fs/xfs/xfs_dir2_sf.c | 15 ++++++++------- + 3 files changed, 15 insertions(+), 13 deletions(-) + +--- a/fs/xfs/xfs_dir2_block.c ++++ b/fs/xfs/xfs_dir2_block.c +@@ -517,9 +517,9 @@ xfs_dir2_block_getdents( + /* + * If it didn't fit, set the final offset to here & return. + */ +- if (filldir(dirent, dep->name, dep->namelen, cook, ++ if (filldir(dirent, dep->name, dep->namelen, cook & 0x7fffffff, + ino, DT_UNKNOWN)) { +- *offset = cook; ++ *offset = cook & 0x7fffffff; + xfs_da_brelse(NULL, bp); + return 0; + } +@@ -529,7 +529,8 @@ xfs_dir2_block_getdents( + * Reached the end of the block. + * Set the offset to a non-existent block 1 and return. + */ +- *offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0); ++ *offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0) & ++ 0x7fffffff; + xfs_da_brelse(NULL, bp); + return 0; + } +--- a/fs/xfs/xfs_dir2_leaf.c ++++ b/fs/xfs/xfs_dir2_leaf.c +@@ -1092,7 +1092,7 @@ xfs_dir2_leaf_getdents( + * Won't fit. Return to caller. + */ + if (filldir(dirent, dep->name, dep->namelen, +- xfs_dir2_byte_to_dataptr(mp, curoff), ++ xfs_dir2_byte_to_dataptr(mp, curoff) & 0x7fffffff, + ino, DT_UNKNOWN)) + break; + +@@ -1108,9 +1108,9 @@ xfs_dir2_leaf_getdents( + * All done. Set output offset value to current offset. + */ + if (curoff > xfs_dir2_dataptr_to_byte(mp, XFS_DIR2_MAX_DATAPTR)) +- *offset = XFS_DIR2_MAX_DATAPTR; ++ *offset = XFS_DIR2_MAX_DATAPTR & 0x7fffffff; + else +- *offset = xfs_dir2_byte_to_dataptr(mp, curoff); ++ *offset = xfs_dir2_byte_to_dataptr(mp, curoff) & 0x7fffffff; + kmem_free(map); + if (bp) + xfs_da_brelse(NULL, bp); +--- a/fs/xfs/xfs_dir2_sf.c ++++ b/fs/xfs/xfs_dir2_sf.c +@@ -752,8 +752,8 @@ xfs_dir2_sf_getdents( + #if XFS_BIG_INUMS + ino += mp->m_inoadd; + #endif +- if (filldir(dirent, ".", 1, dot_offset, ino, DT_DIR)) { +- *offset = dot_offset; ++ if (filldir(dirent, ".", 1, dot_offset & 0x7fffffff, ino, DT_DIR)) { ++ *offset = dot_offset & 0x7fffffff; + return 0; + } + } +@@ -766,8 +766,8 @@ xfs_dir2_sf_getdents( + #if XFS_BIG_INUMS + ino += mp->m_inoadd; + #endif +- if (filldir(dirent, "..", 2, dotdot_offset, ino, DT_DIR)) { +- *offset = dotdot_offset; ++ if (filldir(dirent, "..", 2, dotdot_offset & 0x7fffffff, ino, DT_DIR)) { ++ *offset = dotdot_offset & 0x7fffffff; + return 0; + } + } +@@ -791,14 +791,15 @@ xfs_dir2_sf_getdents( + #endif + + if (filldir(dirent, sfep->name, sfep->namelen, +- off, ino, DT_UNKNOWN)) { +- *offset = off; ++ off & 0x7fffffff, ino, DT_UNKNOWN)) { ++ *offset = off & 0x7fffffff; + return 0; + } + sfep = xfs_dir2_sf_nextentry(sfp, sfep); + } + +- *offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0); ++ *offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0) & ++ 0x7fffffff; + return 0; + } +