]> www.infradead.org Git - users/hch/xfsprogs.git/commitdiff
xfs: fix an undefined behaviour in _da3_path_shift
authorQian Cai <cai@lca.pw>
Wed, 29 Apr 2020 20:08:34 +0000 (16:08 -0400)
committerEric Sandeen <sandeen@redhat.com>
Wed, 29 Apr 2020 20:08:34 +0000 (16:08 -0400)
Source kernel commit: 4982bff1ace1196843f55536fcd4cc119738fe39

In xfs_da3_path_shift() "blk" can be assigned to state->path.blk[-1] if
state->path.active is 1 (which is a valid state) when it tries to add an
entry to a single dir leaf block and then to shift forward to see if
there's a sibling block that would be a better place to put the new
entry. This causes a UBSAN warning given negative array indices are
undefined behavior in C. In practice the warning is entirely harmless
given that "blk" is never dereferenced in this case, but it is still
better to fix up the warning and slightly improve the code.

UBSAN: Undefined behaviour in fs/xfs/libxfs/xfs_da_btree.c:1989:14
index -1 is out of range for type 'xfs_da_state_blk_t [5]'
Call trace:
dump_backtrace+0x0/0x2c8
show_stack+0x20/0x2c
dump_stack+0xe8/0x150
__ubsan_handle_out_of_bounds+0xe4/0xfc
xfs_da3_path_shift+0x860/0x86c [xfs]
xfs_da3_node_lookup_int+0x7c8/0x934 [xfs]
xfs_dir2_node_addname+0x2c8/0xcd0 [xfs]
xfs_dir_createname+0x348/0x38c [xfs]
xfs_create+0x6b0/0x8b4 [xfs]
xfs_generic_create+0x12c/0x1f8 [xfs]
xfs_vn_mknod+0x3c/0x4c [xfs]
xfs_vn_create+0x34/0x44 [xfs]
do_last+0xd4c/0x10c8
path_openat+0xbc/0x2f4
do_filp_open+0x74/0xf4
do_sys_openat2+0x98/0x180
__arm64_sys_openat+0xf8/0x170
do_el0_svc+0x170/0x240
el0_sync_handler+0x150/0x250
el0_sync+0x164/0x180

Suggested-by: Christoph Hellwig <hch@infradead.org>
Signed-off-by: Qian Cai <cai@lca.pw>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
libxfs/xfs_da_btree.c

index 3f40e99ee22c2292cb77662f42f948fae996a23f..7f26d12439b822233ea4208b87d021fbe1f9b14e 100644 (file)
@@ -1983,7 +1983,8 @@ xfs_da3_path_shift(
        ASSERT(path != NULL);
        ASSERT((path->active > 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
        level = (path->active-1) - 1;   /* skip bottom layer in path */
-       for (blk = &path->blk[level]; level >= 0; blk--, level--) {
+       for (; level >= 0; level--) {
+               blk = &path->blk[level];
                xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr,
                                           blk->bp->b_addr);