All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 3.18.y 00/10] recent ext4 CVE fixes
@ 2018-10-04 17:53 Greg Hackmann
  2018-10-04 17:53 ` [PATCH 3.18.y 01/10] ext4: only look at the bg_flags field if it is valid Greg Hackmann
                   ` (10 more replies)
  0 siblings, 11 replies; 12+ messages in thread
From: Greg Hackmann @ 2018-10-04 17:53 UTC (permalink / raw)
  To: stable; +Cc: Theodore Ts'o, Greg Hackmann

A batch of ext4-related CVE fixes were released to other kernels in
linux-stable, but don't apply cleanly to 3.18.y.  For the most part
these are unmodified cherry-picks of Ben Hutchings's 3.16.y backports
(exceptions are noted above my Signed-off-by).

Theodore Ts'o (10):
  ext4: only look at the bg_flags field if it is valid
  ext4: fix check to prevent initializing reserved inodes
  ext4: always check block group bounds in ext4_init_block_bitmap()
  ext4: fix false negatives *and* false positives in
    ext4_check_descriptors()
  ext4: add corruption check in ext4_xattr_set_entry()
  ext4: always verify the magic number in xattr blocks
  ext4: never move the system.data xattr out of the inode body
  ext4: add more inode number paranoia checks
  jbd2: don't mark block as modified if the handle is out of credits
  ext4: avoid running out of journal credits when appending to an inline
    file

 fs/ext4/balloc.c      | 21 ++++++++++++-------
 fs/ext4/ext4.h        |  8 -------
 fs/ext4/ialloc.c      | 19 ++++++++++++++---
 fs/ext4/inline.c      | 38 +--------------------------------
 fs/ext4/inode.c       |  3 ++-
 fs/ext4/mballoc.c     |  6 ++++--
 fs/ext4/super.c       | 12 +++++++++--
 fs/ext4/xattr.c       | 49 ++++++++++++++++++++-----------------------
 fs/jbd2/transaction.c |  2 +-
 9 files changed, 70 insertions(+), 88 deletions(-)

-- 
2.19.0.605.g01d371f741-goog

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 3.18.y 01/10] ext4: only look at the bg_flags field if it is valid
  2018-10-04 17:53 [PATCH 3.18.y 00/10] recent ext4 CVE fixes Greg Hackmann
@ 2018-10-04 17:53 ` Greg Hackmann
  2018-10-04 17:53 ` [PATCH 3.18.y 02/10] ext4: fix check to prevent initializing reserved inodes Greg Hackmann
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Greg Hackmann @ 2018-10-04 17:53 UTC (permalink / raw)
  To: stable; +Cc: Theodore Ts'o, Ben Hutchings, Greg Hackmann

From: Theodore Ts'o <tytso@mit.edu>

commit 8844618d8aa7a9973e7b527d038a2a589665002c upstream.

The bg_flags field in the block group descripts is only valid if the
uninit_bg or metadata_csum feature is enabled.  We were not
consistently looking at this field; fix this.

Also block group #0 must never have uninitialized allocation bitmaps,
or need to be zeroed, since that's where the root inode, and other
special inodes are set up.  Check for these conditions and mark the
file system as corrupted if they are detected.

This addresses CVE-2018-10876.

https://bugzilla.kernel.org/show_bug.cgi?id=199403

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
[bwh: Backported to 3.16:
 - ext4_read_block_bitmap_nowait() and ext4_read_inode_bitmap() return
   a pointer (NULL on error) instead of an error code
 - Open-code sb_rdonly()
 - Adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
[ghackmann@google.com: forward-port to 3.18: adjust context]
Signed-off-by: Greg Hackmann <ghackmann@google.com>
---
 fs/ext4/balloc.c  | 11 ++++++++++-
 fs/ext4/ialloc.c  | 14 ++++++++++++--
 fs/ext4/mballoc.c |  6 ++++--
 fs/ext4/super.c   | 11 ++++++++++-
 4 files changed, 36 insertions(+), 6 deletions(-)

diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index e19719ecff69..7b7691353cf3 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -451,9 +451,18 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
 		goto verify;
 	}
 	ext4_lock_group(sb, block_group);
-	if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
+	if (ext4_has_group_desc_csum(sb) &&
+	    (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) {
 		int err;
 
+		if (block_group == 0) {
+			ext4_unlock_group(sb, block_group);
+			unlock_buffer(bh);
+			ext4_error(sb, "Block bitmap for bg 0 marked "
+				   "uninitialized");
+			put_bh(bh);
+			return NULL;
+		}
 		err = ext4_init_block_bitmap(sb, bh, block_group, desc);
 		set_bitmap_uptodate(bh);
 		set_buffer_uptodate(bh);
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 28aaf640745f..ab2b6f082633 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -117,7 +117,16 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
 	}
 
 	ext4_lock_group(sb, block_group);
-	if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
+	if (ext4_has_group_desc_csum(sb) &&
+	    (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT))) {
+		if (block_group == 0) {
+			ext4_unlock_group(sb, block_group);
+			unlock_buffer(bh);
+			ext4_error(sb, "Inode bitmap for bg 0 marked "
+				   "uninitialized");
+			put_bh(bh);
+			return NULL;
+		}
 		memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8);
 		ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb),
 				     sb->s_blocksize * 8, bh->b_data);
