From patchwork Wed Oct 24 02:55:24 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tao Ma X-Patchwork-Id: 193623 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 7BCC02C0189 for ; Wed, 24 Oct 2012 13:56:05 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S934307Ab2JXC4C (ORCPT ); Tue, 23 Oct 2012 22:56:02 -0400 Received: from oproxy6-pub.bluehost.com ([67.222.54.6]:37065 "HELO oproxy6-pub.bluehost.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with SMTP id S934280Ab2JXCz6 (ORCPT ); Tue, 23 Oct 2012 22:55:58 -0400 Received: (qmail 12549 invoked by uid 0); 24 Oct 2012 02:55:58 -0000 Received: from unknown (HELO box585.bluehost.com) (66.147.242.185) by cpoproxy3.bluehost.com with SMTP; 24 Oct 2012 02:55:58 -0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=tao.ma; s=default; h=References:In-Reply-To:Message-Id:Date:Subject:To:From; bh=b9DKBF9EGaDooCAyGh5y29rHbTvqK5VVNsspi+YjMIg=; b=amuuJ3Z/oDSVeYfKtHuIXNvuW9JuyRGqaY2fWRoxrQL7xCJzOj8SF26JQyuz2Syh8RLKik8DbCYfGf5Cqk3h7q9mZHaT0vt0wWNR75VeZ6tBx83MuYPiAl63NlCxROOi; Received: from [182.92.247.2] (port=23186 helo=tma-laptop1.taobao.ali.com) by box585.bluehost.com with esmtpsa (TLSv1:AES256-SHA:256) (Exim 4.76) (envelope-from ) id 1TQr8P-0006KI-JN for linux-ext4@vger.kernel.org; Tue, 23 Oct 2012 20:55:58 -0600 From: Tao Ma To: linux-ext4@vger.kernel.org Subject: [PATCH V7 09/23] ext4: Refactor __ext4_check_dir_entry to accepts start and size. Date: Wed, 24 Oct 2012 10:55:24 +0800 Message-Id: <1351047338-4963-9-git-send-email-tm@tao.ma> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1351047338-4963-1-git-send-email-tm@tao.ma> References: <1351047002-4723-1-git-send-email-tm@tao.ma> <1351047338-4963-1-git-send-email-tm@tao.ma> X-Identified-User: {1390:box585.bluehost.com:colyli:tao.ma} {sentby:smtp auth 182.92.247.2 authed with tm@tao.ma} Sender: linux-ext4-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-ext4@vger.kernel.org From: Tao Ma __ext4_check_dir_entry is used to check whether the de is over the block boundary. Now with inline data, it could be within the block boundary while exceeds the inode size. So check this function to check the overflow more precisely. Signed-off-by: Tao Ma --- fs/ext4/dir.c | 16 ++++++++-------- fs/ext4/ext4.h | 7 ++++--- fs/ext4/namei.c | 13 +++++++++---- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c index 8e07d2a..7c9d08b 100644 --- a/fs/ext4/dir.c +++ b/fs/ext4/dir.c @@ -72,7 +72,7 @@ static int is_dx_dir(struct inode *inode) int __ext4_check_dir_entry(const char *function, unsigned int line, struct inode *dir, struct file *filp, struct ext4_dir_entry_2 *de, - struct buffer_head *bh, + struct buffer_head *bh, char *buf, int size, unsigned int offset) { const char *error_msg = NULL; @@ -85,9 +85,8 @@ int __ext4_check_dir_entry(const char *function, unsigned int line, error_msg = "rec_len % 4 != 0"; else if (unlikely(rlen < EXT4_DIR_REC_LEN(de->name_len))) error_msg = "rec_len is too small for name_len"; - else if (unlikely(((char *) de - bh->b_data) + rlen > - dir->i_sb->s_blocksize)) - error_msg = "directory entry across blocks"; + else if (unlikely(((char *) de - buf) + rlen > size)) + error_msg = "directory entry across range"; else if (unlikely(le32_to_cpu(de->inode) > le32_to_cpu(EXT4_SB(dir->i_sb)->s_es->s_inodes_count))) error_msg = "inode out of bounds"; @@ -98,14 +97,14 @@ int __ext4_check_dir_entry(const char *function, unsigned int line, ext4_error_file(filp, function, line, bh->b_blocknr, "bad entry in directory: %s - offset=%u(%u), " "inode=%u, rec_len=%d, name_len=%d", - error_msg, (unsigned) (offset % bh->b_size), + error_msg, (unsigned) (offset % size), offset, le32_to_cpu(de->inode), rlen, de->name_len); else ext4_error_inode(dir, function, line, bh->b_blocknr, "bad entry in directory: %s - offset=%u(%u), " "inode=%u, rec_len=%d, name_len=%d", - error_msg, (unsigned) (offset % bh->b_size), + error_msg, (unsigned) (offset % size), offset, le32_to_cpu(de->inode), rlen, de->name_len); @@ -221,8 +220,9 @@ revalidate: while (!error && filp->f_pos < inode->i_size && offset < sb->s_blocksize) { de = (struct ext4_dir_entry_2 *) (bh->b_data + offset); - if (ext4_check_dir_entry(inode, filp, de, - bh, offset)) { + if (ext4_check_dir_entry(inode, filp, de, bh, + bh->b_data, bh->b_size, + offset)) { /* * On error, skip the f_pos to the next block */ diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 8b56db1..cc889a4 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -1943,10 +1943,11 @@ ext4_fsblk_t ext4_inode_to_goal_block(struct inode *); extern int __ext4_check_dir_entry(const char *, unsigned int, struct inode *, struct file *, struct ext4_dir_entry_2 *, - struct buffer_head *, unsigned int); -#define ext4_check_dir_entry(dir, filp, de, bh, offset) \ + struct buffer_head *, char *, int, + unsigned int); +#define ext4_check_dir_entry(dir, filp, de, bh, buf, size, offset) \ unlikely(__ext4_check_dir_entry(__func__, __LINE__, (dir), (filp), \ - (de), (bh), (offset))) + (de), (bh), (buf), (size), (offset))) extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash, __u32 minor_hash, struct ext4_dir_entry_2 *dirent); diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index dcf1be7..4f1c9f5 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -890,6 +890,7 @@ static int htree_dirblock_to_tree(struct file *dir_file, EXT4_DIR_REC_LEN(0)); for (; de < top; de = ext4_next_entry(de, dir->i_sb->s_blocksize)) { if (ext4_check_dir_entry(dir, NULL, de, bh, + bh->b_data, bh->b_size, (block<i_sb)) + ((char *)de - bh->b_data))) { /* On error, skip the f_pos to the next block. */ @@ -1128,7 +1129,8 @@ static inline int search_dirblock(struct buffer_head *bh, if ((char *) de + namelen <= dlimit && ext4_match (namelen, name, de)) { /* found a match - just to be sure, do a full check */ - if (ext4_check_dir_entry(dir, NULL, de, bh, offset)) + if (ext4_check_dir_entry(dir, NULL, de, bh, bh->b_data, + bh->b_size, offset)) return -1; *res_dir = de; return 1; @@ -1624,7 +1626,8 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, de = (struct ext4_dir_entry_2 *)bh->b_data; top = bh->b_data + (blocksize - csum_size) - reclen; while ((char *) de <= top) { - if (ext4_check_dir_entry(dir, NULL, de, bh, offset)) + if (ext4_check_dir_entry(dir, NULL, de, bh, bh->b_data, + bh->b_size, offset)) return -EIO; if (ext4_match(namelen, name, de)) return -EEXIST; @@ -2057,7 +2060,8 @@ static int ext4_delete_entry(handle_t *handle, pde = NULL; de = (struct ext4_dir_entry_2 *) bh->b_data; while (i < bh->b_size - csum_size) { - if (ext4_check_dir_entry(dir, NULL, de, bh, i)) + if (ext4_check_dir_entry(dir, NULL, de, bh, + bh->b_data, bh->b_size, i)) return -EIO; if (de == de_del) { BUFFER_TRACE(bh, "get_write_access"); @@ -2420,7 +2424,8 @@ static int empty_dir(struct inode *inode) set_buffer_verified(bh); de = (struct ext4_dir_entry_2 *) bh->b_data; } - if (ext4_check_dir_entry(inode, NULL, de, bh, offset)) { + 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;