Received: by 2002:a25:8b91:0:0:0:0:0 with SMTP id j17csp13340306ybl; Sun, 29 Dec 2019 09:39:21 -0800 (PST) X-Google-Smtp-Source: APXvYqxlQ9YATRUVYHZS4eJJ+JRozxnqNXFTEbV8iuMb/XqNVcH3z2w3V3zp1E/IGNR7lAH3wxoD X-Received: by 2002:a9d:7593:: with SMTP id s19mr65511344otk.219.1577641161416; Sun, 29 Dec 2019 09:39:21 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1577641161; cv=none; d=google.com; s=arc-20160816; b=piPIsZYjCSGqn3jzVpZyi8eFZcdG5kbl7JDGe7qIHqmmTMJ2oqXsgcEzWFMJjQ2OVv 9XdWwAr977uUga/X+L0x6wosHtw2PsqnBMPep09cmv07AhfdHcxcyMCngTs7kBtZH5l2 S377CYPjbYnxkgsq0pdpqG8JggKueAR7Brf+2yvSonxuGZm205zKSDlLHFZQhkgyVDsJ WxbkFSvq5CZbrvfikPLFual3VpADiHy07smcE5wjWARdC9B2orAh6uidUQiN7rNurp93 IHjuOtDrq9pbsxGVsrAIvSrL90n4U3Canauidt3I7Fncu3O/+/Le98Qvcd2MAF955gt9 Nn3A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=XxNlGUJF+DVpJi3JjqdUgJPgew2O961XRFuufRpVkn8=; b=mqPOl0ZndsMoAIfNsQRmZBLEffo9YOwH2JyxumfSe/FcorepuDlbVTu1GJctTO55pG DaGXrx3tA8bnsvshTEJv7Hau7rDD9rpgBG2o4k8soBoqsY77gi/fcwAyPsxnOsqrcxo7 C+NbdclMq5ccXczlbLDGfJt06X66cbjWVOxZuv3K4Gu60voj5gJi38qqUUvhA8RINC5h 10Kl7U6StbAv8FyBelvgSIJj/QPk4NAJ6641u2KYywO2lE327Zxhho2XuDGVhaEM1MJz u26Q7OZfTKWxKX1fULJsZ7qfEAfAv7V6v+v0nwGvfS8KwyUqaTuqXeZjwEXx8w2WfGqv WVyw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b="0xULnz/W"; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id z1si22393792otq.21.2019.12.29.09.39.10; Sun, 29 Dec 2019 09:39:21 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b="0xULnz/W"; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729749AbfL2Rfx (ORCPT + 99 others); Sun, 29 Dec 2019 12:35:53 -0500 Received: from mail.kernel.org ([198.145.29.99]:40604 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729964AbfL2Rfw (ORCPT ); Sun, 29 Dec 2019 12:35:52 -0500 Received: from localhost (83-86-89-107.cable.dynamic.v4.ziggo.nl [83.86.89.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id CFFBF206CB; Sun, 29 Dec 2019 17:35:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1577640951; bh=c7pI5BPeRWKvFov9jV9dvlOvr4Gl0cF47WHKEiQfKFs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=0xULnz/WnWjZPatB0RwpbC8K5TN7i0TilQviC1ODSUbHQJDBAabulpFdb6spQMfBb uiioo5uaXu+KMpZDMFvZ5wJD+RqYgGbfMCNf1dz3XlBs+jI6uupKGNCSTefo2YeXI/ 8Deb53FXdiOs1+FRjEwYCg4ycNVnX0lbAQEYbKfo= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Jan Kara , Theodore Tso Subject: [PATCH 4.19 205/219] ext4: fix ext4_empty_dir() for directories with holes Date: Sun, 29 Dec 2019 18:20:07 +0100 Message-Id: <20191229162541.106375449@linuxfoundation.org> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20191229162508.458551679@linuxfoundation.org> References: <20191229162508.458551679@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Jan Kara commit 64d4ce892383b2ad6d782e080d25502f91bf2a38 upstream. 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. CC: stable@vger.kernel.org Fixes: 4e19d6b65fb4 ("ext4: allow directory holes") Signed-off-by: Jan Kara Link: https://lore.kernel.org/r/20191202170213.4761-2-jack@suse.cz Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman --- fs/ext4/namei.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -2693,7 +2693,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)) { @@ -2718,19 +2718,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) + - 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); + 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); 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); @@ -2741,12 +2747,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; } @@ -2755,7 +2760,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;