From owner-dev-commits-src-main@freebsd.org Fri May 7 07:28:30 2021 Return-Path: Delivered-To: dev-commits-src-main@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id BC9515FA9A6; Fri, 7 May 2021 07:28:30 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4Fc29p4zT6z3nG8; Fri, 7 May 2021 07:28:30 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 995BB273B6; Fri, 7 May 2021 07:28:30 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 1477SURp085482; Fri, 7 May 2021 07:28:30 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 1477SUBo085481; Fri, 7 May 2021 07:28:30 GMT (envelope-from git) Date: Fri, 7 May 2021 07:28:30 GMT Message-Id: <202105070728.1477SUBo085481@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Fedor Uporov Subject: git: 5679656e09fb - main - Improve extents verification logic. MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: fsu X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 5679656e09fb58254da1613ebda75e368074c507 Auto-Submitted: auto-generated X-BeenThere: dev-commits-src-main@freebsd.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Commit messages for the main branch of the src repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 07 May 2021 07:28:30 -0000 The branch main has been updated by fsu: URL: https://cgit.FreeBSD.org/src/commit/?id=5679656e09fb58254da1613ebda75e368074c507 commit 5679656e09fb58254da1613ebda75e368074c507 Author: Fedor Uporov AuthorDate: 2021-02-18 07:48:10 +0000 Commit: Fedor Uporov CommitDate: 2021-05-07 07:27:28 +0000 Improve extents verification logic. It is possible to walk thru inode extents if EXT2FS_PRINT_EXTENTS macro is defined. The extents headers magics and physical blocks ranges are checked during extents walk. Reviewed by: pfg MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D29932 --- sys/fs/ext2fs/ext2_extents.c | 130 ++++++++++++++++++++++++++++------------- sys/fs/ext2fs/ext2_extents.h | 10 ++-- sys/fs/ext2fs/ext2_inode_cnv.c | 2 +- sys/fs/ext2fs/ext2_vfsops.c | 11 +++- sys/fs/ext2fs/fs.h | 2 +- 5 files changed, 104 insertions(+), 51 deletions(-) diff --git a/sys/fs/ext2fs/ext2_extents.c b/sys/fs/ext2fs/ext2_extents.c index 1a5dca66dd76..cc77107785a5 100644 --- a/sys/fs/ext2fs/ext2_extents.c +++ b/sys/fs/ext2fs/ext2_extents.c @@ -59,94 +59,140 @@ SDT_PROBE_DEFINE2(ext2fs, , trace, extents, "int", "char*"); static MALLOC_DEFINE(M_EXT2EXTENTS, "ext2_extents", "EXT2 extents"); #ifdef EXT2FS_PRINT_EXTENTS -static void -ext4_ext_print_extent(struct ext4_extent *ep) +static const bool print_extents_walk = true; + +static int ext4_ext_check_header(struct inode *, struct ext4_extent_header *); +static int ext4_ext_walk_header(struct inode *, struct ext4_extent_header *); +static inline e4fs_daddr_t ext4_ext_index_pblock(struct ext4_extent_index *); +static inline e4fs_daddr_t ext4_ext_extent_pblock(struct ext4_extent *); + +static int +ext4_ext_blk_check(struct inode *ip, e4fs_daddr_t blk) { + struct m_ext2fs *fs; - printf(" ext %p => (blk %u len %u start %ju)\n", - ep, le32toh(ep->e_blk), le16toh(ep->e_len), - (uint64_t)le16toh(ep->e_start_hi) << 32 | le32toh(ep->e_start_lo)); -} + fs = ip->i_e2fs; -static void ext4_ext_print_header(struct inode *ip, struct ext4_extent_header *ehp); + if (blk < fs->e2fs->e2fs_first_dblock || blk >= fs->e2fs_bcount) + return (EIO); -static void -ext4_ext_print_index(struct inode *ip, struct ext4_extent_index *ex, int do_walk) + return (0); +} + +static int +ext4_ext_walk_index(struct inode *ip, struct ext4_extent_index *ex, bool do_walk) { struct m_ext2fs *fs; struct buf *bp; + e4fs_daddr_t blk; int error; fs = ip->i_e2fs; - printf(" index %p => (blk %u pblk %ju)\n", - ex, le32toh(ex->ei_blk), (uint64_t)le16toh(ex->ei_leaf_hi) << 32 | - le32toh(ex->ei_leaf_lo)); + if (print_extents_walk) + printf(" index %p => (blk %u pblk %ju)\n", ex, + le32toh(ex->ei_blk), (uint64_t)le16toh(ex->ei_leaf_hi) << 32 | + le32toh(ex->ei_leaf_lo)); if(!do_walk) - return; + return (0); + + blk = ext4_ext_index_pblock(ex); + error = ext4_ext_blk_check(ip, blk); + if (error) + return (error); if ((error = bread(ip->i_devvp, - fsbtodb(fs, ((uint64_t)le16toh(ex->ei_leaf_hi) << 32 | - le32toh(ex->ei_leaf_lo))), (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) { + fsbtodb(fs, blk), (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) { brelse(bp); - return; + return (error); } - ext4_ext_print_header(ip, (struct ext4_extent_header *)bp->b_data); + error = ext4_ext_walk_header(ip, (struct ext4_extent_header *)bp->b_data); brelse(bp); + return (error); } -static void -ext4_ext_print_header(struct inode *ip, struct ext4_extent_header *ehp) +static int +ext4_ext_walk_extent(struct inode *ip, struct ext4_extent *ep) +{ + e4fs_daddr_t blk; + int error; + + blk = ext4_ext_extent_pblock(ep); + error = ext4_ext_blk_check(ip, blk); + if (error) + return (error); + + if (print_extents_walk) + printf(" ext %p => (blk %u len %u start %ju)\n", + ep, le32toh(ep->e_blk), le16toh(ep->e_len), + (uint64_t)blk); + + return (0); +} + +static int +ext4_ext_walk_header(struct inode *ip, struct ext4_extent_header *eh) { - int i; + int i, error = 0; - printf("header %p => (magic 0x%x entries %d max %d depth %d gen %d)\n", - ehp, le16toh(ehp->eh_magic), le16toh(ehp->eh_ecount), - le16toh(ehp->eh_max), le16toh(ehp->eh_depth), le32toh(ehp->eh_gen)); + error = ext4_ext_check_header(ip, eh); + if (error) + return (error); + + if (print_extents_walk) + printf("header %p => (entries %d max %d depth %d gen %d)\n", + eh, le16toh(eh->eh_ecount), + le16toh(eh->eh_max), le16toh(eh->eh_depth), le32toh(eh->eh_gen)); - for (i = 0; i < le16toh(ehp->eh_ecount); i++) - if (ehp->eh_depth != 0) - ext4_ext_print_index(ip, - (struct ext4_extent_index *)(ehp + 1 + i), 1); + for (i = 0; i < le16toh(eh->eh_ecount) && error == 0; i++) + if (eh->eh_depth != 0) + error = ext4_ext_walk_index(ip, + (struct ext4_extent_index *)(eh + 1 + i), true); else - ext4_ext_print_extent((struct ext4_extent *)(ehp + 1 + i)); + error = ext4_ext_walk_extent(ip, (struct ext4_extent *)(eh + 1 + i)); + + return (error); } -static void +static int ext4_ext_print_path(struct inode *ip, struct ext4_extent_path *path) { - int k, l; + int k, l, error = 0; l = path->ep_depth; - printf("ip=%ju, Path:\n", ip->i_number); - for (k = 0; k <= l; k++, path++) { + if (print_extents_walk) + printf("ip=%ju, Path:\n", ip->i_number); + + for (k = 0; k <= l && error == 0; k++, path++) { if (path->ep_index) { - ext4_ext_print_index(ip, path->ep_index, 0); + error = ext4_ext_walk_index(ip, path->ep_index, false); } else if (path->ep_ext) { - ext4_ext_print_extent(path->ep_ext); + error = ext4_ext_walk_extent(ip, path->ep_ext); } } + + return (error); } -void -ext4_ext_print_extent_tree_status(struct inode *ip) +int +ext4_ext_walk(struct inode *ip) { struct ext4_extent_header *ehp; - ehp = (struct ext4_extent_header *)(char *)ip->i_db; + ehp = (struct ext4_extent_header *)ip->i_db; - printf("Extent status:ip=%ju\n", ip->i_number); - if (!(ip->i_flag & IN_E4EXTENTS)) - return; + if (print_extents_walk) + printf("Extent status:ip=%ju\n", ip->i_number); - ext4_ext_print_header(ip, ehp); + if (!(ip->i_flag & IN_E4EXTENTS)) + return (0); - return; + return (ext4_ext_walk_header(ip, ehp)); } #endif diff --git a/sys/fs/ext2fs/ext2_extents.h b/sys/fs/ext2fs/ext2_extents.h index 52a96297b606..f662cc9b5cd3 100644 --- a/sys/fs/ext2fs/ext2_extents.h +++ b/sys/fs/ext2fs/ext2_extents.h @@ -122,15 +122,15 @@ struct m_ext2fs; void ext4_ext_tree_init(struct inode *ip); int ext4_ext_in_cache(struct inode *, daddr_t, struct ext4_extent *); void ext4_ext_put_cache(struct inode *, struct ext4_extent *, int); -int ext4_ext_find_extent(struct inode *, daddr_t, struct ext4_extent_path **); -void ext4_ext_path_free(struct ext4_extent_path *path); -int ext4_ext_remove_space(struct inode *ip, off_t length, int flags, +int ext4_ext_find_extent(struct inode *, daddr_t, struct ext4_extent_path **); +void ext4_ext_path_free(struct ext4_extent_path *path); +int ext4_ext_remove_space(struct inode *ip, off_t length, int flags, struct ucred *cred, struct thread *td); -int ext4_ext_get_blocks(struct inode *ip, int64_t iblock, +int ext4_ext_get_blocks(struct inode *ip, int64_t iblock, unsigned long max_blocks, struct ucred *cred, struct buf **bpp, int *allocate, daddr_t *); #ifdef EXT2FS_PRINT_EXTENTS -void ext4_ext_print_extent_tree_status(struct inode *ip); +int ext4_ext_walk(struct inode *ip); #endif #endif /* !_FS_EXT2FS_EXT2_EXTENTS_H_ */ diff --git a/sys/fs/ext2fs/ext2_inode_cnv.c b/sys/fs/ext2fs/ext2_inode_cnv.c index a71d5cef21aa..3c79e1162896 100644 --- a/sys/fs/ext2fs/ext2_inode_cnv.c +++ b/sys/fs/ext2fs/ext2_inode_cnv.c @@ -86,7 +86,7 @@ ext2_print_inode(struct inode *in) le16toh(ep->e_start_hi)); printf("\n"); } else { - printf("BLOCKS:"); + printf("Blocks:"); for (i = 0; i < (in->i_blocks <= 24 ? (in->i_blocks + 1) / 2 : 12); i++) printf(" %d", in->i_db[i]); printf("\n"); diff --git a/sys/fs/ext2fs/ext2_vfsops.c b/sys/fs/ext2fs/ext2_vfsops.c index 099d6bfec981..43cfdf3a1a0b 100644 --- a/sys/fs/ext2fs/ext2_vfsops.c +++ b/sys/fs/ext2fs/ext2_vfsops.c @@ -1283,11 +1283,18 @@ ext2_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) for (i = used_blocks; i < EXT2_NDIR_BLOCKS; i++) ip->i_db[i] = 0; } + + bqrelse(bp); + #ifdef EXT2FS_PRINT_EXTENTS ext2_print_inode(ip); - ext4_ext_print_extent_tree_status(ip); + error = ext4_ext_walk(ip); + if (error) { + vput(vp); + *vpp = NULL; + return (error); + } #endif - bqrelse(bp); /* * Initialize the vnode from the inode, check for aliases. diff --git a/sys/fs/ext2fs/fs.h b/sys/fs/ext2fs/fs.h index e07b69b91bce..c09200af3935 100644 --- a/sys/fs/ext2fs/fs.h +++ b/sys/fs/ext2fs/fs.h @@ -164,6 +164,6 @@ /* * Use if additional debug logging is required. */ -/* #define EXT2FS_PRINT_EXTENTS */ +/* #define EXT2FS_PRINT_EXTENTS */ #endif /* !_FS_EXT2FS_FS_H_ */