]> www.infradead.org Git - mtd-utils.git/commitdiff
tests: ubifs_tools: fsck_tests: Add corrupt+fsck+fault_inject test
authorZhihao Cheng <chengzhihao1@huawei.com>
Mon, 11 Nov 2024 09:08:22 +0000 (17:08 +0800)
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>
Mon, 11 Nov 2024 09:32:46 +0000 (10:32 +0100)
Inject memory/io fault while doing fsck for corrupted UBIFS images.
This testcase mainly checks whether fsck.ubifs has problems (eg.
UAF, null-ptr-def, etc.) in random error paths. Besides, it provides
a similar way to simulate powercut during fsck, and checks whether
the fsck.ubifs can fix an UBIFS image after many rounds interrupted
by kinds of errors.

Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
.gitignore
configure.ac
tests/ubifs_tools-tests/Makemodule.am
tests/ubifs_tools-tests/fsck_tests/cycle_corrupted_fsck_fault_inject.sh.in [new file with mode: 0755]
tests/ubifs_tools-tests/lib/common.sh.in

index b63b98686b6584d07baadaa63e0acd3f7db9be20..ea99a6143e7735e7ba695b322669654cb9249fa7 100644 (file)
@@ -117,6 +117,7 @@ tests/ubifs_tools-tests/lib/common.sh
 tests/ubifs_tools-tests/fsck_tests/authentication_refuse.sh
 tests/ubifs_tools-tests/fsck_tests/cycle_mount_fsck_check.sh
 tests/ubifs_tools-tests/fsck_tests/powercut_fsck_mount.sh
+tests/ubifs_tools-tests/fsck_tests/cycle_corrupted_fsck_fault_inject.sh
 
 #
 # Files generated by autotools
index 460109e7c37a35b07740d08ddaf544bf033f79d7..47efd40c85f6c6c2b7bf6dc994038f5468d2f231 100644 (file)
@@ -296,7 +296,8 @@ AC_CONFIG_FILES([tests/fs-tests/fs_help_all.sh
        tests/ubifs_tools-tests/lib/common.sh
        tests/ubifs_tools-tests/fsck_tests/authentication_refuse.sh
        tests/ubifs_tools-tests/fsck_tests/cycle_mount_fsck_check.sh
-       tests/ubifs_tools-tests/fsck_tests/powercut_fsck_mount.sh])
+       tests/ubifs_tools-tests/fsck_tests/powercut_fsck_mount.sh
+       tests/ubifs_tools-tests/fsck_tests/cycle_corrupted_fsck_fault_inject.sh])
 
 AC_OUTPUT([Makefile])
 
index d54514da3344c3a4ab4cd94d300cbf6a9816c3cb..932a2bcb8cb0ded2ec73c69c9434d5be78342b1b 100644 (file)
@@ -2,4 +2,5 @@ test_SCRIPTS += \
        tests/ubifs_tools-tests/lib/common.sh \
        tests/ubifs_tools-tests/fsck_tests/authentication_refuse.sh \
        tests/ubifs_tools-tests/fsck_tests/cycle_mount_fsck_check.sh \
