btrfs-progs: reorganize extent_buffer and fix alignment of data
authorDavid Sterba <dsterba@suse.com>
Mon, 12 Sep 2016 09:13:24 +0000 (11:13 +0200)
committerDavid Sterba <dsterba@suse.com>
Wed, 21 Sep 2016 09:50:05 +0000 (11:50 +0200)
Reported by UBSAN, the checksum code tries to access unaligned data that
come from the extent_buffer.

struct extent_buffer {
        struct cache_extent        cache_node;           /*     0    48 */
        u64                        start;                /*    48     8 */
        u64                        dev_bytenr;           /*    56     8 */
        /* --- cacheline 1 boundary (64 bytes) --- */
        u32                        len;                  /*    64     4 */

        /* XXX 4 bytes hole, try to pack */

        struct extent_io_tree *    tree;                 /*    72     8 */
        struct list_head           lru;                  /*    80    16 */
        struct list_head           recow;                /*    96    16 */
        int                        refs;                 /*   112     4 */
        u32                        flags;                /*   116     4 */
        int                        fd;                   /*   120     4 */
        char                       data[0];              /*   124     0 */

        /* size: 128, cachelines: 2, members: 11 */
        /* sum members: 120, holes: 1, sum holes: 4 */
        /* padding: 4 */
};

Add explicit alignment to data.

Reported-by: Lukas Lueg <lukas.lueg@gmail.com>
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=156471
Signed-off-by: David Sterba <dsterba@suse.com>
extent_io.h
tests/fuzz-tests/images/bko-156471-ubsan-trigger-crc32c-unaligned.raw.txt [new file with mode: 0644]
tests/fuzz-tests/images/bko-156471-ubsan-trigger-crc32c-unaligned.raw.xz [new file with mode: 0644]

index d9594c3..208c4fe 100644 (file)
@@ -97,7 +97,7 @@ struct extent_buffer {
        int refs;
        u32 flags;
        int fd;
-       char data[];
+       char data[] __attribute__((aligned(8)));
 };
 
 static inline void extent_buffer_get(struct extent_buffer *eb)
