Linux-ext4 Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH] ext4: Fix ext4_empty_dir() for directories with holes
@ 2019-11-27 13:12 Jan Kara
  2019-11-27 19:44 ` Theodore Y. Ts'o
  2019-11-27 20:00 ` Theodore Y. Ts'o
  0 siblings, 2 replies; 4+ messages in thread
From: Jan Kara @ 2019-11-27 13:12 UTC (permalink / raw)
  To: Ted Tso; +Cc: linux-ext4, Jan Kara, stable

Function ext4_empty_dir() doesn't correctly handle directories with
holes and crashes on bh->b_data dereference when bh is NULL. Reorganize
the loop to use 'offset' variable all the times instead of comparing
pointers to current direntry with bh->b_data pointer. Also add more
strict checking of '.' and '..' directory entries to avoid entering loop
in possibly invalid state on corrupted filesystems.

References: CVE-2019-19037
CC: stable@vger.kernel.org
Fixes: 4e19d6b65fb4 ("ext4: allow directory holes")
Signed-off-by: Jan Kara <jack@suse.cz>
---
 fs/ext4/namei.c | 32 ++++++++++++++++++--------------
 1 file changed, 18 insertions(+), 14 deletions(-)

diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index a427d2031a8d..91083eb9c203 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -2808,7 +2808,7 @@ bool ext4_empty_dir(struct inode *inode)
 {
 	unsigned int offset;
 	struct buffer_head *bh;
-	struct ext4_dir_entry_2 *de, *de1;
+	struct ext4_dir_entry_2 *de;
 	struct super_block *sb;
 
 	if (ext4_has_inline_data(inode)) {
@@ -2833,19 +2833,25 @@ bool ext4_empty_dir(struct inode *inode)
 		return true;
 
 	de = (struct ext4_dir_entry_2 *) bh->b_data;
-	de1 = ext4_next_entry(de, sb->s_blocksize);
-	if (le32_to_cpu(de->inode) != inode->i_ino ||
-			le32_to_cpu(de1->inode) == 0 ||
-			strcmp(".", de->name) || strcmp("..", de1->name)) {
-		ext4_warning_inode(inode, "directory missing '.' and/or '..'");
+	if (ext4_check_dir_entry(inode, NULL, de, bh, bh->b_data, bh->b_size,
+				 0) ||
+	    le32_to_cpu(de->inode) != inode->i_ino || strcmp(".", de->name)) {
+		ext4_warning_inode(inode, "directory missing '.'");
+		brelse(bh);
+		return true;
+	}
+	offset = ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize);
+	de = ext4_next_entry(de, sb->s_blocksize);
+	if (ext4_check_dir_entry(inode, NULL, de, bh, bh->b_data, bh->b_size,
+				 offset) ||
+	    le32_to_cpu(de->inode) == 0 || strcmp("..", de->name)) {
+		ext4_warning_inode(inode, "directory missing '..'");
 		brelse(bh);
 		return true;
 	}
-	offset = ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize) +
-		 ext4_rec_len_from_disk(de1->rec_len, sb->s_blocksize);
-	de = ext4_next_entry(de1, sb->s_blocksize);
+	offset += ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize);
 	while (offset < inode->i_size) {
-		if ((void *) de >= (void *) (bh->b_data+sb->s_blocksize)) {
+		if (!(offset & (sb->s_blocksize - 1))) {
 			unsigned int lblock;
 			brelse(bh);
 			lblock = offset >> EXT4_BLOCK_SIZE_BITS(sb);
@@ -2856,12 +2862,11 @@ bool ext4_empty_dir(struct inode *inode)
 			}
 			if (IS_ERR(bh))
 				return true;
-			de = (struct ext4_dir_entry_2 *) bh->b_data;
 		}
+		de = (struct ext4_dir_entry_2 *) bh->b_data +
+					(offset & (sb->s_blocksize - 1));
 		if (ext4_check_dir_entry(inode, NULL, de, bh,
 					 bh->b_data, bh->b_size, offset)) {
-			de = (struct ext4_dir_entry_2 *)(bh->b_data +
-							 sb->s_blocksize);
 			offset = (offset | (sb->s_blocksize - 1)) + 1;
 			continue;
 		}
@@ -2870,7 +2875,6 @@ bool ext4_empty_dir(struct inode *inode)
 			return false;
 		}
 		offset += ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize);
-		de = ext4_next_entry(de, sb->s_blocksize);
 	}
 	brelse(bh);
 	return true;
-- 
2.16.4


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