@@ -873,7 +882,8 @@ got:
 
 		/* recheck and clear flag under lock if we still need to */
 		ext4_lock_group(sb, group);
-		if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
+		if (ext4_has_group_desc_csum(sb) &&
+		    (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) {
 			gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
 			ext4_free_group_clusters_set(sb, gdp,
 				ext4_free_clusters_after_init(sb, group, gdp));
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index 6f51f016f80b..d8a729754e2c 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -2415,7 +2415,8 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group,
 	 * initialize bb_free to be able to skip
 	 * empty groups without initialization
 	 */
-	if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
+	if (ext4_has_group_desc_csum(sb) &&
+	    (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) {
 		meta_group_info[i]->bb_free =
 			ext4_free_clusters_after_init(sb, group, desc);
 	} else {
@@ -2942,7 +2943,8 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
 #endif
 	ext4_set_bits(bitmap_bh->b_data, ac->ac_b_ex.fe_start,
 		      ac->ac_b_ex.fe_len);
-	if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
+	if (ext4_has_group_desc_csum(sb) &&
+	    (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) {
 		gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
 		ext4_free_group_clusters_set(sb, gdp,
 					     ext4_free_clusters_after_init(sb,
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index cd1fb8cf5161..6bff55db4d8f 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -3132,13 +3132,22 @@ static ext4_group_t ext4_has_uninit_itable(struct super_block *sb)
 	ext4_group_t group, ngroups = EXT4_SB(sb)->s_groups_count;
 	struct ext4_group_desc *gdp = NULL;
 
+	if (!ext4_has_group_desc_csum(sb))
+		return ngroups;
+
 	for (group = 0; group < ngroups; group++) {
 		gdp = ext4_get_group_desc(sb, group, NULL);
 		if (!gdp)
 			continue;
 
-		if (!(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED)))
+		if (gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED))
+			continue;
+		if (group != 0)
 			break;
+		ext4_error(sb, "Inode table for bg 0 marked as "
+			   "needing zeroing");
+		if (sb->s_flags & MS_RDONLY)
+			return ngroups;
 	}
 
 	return group;
-- 
2.19.0.605.g01d371f741-goog

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3.18.y 02/10] ext4: fix check to prevent initializing reserved inodes
  2018-10-04 17:53 [PATCH 3.18.y 00/10] recent ext4 CVE fixes Greg Hackmann
  2018-10-04 17:53 ` [PATCH 3.18.y 01/10] ext4: only look at the bg_flags field if it is valid Greg Hackmann
@ 2018-10-04 17:53 ` Greg Hackmann
  2018-10-04 17:53 ` [PATCH 3.18.y 03/10] ext4: always check block group bounds in ext4_init_block_bitmap() Greg Hackmann
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Greg Hackmann @ 2018-10-04 17:53 UTC (permalink / raw)
  To: stable; +Cc: Theodore Ts'o, Ben Hutchings, Greg Hackmann

From: Theodore Ts'o <tytso@mit.edu>

commit 5012284700775a4e6e3fbe7eac4c543c4874b559 upstream.

Commit 8844618d8aa7: "ext4: only look at the bg_flags field if it is
valid" will complain if block group zero does not have the
EXT4_BG_INODE_ZEROED flag set.  Unfortunately, this is not correct,
since a freshly created file system has this flag cleared.  It gets
almost immediately after the file system is mounted read-write --- but
the following somewhat unlikely sequence will end up triggering a
false positive report of a corrupted file system:

   mkfs.ext4 /dev/vdc
   mount -o ro /dev/vdc /vdc
   mount -o remount,rw /dev/vdc

Instead, when initializing the inode table for block group zero, test
to make sure that itable_unused count is not too large, since that is
the case that will result in some or all of the reserved inodes
getting cleared.

This fixes the failures reported by Eric Whiteney when running
generic/230 and generic/231 in the the nojournal test case.

Fixes: 8844618d8aa7 ("ext4: only look at the bg_flags field if it is valid")
Reported-by: Eric Whitney <enwlinux@gmail.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
[bwh: Backported to 3.16: adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Signed-off-by: Greg Hackmann <ghackmann@google.com>
---
 fs/ext4/ialloc.c | 5 ++++-
 fs/ext4/super.c  | 8 +-------
 2 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index ab2b6f082633..2bd846f84b8b 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -1253,7 +1253,10 @@ int ext4_init_inode_table(struct super_block *sb, ext4_group_t group,
 			    ext4_itable_unused_count(sb, gdp)),
 			    sbi->s_inodes_per_block);
 
-	if ((used_blks < 0) || (used_blks > sbi->s_itb_per_group)) {
+	if ((used_blks < 0) || (used_blks > sbi->s_itb_per_group) ||
+	    ((group == 0) && ((EXT4_INODES_PER_GROUP(sb) -
+			       ext4_itable_unused_count(sb, gdp)) <
+			      EXT4_FIRST_INO(sb)))) {
 		ext4_error(sb, "Something is wrong with group %u: "
 			   "used itable blocks: %d; "
 			   "itable unused count: %u",
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 6bff55db4d8f..91740af5648e 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -3140,14 +3140,8 @@ static ext4_group_t ext4_has_uninit_itable(struct super_block *sb)
 		if (!gdp)
 			continue;
 
-		if (gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED))
-			continue;
-		if (group != 0)
+		if (!(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED)))
 			break;
-		ext4_error(sb, "Inode table for bg 0 marked as "
-			   "needing zeroing");
-		if (sb->s_flags & MS_RDONLY)
-			return ngroups;
 	}
 
 	return group;
-- 
2.19.0.605.g01d371f741-goog

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3.18.y 03/10] ext4: always check block group bounds in ext4_init_block_bitmap()
  2018-10-04 17:53 [PATCH 3.18.y 00/10] recent ext4 CVE fixes Greg Hackmann
  2018-10-04 17:53 ` [PATCH 3.18.y 01/10] ext4: only look at the bg_flags field if it is valid Greg Hackmann
  2018-10-04 17:53 ` [PATCH 3.18.y 02/10] ext4: fix check to prevent initializing reserved inodes Greg Hackmann
@ 2018-10-04 17:53 ` Greg Hackmann
  2018-10-04 17:53 ` [PATCH 3.18.y 04/10] ext4: fix false negatives *and* false positives in ext4_check_descriptors() Greg Hackmann
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Greg Hackmann @ 2018-10-04 17:53 UTC (permalink / raw)
  To: stable; +Cc: Theodore Ts'o, Ben Hutchings, Greg Hackmann

From: Theodore Ts'o <tytso@mit.edu>

commit 819b23f1c501b17b9694325471789e6b5cc2d0d2 upstream.

Regardless of whether the flex_bg feature is set, we should always
check to make sure the bits we are setting in the block bitmap are
within the block group bounds.

https://bugzilla.kernel.org/show_bug.cgi?id=199865

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
[bwh: Backported to 3.16: adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Signed-off-by: Greg Hackmann <ghackmann@google.com>
---
 fs/ext4/balloc.c | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index 7b7691353cf3..c56b9b4f6f76 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -184,7 +184,6 @@ static int ext4_init_block_bitmap(struct super_block *sb,
 	unsigned int bit, bit_max;
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
 	ext4_fsblk_t start, tmp;
-	int flex_bg = 0;
 	struct ext4_group_info *grp;
 
 	J_ASSERT_BH(bh, buffer_locked(bh));
@@ -217,22 +216,19 @@ static int ext4_init_block_bitmap(struct super_block *sb,
 
 	start = ext4_group_first_block_no(sb, block_group);
 
-	if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG))
-		flex_bg = 1;
-
 	/* Set bits for block and inode bitmaps, and inode table */
 	tmp = ext4_block_bitmap(sb, gdp);
-	if (!flex_bg || ext4_block_in_group(sb, tmp, block_group))
+	if (ext4_block_in_group(sb, tmp, block_group))
 		ext4_set_bit(EXT4_B2C(sbi, tmp - start), bh->b_data);
 
 	tmp = ext4_inode_bitmap(sb, gdp);
-	if (!flex_bg || ext4_block_in_group(sb, tmp, block_group))
+	if (ext4_block_in_group(sb, tmp, block_group))
 		ext4_set_bit(EXT4_B2C(sbi, tmp - start), bh->b_data);
 
 	tmp = ext4_inode_table(sb, gdp);
 	for (; tmp < ext4_inode_table(sb, gdp) +
 		     sbi->s_itb_per_group; tmp++) {
-		if (!flex_bg || ext4_block_in_group(sb, tmp, block_group))
+		if (ext4_block_in_group(sb, tmp, block_group))
 			ext4_set_bit(EXT4_B2C(sbi, tmp - start), bh->b_data);
 	}
 
-- 
2.19.0.605.g01d371f741-goog

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3.18.y 04/10] ext4: fix false negatives *and* false positives in ext4_check_descriptors()
  2018-10-04 17:53 [PATCH 3.18.y 00/10] recent ext4 CVE fixes Greg Hackmann
                   ` (2 preceding siblings ...)
  2018-10-04 17:53 ` [PATCH 3.18.y 03/10] ext4: always check block group bounds in ext4_init_block_bitmap() Greg Hackmann
@ 2018-10-04 17:53 ` Greg Hackmann
  2018-10-04 17:53 ` [PATCH 3.18.y 05/10] ext4: add corruption check in ext4_xattr_set_entry() Greg Hackmann
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Greg Hackmann @ 2018-10-04 17:53 UTC (permalink / raw)
  To: stable; +Cc: Theodore Ts'o, Ben Hutchings, Greg Hackmann

From: Theodore Ts'o <tytso@mit.edu>

commit 44de022c4382541cebdd6de4465d1f4f465ff1dd upstream.

Ext4_check_descriptors() was getting called before s_gdb_count was
initialized.  So for file systems w/o the meta_bg feature, allocation
bitmaps could overlap the block group descriptors and ext4 wouldn't
notice.

For file systems with the meta_bg feature enabled, there was a
fencepost error which would cause the ext4_check_descriptors() to
incorrectly believe that the block allocation bitmap overlaps with the
block group descriptor blocks, and it would reject the mount.

Fix both of these problems.

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
[bwh: Backported to 3.16: adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Signed-off-by: Greg Hackmann <ghackmann@google.com>
---
 fs/ext4/super.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 91740af5648e..6806b8937803 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -2064,7 +2064,7 @@ static int ext4_check_descriptors(struct super_block *sb,
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
 	ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
 	ext4_fsblk_t last_block;
-	ext4_fsblk_t last_bg_block = sb_block + ext4_bg_num_gdb(sb, 0) + 1;
+	ext4_fsblk_t last_bg_block = sb_block + ext4_bg_num_gdb(sb, 0);
 	ext4_fsblk_t block_bitmap;
 	ext4_fsblk_t inode_bitmap;
 	ext4_fsblk_t inode_table;
@@ -4018,12 +4018,12 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
 			goto failed_mount2;
 		}
 	}
+	sbi->s_gdb_count = db_count;
 	if (!ext4_check_descriptors(sb, logical_sb_block, &first_not_zeroed)) {
 		ext4_msg(sb, KERN_ERR, "group descriptors corrupted!");
 		goto failed_mount2;
 	}
 
-	sbi->s_gdb_count = db_count;
 	get_random_bytes(&sbi->s_next_generation, sizeof(u32));
 	spin_lock_init(&sbi->s_next_gen_lock);
 
-- 
2.19.0.605.g01d371f741-goog

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3.18.y 05/10] ext4: add corruption check in ext4_xattr_set_entry()
  2018-10-04 17:53 [PATCH 3.18.y 00/10] recent ext4 CVE fixes Greg Hackmann
                   ` (3 preceding siblings ...)
  2018-10-04 17:53 ` [PATCH 3.18.y 04/10] ext4: fix false negatives *and* false positives in ext4_check_descriptors() Greg Hackmann
@ 2018-10-04 17:53 ` Greg Hackmann
  2018-10-04 17:53 ` [PATCH 3.18.y 06/10] ext4: always verify the magic number in xattr blocks Greg Hackmann
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Greg Hackmann @ 2018-10-04 17:53 UTC (permalink / raw)
  To: stable; +Cc: Theodore Ts'o, Ben Hutchings, Greg Hackmann

From: Theodore Ts'o <tytso@mit.edu>

commit 5369a762c882c0b6e9599e4ebbb3a9ba9eee7e2d upstream.

In theory this should have been caught earlier when the xattr list was
verified, but in case it got missed, it's simple enough to add check
to make sure we don't overrun the xattr buffer.

This addresses CVE-2018-10879.

https://bugzilla.kernel.org/show_bug.cgi?id=200001

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Reviewed-by: Andreas Dilger <adilger@dilger.ca>
[bwh: Backported to 3.16:
 - Add inode parameter to ext4_xattr_set_entry() and update callers
 - Return -EIO instead of -EFSCORRUPTED on error
 - Adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Signed-off-by: Greg Hackmann <ghackmann@google.com>
---
 fs/ext4/xattr.c | 22 ++++++++++++++--------
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index c8d782bf8c5c..5b391e74c0cc 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -637,14 +637,20 @@ static size_t ext4_xattr_free_space(struct ext4_xattr_entry *last,
 }
 
 static int
-ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s)
+ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s,
+		     struct inode *inode)
 {
-	struct ext4_xattr_entry *last;
+	struct ext4_xattr_entry *last, *next;
 	size_t free, min_offs = s->end - s->base, name_len = strlen(i->name);
 
 	/* Compute min_offs and last. */
 	last = s->first;
-	for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
+	for (; !IS_LAST_ENTRY(last); last = next) {
+		next = EXT4_XATTR_NEXT(last);
+		if ((void *)next >= s->end) {
+			EXT4_ERROR_INODE(inode, "corrupted xattr entries");
+			return -EIO;
+		}
 		if (!last->e_value_block && last->e_value_size) {
 			size_t offs = le16_to_cpu(last->e_value_offs);
 			if (offs < min_offs)
@@ -825,7 +831,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
 				ce = NULL;
 			}
 			ea_bdebug(bs->bh, "modifying in-place");
-			error = ext4_xattr_set_entry(i, s);
+			error = ext4_xattr_set_entry(i, s, inode);
 			if (!error) {
 				if (!IS_LAST_ENTRY(s->first))
 					ext4_xattr_rehash(header(s->base),
@@ -877,7 +883,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
 		s->end = s->base + sb->s_blocksize;
 	}
 
-	error = ext4_xattr_set_entry(i, s);
+	error = ext4_xattr_set_entry(i, s, inode);
 	if (error == -EIO)
 		goto bad_block;
 	if (error)
@@ -1038,7 +1044,7 @@ int ext4_xattr_ibody_inline_set(handle_t *handle, struct inode *inode,
 
 	if (EXT4_I(inode)->i_extra_isize == 0)
 		return -ENOSPC;
-	error = ext4_xattr_set_entry(i, s);
+	error = ext4_xattr_set_entry(i, s, inode);
 	if (error) {
 		if (error == -ENOSPC &&
 		    ext4_has_inline_data(inode)) {
@@ -1050,7 +1056,7 @@ int ext4_xattr_ibody_inline_set(handle_t *handle, struct inode *inode,
 			error = ext4_xattr_ibody_find(inode, i, is);
 			if (error)
 				return error;
-			error = ext4_xattr_set_entry(i, s);
+			error = ext4_xattr_set_entry(i, s, inode);
 		}
 		if (error)
 			return error;
@@ -1076,7 +1082,7 @@ static int ext4_xattr_ibody_set(handle_t *handle, struct inode *inode,
 
 	if (EXT4_I(inode)->i_extra_isize == 0)
 		return -ENOSPC;
-	error = ext4_xattr_set_entry(i, s);
+	error = ext4_xattr_set_entry(i, s, inode);
 	if (error)
 		return error;
 	header = IHDR(inode, ext4_raw_inode(&is->iloc));
-- 
2.19.0.605.g01d371f741-goog

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3.18.y 06/10] ext4: always verify the magic number in xattr blocks
  2018-10-04 17:53 [PATCH 3.18.y 00/10] recent ext4 CVE fixes Greg Hackmann
                   ` (4 preceding siblings ...)
  2018-10-04 17:53 ` [PATCH 3.18.y 05/10] ext4: add corruption check in ext4_xattr_set_entry() Greg Hackmann
@ 2018-10-04 17:53 ` Greg Hackmann
  2018-10-04 17:53 ` [PATCH 3.18.y 07/10] ext4: never move the system.data xattr out of the inode body Greg Hackmann
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Greg Hackmann @ 2018-10-04 17:53 UTC (permalink / raw)
  To: stable; +Cc: Theodore Ts'o, stable, Greg Hackmann

From: Theodore Ts'o <tytso@mit.edu>

commit 513f86d73855ce556ea9522b6bfd79f87356dc3a upstream.

If there an inode points to a block which is also some other type of
metadata block (such as a block allocation bitmap), the
buffer_verified flag can be set when it was validated as that other
metadata block type; however, it would make a really terrible external
attribute block.  The reason why we use the verified flag is to avoid
constantly reverifying the block.  However, it doesn't take much
overhead to make sure the magic number of the xattr block is correct,
and this will avoid potential crashes.

This addresses CVE-2018-10879.

https://bugzilla.kernel.org/show_bug.cgi?id=200001

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Reviewed-by: Andreas Dilger <adilger@dilger.ca>
Cc: stable@kernel.org
[ghackmann@google.com: 3.18 backport: adjust context]
Signed-off-by: Greg Hackmann <ghackmann@google.com>
---
 fs/ext4/xattr.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index 5b391e74c0cc..bb4faf2d0c5c 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -218,12 +218,12 @@ ext4_xattr_check_block(struct inode *inode, struct buffer_head *bh)
 {
 	int error;
 
-	if (buffer_verified(bh))
-		return 0;
-
 	if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) ||
 	    BHDR(bh)->h_blocks != cpu_to_le32(1))
 		return -EIO;
+	if (buffer_verified(bh))
+		return 0;
+
 	if (!ext4_xattr_block_csum_verify(inode, bh->b_blocknr, BHDR(bh)))
 		return -EIO;
 	error = ext4_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size,
-- 
2.19.0.605.g01d371f741-goog

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3.18.y 07/10] ext4: never move the system.data xattr out of the inode body
  2018-10-04 17:53 [PATCH 3.18.y 00/10] recent ext4 CVE fixes Greg Hackmann
                   ` (5 preceding siblings ...)
  2018-10-04 17:53 ` [PATCH 3.18.y 06/10] ext4: always verify the magic number in xattr blocks Greg Hackmann
@ 2018-10-04 17:53 ` Greg Hackmann
  2018-10-04 17:53 ` [PATCH 3.18.y 08/10] ext4: add more inode number paranoia checks Greg Hackmann
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Greg Hackmann @ 2018-10-04 17:53 UTC (permalink / raw)
  To: stable; +Cc: Theodore Ts'o, Ben Hutchings, Greg Hackmann

From: Theodore Ts'o <tytso@mit.edu>

commit 8cdb5240ec5928b20490a2bb34cb87e9a5f40226 upstream.

When expanding the extra isize space, we must never move the
system.data xattr out of the inode body.  For performance reasons, it
doesn't make any sense, and the inline data implementation assumes
that system.data xattr is never in the external xattr block.

This addresses CVE-2018-10880

https://bugzilla.kernel.org/show_bug.cgi?id=200005

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
[bwh: Backported to 3.16: adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Signed-off-by: Greg Hackmann <ghackmann@google.com>
---
 fs/ext4/xattr.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index bb4faf2d0c5c..5f67ef828ccd 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -1391,6 +1391,11 @@ retry:
 		/* Find the entry best suited to be pushed into EA block */
 		entry = NULL;
 		for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
+			/* never move system.data out of the inode */
+			if ((last->e_name_len == 4) &&
+			    (last->e_name_index == EXT4_XATTR_INDEX_SYSTEM) &&
+			    !memcmp(last->e_name, "data", 4))
+				continue;
 			total_size =
 			EXT4_XATTR_SIZE(le32_to_cpu(last->e_value_size)) +
 					EXT4_XATTR_LEN(last->e_name_len);
-- 
2.19.0.605.g01d371f741-goog

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3.18.y 08/10] ext4: add more inode number paranoia checks
  2018-10-04 17:53 [PATCH 3.18.y 00/10] recent ext4 CVE fixes Greg Hackmann
                   ` (6 preceding siblings ...)
  2018-10-04 17:53 ` [PATCH 3.18.y 07/10] ext4: never move the system.data xattr out of the inode body Greg Hackmann
@ 2018-10-04 17:53 ` Greg Hackmann
  2018-10-04 17:53 ` [PATCH 3.18.y 09/10] jbd2: don't mark block as modified if the handle is out of credits Greg Hackmann
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Greg Hackmann @ 2018-10-04 17:53 UTC (permalink / raw)
  To: stable; +Cc: Theodore Ts'o, Ben Hutchings, Greg Hackmann

From: Theodore Ts'o <tytso@mit.edu>

commit c37e9e013469521d9adb932d17a1795c139b36db upstream.

If there is a directory entry pointing to a system inode (such as a
journal inode), complain and declare the file system to be corrupted.

Also, if the superblock's first inode number field is too small,
refuse to mount the file system.

This addresses CVE-2018-10882.

https://bugzilla.kernel.org/show_bug.cgi?id=200069

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
[bwh: Backported to 3.16: adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Signed-off-by: Greg Hackmann <ghackmann@google.com>
---
 fs/ext4/ext4.h  | 5 -----
 fs/ext4/inode.c | 3 ++-
 fs/ext4/super.c | 5 +++++
 3 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index bd997b3d6a6f..beea7a33f5ee 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1386,11 +1386,6 @@ static inline struct timespec ext4_current_time(struct inode *inode)
 static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
 {
 	return ino == EXT4_ROOT_INO ||
-		ino == EXT4_USR_QUOTA_INO ||
-		ino == EXT4_GRP_QUOTA_INO ||
-		ino == EXT4_BOOT_LOADER_INO ||
-		ino == EXT4_JOURNAL_INO ||
-		ino == EXT4_RESIZE_INO ||
 		(ino >= EXT4_FIRST_INO(sb) &&
 		 ino <= le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count));
 }
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index eb06f62fa95b..75dc9da78196 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3737,7 +3737,8 @@ static int __ext4_get_inode_loc(struct inode *inode,
 	int			inodes_per_block, inode_offset;
 
 	iloc->bh = NULL;
-	if (!ext4_valid_inum(sb, inode->i_ino))
+	if (inode->i_ino < EXT4_ROOT_INO ||
+	    inode->i_ino > le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count))
 		return -EIO;
 
 	iloc->block_group = (inode->i_ino - 1) / EXT4_INODES_PER_GROUP(sb);
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 6806b8937803..a9e8df7c529f 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -3794,6 +3794,11 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
 	} else {
 		sbi->s_inode_size = le16_to_cpu(es->s_inode_size);
 		sbi->s_first_ino = le32_to_cpu(es->s_first_ino);
+		if (sbi->s_first_ino < EXT4_GOOD_OLD_FIRST_INO) {
+			ext4_msg(sb, KERN_ERR, "invalid first ino: %u",
+				 sbi->s_first_ino);
+			goto failed_mount;
+		}
 		if ((sbi->s_inode_size < EXT4_GOOD_OLD_INODE_SIZE) ||
 		    (!is_power_of_2(sbi->s_inode_size)) ||
 		    (sbi->s_inode_size > blocksize)) {
-- 
2.19.0.605.g01d371f741-goog

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3.18.y 09/10] jbd2: don't mark block as modified if the handle is out of credits
  2018-10-04 17:53 [PATCH 3.18.y 00/10] recent ext4 CVE fixes Greg Hackmann
                   ` (7 preceding siblings ...)
  2018-10-04 17:53 ` [PATCH 3.18.y 08/10] ext4: add more inode number paranoia checks Greg Hackmann
@ 2018-10-04 17:53 ` Greg Hackmann
  2018-10-04 17:53 ` [PATCH 3.18.y 10/10] ext4: avoid running out of journal credits when appending to an inline file Greg Hackmann
  2018-10-11  9:17 ` [PATCH 3.18.y 00/10] recent ext4 CVE fixes Greg KH
  10 siblings, 0 replies; 12+ messages in thread
From: Greg Hackmann @ 2018-10-04 17:53 UTC (permalink / raw)
  To: stable; +Cc: Theodore Ts'o, Ben Hutchings, Greg Hackmann

From: Theodore Ts'o <tytso@mit.edu>

commit e09463f220ca9a1a1ecfda84fcda658f99a1f12a upstream.

Do not set the b_modified flag in block's journal head should not
until after we're sure that jbd2_journal_dirty_metadat() will not
abort with an error due to there not being enough space reserved in
the jbd2 handle.

Otherwise, future attempts to modify the buffer may lead a large
number of spurious errors and warnings.

This addresses CVE-2018-10883.

https://bugzilla.kernel.org/show_bug.cgi?id=200071

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
[bwh: Backported to 3.16: Drop the added logging statement, as it's on
 a code path that doesn't exist here]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Signed-off-by: Greg Hackmann <ghackmann@google.com>
---
 fs/jbd2/transaction.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
index f3818e7cfa60..ab034f48ffe4 100644
--- a/fs/jbd2/transaction.c
+++ b/fs/jbd2/transaction.c
@@ -1283,11 +1283,11 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh)
 		 * of the transaction. This needs to be done
 		 * once a transaction -bzzz
 		 */
-		jh->b_modified = 1;
 		if (handle->h_buffer_credits <= 0) {
 			ret = -ENOSPC;
 			goto out_unlock_bh;
 		}
+		jh->b_modified = 1;
 		handle->h_buffer_credits--;
 	}
 
-- 
2.19.0.605.g01d371f741-goog

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3.18.y 10/10] ext4: avoid running out of journal credits when appending to an inline file
  2018-10-04 17:53 [PATCH 3.18.y 00/10] recent ext4 CVE fixes Greg Hackmann
                   ` (8 preceding siblings ...)
  2018-10-04 17:53 ` [PATCH 3.18.y 09/10] jbd2: don't mark block as modified if the handle is out of credits Greg Hackmann
@ 2018-10-04 17:53 ` Greg Hackmann
  2018-10-11  9:17 ` [PATCH 3.18.y 00/10] recent ext4 CVE fixes Greg KH
  10 siblings, 0 replies; 12+ messages in thread
From: Greg Hackmann @ 2018-10-04 17:53 UTC (permalink / raw)
  To: stable; +Cc: Theodore Ts'o, Ben Hutchings, Greg Hackmann

From: Theodore Ts'o <tytso@mit.edu>

commit 8bc1379b82b8e809eef77a9fedbb75c6c297be19 upstream.

Use a separate journal transaction if it turns out that we need to
convert an inline file to use an data block.  Otherwise we could end
up failing due to not having journal credits.

This addresses CVE-2018-10883.

https://bugzilla.kernel.org/show_bug.cgi?id=200071

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
[bwh: Backported to 3.16: adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Signed-off-by: Greg Hackmann <ghackmann@google.com>
---
 fs/ext4/ext4.h   |  3 ---
 fs/ext4/inline.c | 38 +-------------------------------------
 fs/ext4/xattr.c  | 18 ++----------------
 3 files changed, 3 insertions(+), 56 deletions(-)

diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index beea7a33f5ee..a27ccb098558 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -2663,9 +2663,6 @@ extern struct buffer_head *ext4_get_first_inline_block(struct inode *inode,
 extern int ext4_inline_data_fiemap(struct inode *inode,
 				   struct fiemap_extent_info *fieinfo,
 				   int *has_inline);
-extern int ext4_try_to_evict_inline_data(handle_t *handle,
-					 struct inode *inode,
-					 int needed);
 extern void ext4_inline_data_truncate(struct inode *inode, int *has_inline);
 
 extern int ext4_convert_inline_data(struct inode *inode);
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
index 7762d365260e..f373e9d220ce 100644
--- a/fs/ext4/inline.c
+++ b/fs/ext4/inline.c
@@ -873,11 +873,11 @@ retry_journal:
 	}
 
 	if (ret == -ENOSPC) {
+		ext4_journal_stop(handle);
 		ret = ext4_da_convert_inline_data_to_extent(mapping,
 							    inode,
 							    flags,
 							    fsdata);
-		ext4_journal_stop(handle);
 		if (ret == -ENOSPC &&
 		    ext4_should_retry_alloc(inode->i_sb, &retries))
 			goto retry_journal;
@@ -1840,42 +1840,6 @@ out:
 	return (error < 0 ? error : 0);
 }
 
-/*
- * Called during xattr set, and if we can sparse space 'needed',
- * just create the extent tree evict the data to the outer block.
- *
- * We use jbd2 instead of page cache to move data to the 1st block
- * so that the whole transaction can be committed as a whole and
- * the data isn't lost because of the delayed page cache write.
- */
-int ext4_try_to_evict_inline_data(handle_t *handle,
-				  struct inode *inode,
-				  int needed)
-{
-	int error;
-	struct ext4_xattr_entry *entry;
-	struct ext4_inode *raw_inode;
-	struct ext4_iloc iloc;
-
-	error = ext4_get_inode_loc(inode, &iloc);
-	if (error)
-		return error;
-
-	raw_inode = ext4_raw_inode(&iloc);
-	entry = (struct ext4_xattr_entry *)((void *)raw_inode +
-					    EXT4_I(inode)->i_inline_off);
-	if (EXT4_XATTR_LEN(entry->e_name_len) +
-	    EXT4_XATTR_SIZE(le32_to_cpu(entry->e_value_size)) < needed) {
-		error = -ENOSPC;
-		goto out;
-	}
-
-	error = ext4_convert_inline_data_nolock(handle, inode, &iloc);
-out:
-	brelse(iloc.bh);
-	return error;
-}
-
 void ext4_inline_data_truncate(struct inode *inode, int *has_inline)
 {
 	handle_t *handle;
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index 5f67ef828ccd..9b4f642d6dea 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -1045,22 +1045,8 @@ int ext4_xattr_ibody_inline_set(handle_t *handle, struct inode *inode,
 	if (EXT4_I(inode)->i_extra_isize == 0)
 		return -ENOSPC;
 	error = ext4_xattr_set_entry(i, s, inode);
-	if (error) {
-		if (error == -ENOSPC &&
-		    ext4_has_inline_data(inode)) {
-			error = ext4_try_to_evict_inline_data(handle, inode,
-					EXT4_XATTR_LEN(strlen(i->name) +
-					EXT4_XATTR_SIZE(i->value_len)));
-			if (error)
-				return error;
-			error = ext4_xattr_ibody_find(inode, i, is);
-			if (error)
-				return error;
-			error = ext4_xattr_set_entry(i, s, inode);
-		}
-		if (error)
-			return error;
-	}
+	if (error)
+		return error;
 	header = IHDR(inode, ext4_raw_inode(&is->iloc));
 	if (!IS_LAST_ENTRY(s->first)) {
 		header->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC);
-- 
2.19.0.605.g01d371f741-goog

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 3.18.y 00/10] recent ext4 CVE fixes
  2018-10-04 17:53 [PATCH 3.18.y 00/10] recent ext4 CVE fixes Greg Hackmann
                   ` (9 preceding siblings ...)
  2018-10-04 17:53 ` [PATCH 3.18.y 10/10] ext4: avoid running out of journal credits when appending to an inline file Greg Hackmann
@ 2018-10-11  9:17 ` Greg KH
  10 siblings, 0 replies; 12+ messages in thread
From: Greg KH @ 2018-10-11  9:17 UTC (permalink / raw)
  To: Greg Hackmann; +Cc: stable, Theodore Ts'o, Greg Hackmann

On Thu, Oct 04, 2018 at 10:53:10AM -0700, Greg Hackmann wrote:
> A batch of ext4-related CVE fixes were released to other kernels in
> linux-stable, but don't apply cleanly to 3.18.y.  For the most part
> these are unmodified cherry-picks of Ben Hutchings's 3.16.y backports
> (exceptions are noted above my Signed-off-by).
> 
> Theodore Ts'o (10):
>   ext4: only look at the bg_flags field if it is valid
>   ext4: fix check to prevent initializing reserved inodes
>   ext4: always check block group bounds in ext4_init_block_bitmap()
>   ext4: fix false negatives *and* false positives in
>     ext4_check_descriptors()
>   ext4: add corruption check in ext4_xattr_set_entry()
>   ext4: always verify the magic number in xattr blocks
>   ext4: never move the system.data xattr out of the inode body
>   ext4: add more inode number paranoia checks
>   jbd2: don't mark block as modified if the handle is out of credits
>   ext4: avoid running out of journal credits when appending to an inline
>     file

All now applied, thanks.

greg k-h

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2018-10-11 16:43 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-10-04 17:53 [PATCH 3.18.y 00/10] recent ext4 CVE fixes Greg Hackmann
2018-10-04 17:53 ` [PATCH 3.18.y 01/10] ext4: only look at the bg_flags field if it is valid Greg Hackmann
2018-10-04 17:53 ` [PATCH 3.18.y 02/10] ext4: fix check to prevent initializing reserved inodes Greg Hackmann
2018-10-04 17:53 ` [PATCH 3.18.y 03/10] ext4: always check block group bounds in ext4_init_block_bitmap() Greg Hackmann
2018-10-04 17:53 ` [PATCH 3.18.y 04/10] ext4: fix false negatives *and* false positives in ext4_check_descriptors() Greg Hackmann
2018-10-04 17:53 ` [PATCH 3.18.y 05/10] ext4: add corruption check in ext4_xattr_set_entry() Greg Hackmann
2018-10-04 17:53 ` [PATCH 3.18.y 06/10] ext4: always verify the magic number in xattr blocks Greg Hackmann
2018-10-04 17:53 ` [PATCH 3.18.y 07/10] ext4: never move the system.data xattr out of the inode body Greg Hackmann
2018-10-04 17:53 ` [PATCH 3.18.y 08/10] ext4: add more inode number paranoia checks Greg Hackmann
2018-10-04 17:53 ` [PATCH 3.18.y 09/10] jbd2: don't mark block as modified if the handle is out of credits Greg Hackmann
2018-10-04 17:53 ` [PATCH 3.18.y 10/10] ext4: avoid running out of journal credits when appending to an inline file Greg Hackmann
2018-10-11  9:17 ` [PATCH 3.18.y 00/10] recent ext4 CVE fixes Greg KH

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.