diff --git a/tests/fuzz-tests/images/bko-156471-ubsan-trigger-crc32c-unaligned.raw.txt b/tests/fuzz-tests/images/bko-156471-ubsan-trigger-crc32c-unaligned.raw.txt
new file mode 100644 (file)
index 0000000..c827963
--- /dev/null
@@ -0,0 +1,62 @@
+URL: https://bugzilla.kernel.org/show_bug.cgi?id=156471
+Lukas Lueg 2016-09-09 18:58:27 UTC
+
+More news from the fuzzer and (up to now) the only news from UBSAN using
+btrfs-progs v4.7-42-g56e9586. The attached image causes btrfsck to trigger
+undefined behavior by dereferencing a ptr to a long unsigned int that was cast
+from an uchar with no alignment guarantees.
+
+UBSAN complains:
+crc32c.c:75:19: runtime error: load of misaligned address 0x000001b3736c for
+type 'long unsigned int', which requires 8 byte alignment
+
+I've attached an image and a log, the behavior is triggered all the time and
+unspecific, though.
+
+AFAIC the problem is that *ptmp is cast from *data. This may actually not cause
+the CPU to fault due to how *data is de-facto aligned by it's callers. The code
+may still cause nose demons as the pure act of having *ptmp is undefined
+behavior.
+
+crc32c.c:75:19: runtime error: load of misaligned address 0x000001b3736c for type 'long unsigned int', which requires 8 byte alignment
+0x000001b3736c: note: pointer points here
+  00 00 00 00 b7 0e 65 6c  64 61 40 4b a5 0d 0f ba  33 0c 75 27 00 00 02 00  00 00 00 00 01 00 00 00
+              ^ 
+    #0 0x4f4308 in crc32c_intel /home/lukas/dev/btrfsfuzz/src-ubsan/crc32c.c:75
+    #1 0x4f43f3 in crc32c_le /home/lukas/dev/btrfsfuzz/src-ubsan/crc32c.c:221
+    #2 0x486c39 in __csum_tree_block_size /home/lukas/dev/btrfsfuzz/src-ubsan/disk-io.c:139
+    #3 0x486c39 in csum_tree_block_size /home/lukas/dev/btrfsfuzz/src-ubsan/disk-io.c:159
+    #4 0x486d48 in csum_tree_block_fs_info /home/lukas/dev/btrfsfuzz/src-ubsan/disk-io.c:174
+    #5 0x48ba29 in read_tree_block_fs_info /home/lukas/dev/btrfsfuzz/src-ubsan/disk-io.c:348
+    #6 0x48d48d in read_tree_block /home/lukas/dev/btrfsfuzz/src-ubsan/disk-io.h:112
+    #7 0x48d48d in btrfs_setup_chunk_tree_and_device_map /home/lukas/dev/btrfsfuzz/src-ubsan/disk-io.c:1210
+    #8 0x48d95b in __open_ctree_fd /home/lukas/dev/btrfsfuzz/src-ubsan/disk-io.c:1322
+    #9 0x48dd80 in open_ctree_fs_info /home/lukas/dev/btrfsfuzz/src-ubsan/disk-io.c:1381
+    #10 0x45011a in cmd_check /home/lukas/dev/btrfsfuzz/src-ubsan/cmds-check.c:11449
+    #11 0x40a799 in main /home/lukas/dev/btrfsfuzz/src-ubsan/btrfs.c:243
+    #12 0x7fdf11c96730 in __libc_start_main (/lib64/libc.so.6+0x20730)
+    #13 0x40a1e8 in _start (/home/lukas/dev/btrfsfuzz/bin-ubsan/bin/btrfs+0x40a1e8)
+
+key (3472328296227680304 INODE_EXTREF 3472328296227680304)slot end outside of leaf 12360 > 3995
+parent transid verify failed on 4227072 wanted 3472328296227680304 found 4
+Ignoring transid failure
+checking extents
+Checking filesystem on ubsan_logs/id:000990,src:000816,op:flip1,pos:3845.img
+UUID: b70e656c-6461-404b-a50d-0fba330c7527
+key (3472328296227680304 INODE_EXTREF 3472328296227680304)slot end outside of leaf 12360 > 3995
+Invalid key type(ROOT_ITEM) found in root(3472328296227680304)
+ignoring invalid key
+Invalid key type(ROOT_ITEM) found in root(3472328296227680304)
+ignoring invalid key
+Invalid key type(ROOT_ITEM) found in root(3472328296227680304)
+ignoring invalid key
+Invalid key type(ROOT_ITEM) found in root(3472328296227680304)
+ignoring invalid key
+key (3472328296227680304 INODE_EXTREF 3472328296227680304)slot end outside of leaf 12360 > 3995
+key (3472328296227680304 INODE_EXTREF 3472328296227680304)slot end outside of leaf 12360 > 3995
+key (3472328296227680304 INODE_EXTREF 3472328296227680304)slot end outside of leaf 12360 > 3995
+key (3472328296227680304 INODE_EXTREF 3472328296227680304)slot end outside of leaf 12360 > 3995
+key (3472328296227680304 INODE_EXTREF 3472328296227680304)slot end outside of leaf 12360 > 3995
+bad block 4202496
+Errors found in extent allocation tree or chunk allocation
+key (3472328296227680304 INODE_EXTREF 3472328296227680304)slot end outside of leaf 12360 > 3995
diff --git a/tests/fuzz-tests/images/bko-156471-ubsan-trigger-crc32c-unaligned.raw.xz b/tests/fuzz-tests/images/bko-156471-ubsan-trigger-crc32c-unaligned.raw.xz
new file mode 100644 (file)
index 0000000..ee5778a
Binary files /dev/null and b/tests/fuzz-tests/images/bko-156471-ubsan-trigger-crc32c-unaligned.raw.xz differ