-       tests/ubifs_tools-tests/fsck_tests/powercut_fsck_mount.sh
+       tests/ubifs_tools-tests/fsck_tests/powercut_fsck_mount.sh \
+       tests/ubifs_tools-tests/fsck_tests/cycle_corrupted_fsck_fault_inject.sh
diff --git a/tests/ubifs_tools-tests/fsck_tests/cycle_corrupted_fsck_fault_inject.sh.in b/tests/ubifs_tools-tests/fsck_tests/cycle_corrupted_fsck_fault_inject.sh.in
new file mode 100755 (executable)
index 0000000..2073fec
--- /dev/null
@@ -0,0 +1,225 @@
+#!/bin/sh
+# Copyright (c), 2024, Huawei Technologies Co, Ltd.
+# Author: Zhihao Cheng <chengzhihao1@huawei.com>
+#
+# Test Description:
+# For many kinds of flash, do following things
+#  1. mount UBIFS
+#  2. fsstress && unmount
+#  3. inject corruption into UBIFS image randomly
+#  3. fsck UBIFS && inject kinds of errors(memory, io)
+#  4. check UBIFS mounting result
+# Running time: 15min
+
+TESTBINDIR=@TESTBINDIR@
+source $TESTBINDIR/common.sh
+
+function run_test()
+{
+       local simulator="$1";
+       local size="$2";
+       local peb_size="$3";
+       local page_size="$4";
+       local encryption=$5;
+
+       echo "======================================================================"
+       printf "%s" "$simulator: ${size}MiB PEB size ${peb_size}KiB"
+       if [ "$simulator" = "nandsim" ]; then
+               printf " %s" "page size ${page_size}Bytes"
+       fi
+       printf " $encryption\n"
+
+       if [ "$simulator" = "nandsim" ]; then
+               $TESTBINDIR/load_nandsim.sh "$size" "$peb_size" "$page_size" || echo "cannot load nandsim";
+               mtdnum="$(find_mtd_device "$nandsim_patt")"
+       elif [ "$simulator" = "mtdram" ]; then
+               load_mtdram "$size" "$peb_size" || echo "cannot load mtdram"
+               mtdnum="$(find_mtd_device "$mtdram_patt")"
+       else
+               fatal "$simulator is not supported"
+       fi
+
+       flash_eraseall /dev/mtd$mtdnum
+       modprobe ubi mtd="$mtdnum,$page_size" || fatal "modprobe ubi fail"
+       ubimkvol -N vol_test -m -n 0 /dev/ubi$UBI_NUM || fatal "mkvol fail"
+       modprobe ubifs || fatal "modprobe ubifs fail"
+       mount_ubifs $DEV $MNT || fatal "mount ubifs fail"
+       if [[ "$encryption" == "encrypted" ]]; then
+               encryption_gen_key
+               encryption_set_key $MNT
+       fi
+
+       fsstress -d $MNT -l0 -p4 -n10000 &
+
+       sleep $((RANDOM % 20))
+
+       ps -e | grep -w fsstress > /dev/null 2>&1
+       while [ $? -eq 0 ]
+       do
+               killall -9 fsstress > /dev/null 2>&1
+               sleep 1
+               ps -e | grep -w fsstress > /dev/null 2>&1
+       done
+
+       while true
+       do
+               res=`mount | grep "$MNT"`
+               if [[ "$res" == "" ]]
+               then
+                       break;
+               fi
+               umount $MNT
+               sleep 0.1
+       done
+
+       # inject corruption
+       times=$((RANDOM % 10))
+       let times=$times+10
+       i=0
+       tot_peb=`cat /sys/class/ubi/ubi$UBI_NUM/total_eraseblocks`;
+
+       modprobe -r ubifs
+       modprobe -r ubi # Stop wear-leveling & erasing worker
+       while [[ $i -lt $times ]]
+       do
+               let i=$i+1;
+               peb=$((RANDOM % $tot_peb));
+               pg=`expr $peb_size \* 1024`;
+               peb_off=`expr $pg \* $peb`
+               pages=`expr $pg / $page_size`;
+               pg=`expr $pages - 2`;
+               pg=$((RANDOM % $pg));
+               pg_off=`expr $pg + 2`;
+               pg_start=`expr $pages \* $peb`;
+               pg=`expr $pg_start + $pg_off`;
+               vid_pg=`expr $pg_start + 1`;
+               dd if=/dev/mtd$mtdnum of=$TMP_FILE bs=$page_size skip=$vid_pg count=1 2>/dev/null;
+               content=`cat $TMP_FILE | grep UBI!`; # vid header magic
+               if [[ "$content" == "" ]]; then
+                       # Skip free PEB, otherwise LEB data could be overwritten in UBIFS
+                       continue;
+               fi
+               if [[ $((RANDOM % 2)) == 0 ]]; then
+                       # Corrupts 1 page
+                       dd if=/dev/urandom of=/dev/mtd$mtdnum bs=$page_size seek=$pg count=1;
+               else
+                       # Erase 1 LEB, TNC points to an unmapped area
+                       flash_erase /dev/mtd$mtdnum $peb_off 1
+               fi
+       done
+       rm -f $TMP_FILE 2>/dev/null
+       sync
+
+       skip=0
+       modprobe ubi mtd="$mtdnum,$page_size"
+       ret=$?
+       if [[ $ret != 0 ]]
+       then
+               skip=1
+               echo "UBI layout volume is corrupted, skip"
+       fi
+
+       if [[ $skip == 0 ]]; then
+               modprobe ubifs || fatal "modprobe ubifs2 fail"
+               dmesg -c > /dev/null
+
+               round=0
+               while [[ $round -lt 50 ]];
+               do
+                       let round=$round+1
+                       inject_mem=0
+
+                       fsck.ubifs -yb $DEV 2>&1 > $LOG_FILE &
+                       pid=$!
+                       if [[ $((RANDOM % 2)) == 0 ]]; then
+                               inject_mem_err $pid
+                               inject_mem=1
+                       fi
+                       inject_io_err
+                       wait $pid
+                       cat $LOG_FILE
+                       if [[ $inject_mem == 1 ]]; then
+                               cancel_mem_err
+                       fi
+                       cancel_io_err
+
+                       # UBI could become ro-mode, reload it
+                       modprobe -r ubifs
+                       modprobe -r ubi
+                       modprobe ubi mtd="$mtdnum,$page_size" || fatal "modprobe ubi2 fail"
+                       modprobe ubifs || fatal "modprobe ubifs3 fail"
+               done
+
+               fsck.ubifs -yb $DEV 2>&1 > $LOG_FILE
+               res=$?
+               cat $LOG_FILE
+               let "ret=$res&~$FSCK_NONDESTRUCT"
+               if [[ $ret != $FSCK_OK ]]
+               then
+                       # Skip superblock error
+                       log=`cat $LOG_FILE | grep "bad node at LEB 0:"`
+                       if [[ "$log" != "" ]]
+                       then
+                               skip=1
+                               echo "SB is corrupted, skip fsck & mounting"
+                       else
+                               fatal "fsck fail $res"
+                       fi
+               fi
+
+               if [[ $skip == 0 ]]; then
+                       enable_chkfs
+
+                       mount_ubifs $DEV $MNT "noauthentication" "noatime"
+                       res=$?
+                       if [[ $res != 0 ]]
+                       then
+                               fatal "mount fail $res"
+                       fi
+
+                       if [[ "$encryption" == "encrypted" ]]; then
+                               # Ignore the encrypting error, root dir could be
+                               # corrupted, the new root dir cannot be
+                               # encrypted because it is not empty.
+                               encryption_set_key $MNT 1
+                       fi
+
+                       du -sh $MNT > /dev/null  # Make sure all files are accessible
+                       ret=$?
+                       if [[ $ret != 0 ]]; then
+                               fatal "Cannot access all files"
+                       fi
+                       # check_err_msg is not suggested in this testcase, because
+                       # ubi_io_read(triggered by wear_leveling_worker -> ubi_eba_copy_leb)
+                       # could print stack if ecc uncorrectable errors are detected.
+
+                       umount $MNT
+                       res=$?
+                       if [[ $res != 0 ]]
+                       then
+                               fatal "unmount fail $res"
+                       fi
+               fi
+
+               modprobe -r ubifs
+               modprobe -r ubi
+       fi
+       modprobe -r $simulator
+
+       echo "----------------------------------------------------------------------"
+}
+
+check_fsstress
+start_t=$(date +%s)
+echo "Do corrruption+cycle_fsck_fault_injection test in kinds of flashes"
+for simulator in "mtdram" "nandsim"; do
+       for encryption in "encrypted" "noencrypted"; do
+               run_test "$simulator" "16" "16" "512" $encryption
+               run_test "$simulator" "256" "128" "2048" $encryption
+               run_test "$simulator" "1024" "512" "2048" $encryption
+       done
+done
+end_t=$(date +%s)
+time_cost=$(( end_t - start_t ))
+echo "Success, cost $time_cost seconds"
+exit 0
index 5a07ebcdb92070ed13dc35f3de0b8d20c3113ed1..a27fe108d2fd54d68b9e5a1ee2ee9ef938276ebf 100755 (executable)
@@ -234,12 +234,13 @@ function encryption_gen_key()
 function encryption_set_key()
 {
        mnt=$1
+       ignore_err=$2
        # https://github.com/google/fscryptctl
        key=$(fscryptctl add_key $mnt < $KEY_FILE)
        fscryptctl set_policy $key $mnt
        #fscryptctl get_policy $mnt
        ret=$?
-       if [[ $ret != 0 ]]; then
+       if [[ $ret != 0 && $ignore_err != 1 ]]; then
                fatal "set encryption policy failed"
        fi
 }