* Re: [PATCH] ext4: Fix ext4_empty_dir() for directories with holes
  2019-11-27 13:12 [PATCH] ext4: Fix ext4_empty_dir() for directories with holes Jan Kara
@ 2019-11-27 19:44 ` Theodore Y. Ts'o
  2019-11-27 19:53   ` Theodore Y. Ts'o
  2019-11-27 20:00 ` Theodore Y. Ts'o
  1 sibling, 1 reply; 4+ messages in thread
From: Theodore Y. Ts'o @ 2019-11-27 19:44 UTC (permalink / raw)
  To: Jan Kara; +Cc: linux-ext4, stable

On Wed, Nov 27, 2019 at 02:12:58PM +0100, Jan Kara wrote:
> Function ext4_empty_dir() doesn't correctly handle directories with
> holes and crashes on bh->b_data dereference when bh is NULL....

Hi Jan,

Thanks for the patch.

However, it looks like we're still vulnerable to the first block of
the directory being NULL?

> @@ -2833,19 +2833,25 @@ bool ext4_empty_dir(struct inode *inode)
>  		return true;
>  
>  	de = (struct ext4_dir_entry_2 *) bh->b_data;
                                         ^^^^^^^^^^^

						- Ted
							

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

* Re: [PATCH] ext4: Fix ext4_empty_dir() for directories with holes
  2019-11-27 19:44 ` Theodore Y. Ts'o
@ 2019-11-27 19:53   ` Theodore Y. Ts'o
  0 siblings, 0 replies; 4+ messages in thread
From: Theodore Y. Ts'o @ 2019-11-27 19:53 UTC (permalink / raw)
  To: Jan Kara; +Cc: linux-ext4, stable

On Wed, Nov 27, 2019 at 02:44:15PM -0500, Theodore Y. Ts'o wrote:
> On Wed, Nov 27, 2019 at 02:12:58PM +0100, Jan Kara wrote:
> > Function ext4_empty_dir() doesn't correctly handle directories with
> > holes and crashes on bh->b_data dereference when bh is NULL....
> 
> Hi Jan,
> 
> Thanks for the patch.
> 
> However, it looks like we're still vulnerable to the first block of
> the directory being NULL?
> 
> > @@ -2833,19 +2833,25 @@ bool ext4_empty_dir(struct inode *inode)
> >  		return true;
> >  
> >  	de = (struct ext4_dir_entry_2 *) bh->b_data;
>                                          ^^^^^^^^^^^

Ah, never mind.  Since we're calling ext4_read_dirblock() with
DIRENT_HTREE, if bh is NULL, it will get caught earlier, and
ext4_read_dirblock() will return ERR_PTR(-EFSCORRUPTED).

						- Ted

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

* Re: [PATCH] ext4: Fix ext4_empty_dir() for directories with holes
  2019-11-27 13:12 [PATCH] ext4: Fix ext4_empty_dir() for directories with holes Jan Kara
  2019-11-27 19:44 ` Theodore Y. Ts'o
@ 2019-11-27 20:00 ` Theodore Y. Ts'o
  1 sibling, 0 replies; 4+ messages in thread
From: Theodore Y. Ts'o @ 2019-11-27 20:00 UTC (permalink / raw)
  To: Jan Kara; +Cc: linux-ext4, stable

On Wed, Nov 27, 2019 at 02:12:58PM +0100, Jan Kara wrote:
> Function ext4_empty_dir() doesn't correctly handle directories with
> holes and crashes on bh->b_data dereference when bh is NULL. Reorganize
> the loop to use 'offset' variable all the times instead of comparing
> pointers to current direntry with bh->b_data pointer. Also add more
> strict checking of '.' and '..' directory entries to avoid entering loop
> in possibly invalid state on corrupted filesystems.
> 
> References: CVE-2019-19037
> CC: stable@vger.kernel.org
> Fixes: 4e19d6b65fb4 ("ext4: allow directory holes")
> Signed-off-by: Jan Kara <jack@suse.cz>

Thanks, applied.

					- Ted

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

end of thread, back to index

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-27 13:12 [PATCH] ext4: Fix ext4_empty_dir() for directories with holes Jan Kara
2019-11-27 19:44 ` Theodore Y. Ts'o
2019-11-27 19:53   ` Theodore Y. Ts'o
2019-11-27 20:00 ` Theodore Y. Ts'o

Linux-ext4 Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-ext4/0 linux-ext4/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-ext4 linux-ext4/ https://lore.kernel.org/linux-ext4 \
		linux-ext4@vger.kernel.org
	public-inbox-index linux-ext4

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-ext4


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git