From 58a1bf3c0c523276da006a5a946ecb4343139ef4 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Fri, 30 Dec 2022 14:19:45 -0800 Subject: [PATCH] fuzzy: test fuzzing realtime free space metadata Fuzz the contents of the realtime bitmap and summary files to see what happens. Signed-off-by: Darrick J. Wong Reviewed-by: Zorro Lang Signed-off-by: Zorro Lang --- common/fuzzy | 107 ++++++++++++++++++++++++++++++++++++++++++++-- tests/xfs/739 | 41 ++++++++++++++++++ tests/xfs/739.out | 4 ++ tests/xfs/740 | 41 ++++++++++++++++++ tests/xfs/740.out | 4 ++ tests/xfs/741 | 41 ++++++++++++++++++ tests/xfs/741.out | 4 ++ tests/xfs/742 | 41 ++++++++++++++++++ tests/xfs/742.out | 4 ++ tests/xfs/743 | 42 ++++++++++++++++++ tests/xfs/743.out | 4 ++ tests/xfs/744 | 42 ++++++++++++++++++ tests/xfs/744.out | 4 ++ tests/xfs/745 | 41 ++++++++++++++++++ tests/xfs/745.out | 4 ++ tests/xfs/746 | 41 ++++++++++++++++++ tests/xfs/746.out | 4 ++ 17 files changed, 465 insertions(+), 4 deletions(-) create mode 100755 tests/xfs/739 create mode 100644 tests/xfs/739.out create mode 100755 tests/xfs/740 create mode 100644 tests/xfs/740.out create mode 100755 tests/xfs/741 create mode 100644 tests/xfs/741.out create mode 100755 tests/xfs/742 create mode 100644 tests/xfs/742.out create mode 100755 tests/xfs/743 create mode 100644 tests/xfs/743.out create mode 100755 tests/xfs/744 create mode 100644 tests/xfs/744.out create mode 100755 tests/xfs/745 create mode 100644 tests/xfs/745.out create mode 100755 tests/xfs/746 create mode 100644 tests/xfs/746.out diff --git a/common/fuzzy b/common/fuzzy index 224139d8..470bec47 100644 --- a/common/fuzzy +++ b/common/fuzzy @@ -154,6 +154,12 @@ _scratch_xfs_dump_metadata() { _scratch_xfs_db "${cmds[@]}" -c print } +# Decide from the output of the xfs_db "stack" command if the debugger's io +# cursor is pointed at a block that is an unstructured data format (blob). +__scratch_xfs_detect_blob_from_stack() { + grep -q -E 'inode.*, type (data|rtsummary|rtbitmap)' +} + # Navigate to some part of the filesystem and print the field info. # The first argument is an grep filter for the fields # The rest of the arguments are xfs_db commands to locate the metadata. @@ -169,7 +175,17 @@ _scratch_xfs_list_metadata_fields() { for arg in "$@"; do cmds+=("-c" "${arg}") done - _scratch_xfs_db "${cmds[@]}" -c print | __filter_xfs_db_print_fields "${filter}" + + # Does the path argument point towards something that is an + # unstructured blob? + if _scratch_xfs_db "${cmds[@]}" -c stack 2>/dev/null | \ + __scratch_xfs_detect_blob_from_stack; then + echo "" + return + fi + + _scratch_xfs_db "${cmds[@]}" -c print | \ + __filter_xfs_db_print_fields "${filter}" } # Fuzz a metadata field @@ -207,6 +223,70 @@ _scratch_xfs_fuzz_metadata_field() { return 0 } +# List the fuzzing verbs available for unstructured blobs +__scratch_xfs_list_blob_fuzz_verbs() { + cat << ENDL +zeroes +ones +firstbit +middlebit +lastbit +random +ENDL +} + +# Fuzz a metadata blob +# The first arg is a blob fuzzing verb +# The rest of the arguments are xfs_db commands to find the metadata. +_scratch_xfs_fuzz_metadata_blob() { + local fuzzverb="$1" + shift + local trashcmd=(blocktrash -z) + + local cmds=() + for arg in "$@"; do + cmds+=("-c" "${arg}") + done + + local bytecount=$(_scratch_xfs_db "${cmds[@]}" -c "stack" | grep 'byte.*length' | awk '{print $5}') + local bitmax=$((bytecount * 8)) + + case "${fuzzverb}" in + "zeroes") + trashcmd+=(-0 -o 0 -x "${bitmax}" -y "${bitmax}");; + "ones") + trashcmd+=(-1 -o 0 -x "${bitmax}" -y "${bitmax}");; + "firstbit") + trashcmd+=(-2 -o 0 -x 1 -y 1);; + "middlebit") + trashcmd+=(-2 -o $((bitmax / 2)) -x 1 -y 1);; + "lastbit") + trashcmd+=(-2 -o "${bitmax}" -x 1 -y 1);; + "random") + trashcmd+=(-3 -o 0 -x "${bitmax}" -y "${bitmax}");; + *) + echo "Unknown blob fuzz verb \"${fuzzverb}\"." + return 1 + ;; + esac + + trashcmd="${trashcmd[@]}" + oldval="$(_scratch_xfs_get_metadata_field "" "$@")" + while true; do + _scratch_xfs_db -x "${cmds[@]}" -c "${trashcmd}" + echo + newval="$(_scratch_xfs_get_metadata_field "" "$@" 2> /dev/null)" + if [ "${fuzzverb}" != "random" ] || [ "${oldval}" != "${newval}" ]; then + break; + fi + done + if [ "${oldval}" = "${newval}" ]; then + echo "Blob already set to new value, skipping test." + return 1 + fi + return 0 +} + # Try to forcibly unmount the scratch fs __scratch_xfs_fuzz_unmount() { @@ -503,7 +583,11 @@ __scratch_xfs_fuzz_field_test() { # Set the new field value __fuzz_notify "+ Fuzz ${field} = ${fuzzverb}" - _scratch_xfs_fuzz_metadata_field "${field}" ${fuzzverb} "$@" + if [ "$field" = "" ]; then + _scratch_xfs_fuzz_metadata_blob ${fuzzverb} "$@" + else + _scratch_xfs_fuzz_metadata_field "${field}" ${fuzzverb} "$@" + fi res=$? test $res -ne 0 && return @@ -587,7 +671,22 @@ _scratch_xfs_list_fuzz_verbs() { echo "${SCRATCH_XFS_LIST_FUZZ_VERBS}" | tr '[ ,]' '[\n\n]' return; fi - _scratch_xfs_db -x -c 'sb 0' -c 'fuzz' | grep '^Fuzz commands:' | \ + + local cmds=() + for arg in "$@"; do + cmds+=("-c" "${arg}") + done + test "${#cmds[@]}" -eq 0 && cmds=('-c' 'sb 0') + + # Does the path argument point towards something that is an + # unstructured blob? + if _scratch_xfs_db "${cmds[@]}" -c stack 2>/dev/null | \ + __scratch_xfs_detect_blob_from_stack; then + __scratch_xfs_list_blob_fuzz_verbs + return + fi + + _scratch_xfs_db -x "${cmds[@]}" -c 'fuzz' | grep '^Fuzz commands:' | \ sed -e 's/[,.]//g' -e 's/Fuzz commands: //g' -e 's/ /\n/g' | \ grep -v '^random$' } @@ -605,7 +704,7 @@ _scratch_xfs_fuzz_metadata() { shift; shift fields="$(_scratch_xfs_list_metadata_fields "${filter}" "$@")" - verbs="$(_scratch_xfs_list_fuzz_verbs)" + verbs="$(_scratch_xfs_list_fuzz_verbs "$@")" echo "Fields we propose to fuzz with the \"${repair}\" repair strategy: $@" echo $(echo "${fields}") echo "Verbs we propose to fuzz with:" diff --git a/tests/xfs/739 b/tests/xfs/739 new file mode 100755 index 00000000..fb7fe2e6 --- /dev/null +++ b/tests/xfs/739 @@ -0,0 +1,41 @@ +#! /bin/bash +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Oracle. All Rights Reserved. +# +# FS QA Test No. 739 +# +# Populate a XFS filesystem and fuzz every realtime bitmap field. +# Use xfs_scrub to fix the corruption. + +. ./common/preamble +_begin_fstest dangerous_fuzzers dangerous_scrub dangerous_online_repair realtime + +_register_cleanup "_cleanup" BUS + +# Import common functions. +. ./common/filter +. ./common/populate +. ./common/fuzzy + +# real QA test starts here +_supported_fs xfs +_require_realtime +_require_scratch_xfs_fuzz_fields +_disable_dmesg_check + +echo "Format and populate" +_scratch_populate_cached nofill > $seqres.full 2>&1 + +echo "Fuzz rtbitmap" +is_metadir=$(_scratch_xfs_get_metadata_field "core.version" 'path -m /realtime/0.bitmap') +if [ -n "$is_metadir" ]; then + path=('path -m /realtime/0.bitmap') +else + path=('sb' 'addr rbmino') +fi +_scratch_xfs_fuzz_metadata '' 'online' "${path[@]}" 'dblock 0' >> $seqres.full +echo "Done fuzzing rtbitmap" + +# success, all done +status=0 +exit diff --git a/tests/xfs/739.out b/tests/xfs/739.out new file mode 100644 index 00000000..7f0c6049 --- /dev/null +++ b/tests/xfs/739.out @@ -0,0 +1,4 @@ +QA output created by 739 +Format and populate +Fuzz rtbitmap +Done fuzzing rtbitmap diff --git a/tests/xfs/740 b/tests/xfs/740 new file mode 100755 index 00000000..a59fa37e --- /dev/null +++ b/tests/xfs/740 @@ -0,0 +1,41 @@ +#! /bin/bash +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Oracle. All Rights Reserved. +# +# FS QA Test No. 740 +# +# Populate a XFS filesystem and fuzz every realtime summary field. +# Use xfs_scrub to fix the corruption. + +. ./common/preamble +_begin_fstest dangerous_fuzzers dangerous_scrub dangerous_online_repair realtime + +_register_cleanup "_cleanup" BUS + +# Import common functions. +. ./common/filter +. ./common/populate +. ./common/fuzzy + +# real QA test starts here +_supported_fs xfs +_require_realtime +_require_scratch_xfs_fuzz_fields +_disable_dmesg_check + +echo "Format and populate" +_scratch_populate_cached nofill > $seqres.full 2>&1 + +echo "Fuzz rtsummary" +is_metadir=$(_scratch_xfs_get_metadata_field "core.version" 'path -m /realtime/0.summary') +if [ -n "$is_metadir" ]; then + path=('path -m /realtime/0.summary') +else + path=('sb' 'addr rsumino') +fi +_scratch_xfs_fuzz_metadata '' 'online' "${path[@]}" 'dblock 0' >> $seqres.full +echo "Done fuzzing rtsummary" + +# success, all done +status=0 +exit diff --git a/tests/xfs/740.out b/tests/xfs/740.out new file mode 100644 index 00000000..bb866529 --- /dev/null +++ b/tests/xfs/740.out @@ -0,0 +1,4 @@ +QA output created by 740 +Format and populate +Fuzz rtsummary +Done fuzzing rtsummary diff --git a/tests/xfs/741 b/tests/xfs/741 new file mode 100755 index 00000000..957bed79 --- /dev/null +++ b/tests/xfs/741 @@ -0,0 +1,41 @@ +#! /bin/bash +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Oracle. All Rights Reserved. +# +# FS QA Test No. 741 +# +# Populate a XFS filesystem and fuzz every realtime bitmap field. +# Use xfs_repair to fix the corruption. + +. ./common/preamble +_begin_fstest dangerous_fuzzers dangerous_scrub dangerous_repair realtime + +_register_cleanup "_cleanup" BUS + +# Import common functions. +. ./common/filter +. ./common/populate +. ./common/fuzzy + +# real QA test starts here +_supported_fs xfs +_require_realtime +_require_scratch_xfs_fuzz_fields +_disable_dmesg_check + +echo "Format and populate" +_scratch_populate_cached nofill > $seqres.full 2>&1 + +echo "Fuzz rtbitmap" +is_metadir=$(_scratch_xfs_get_metadata_field "core.version" 'path -m /realtime/0.bitmap') +if [ -n "$is_metadir" ]; then + path=('path -m /realtime/0.bitmap') +else + path=('sb' 'addr rbmino') +fi +_scratch_xfs_fuzz_metadata '' 'offline' "${path[@]}" 'dblock 0' >> $seqres.full +echo "Done fuzzing rtbitmap" + +# success, all done +status=0 +exit diff --git a/tests/xfs/741.out b/tests/xfs/741.out new file mode 100644 index 00000000..db7a071e --- /dev/null +++ b/tests/xfs/741.out @@ -0,0 +1,4 @@ +QA output created by 741 +Format and populate +Fuzz rtbitmap +Done fuzzing rtbitmap diff --git a/tests/xfs/742 b/tests/xfs/742 new file mode 100755 index 00000000..d9117484 --- /dev/null +++ b/tests/xfs/742 @@ -0,0 +1,41 @@ +#! /bin/bash +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Oracle. All Rights Reserved. +# +# FS QA Test No. 742 +# +# Populate a XFS filesystem and fuzz every realtime summary field. +# Use xfs_repair to fix the corruption. + +. ./common/preamble +_begin_fstest dangerous_fuzzers dangerous_scrub dangerous_repair realtime + +_register_cleanup "_cleanup" BUS + +# Import common functions. +. ./common/filter +. ./common/populate +. ./common/fuzzy + +# real QA test starts here +_supported_fs xfs +_require_realtime +_require_scratch_xfs_fuzz_fields +_disable_dmesg_check + +echo "Format and populate" +_scratch_populate_cached nofill > $seqres.full 2>&1 + +echo "Fuzz rtsummary" +is_metadir=$(_scratch_xfs_get_metadata_field "core.version" 'path -m /realtime/0.summary') +if [ -n "$is_metadir" ]; then + path=('path -m /realtime/0.summary') +else + path=('sb' 'addr rsumino') +fi +_scratch_xfs_fuzz_metadata '' 'offline' "${path[@]}" 'dblock 0' >> $seqres.full +echo "Done fuzzing rtsummary" + +# success, all done +status=0 +exit diff --git a/tests/xfs/742.out b/tests/xfs/742.out new file mode 100644 index 00000000..dd209a89 --- /dev/null +++ b/tests/xfs/742.out @@ -0,0 +1,4 @@ +QA output created by 742 +Format and populate +Fuzz rtsummary +Done fuzzing rtsummary diff --git a/tests/xfs/743 b/tests/xfs/743 new file mode 100755 index 00000000..69e865a4 --- /dev/null +++ b/tests/xfs/743 @@ -0,0 +1,42 @@ +#! /bin/bash +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Oracle. All Rights Reserved. +# +# FS QA Test No. 743 +# +# Populate a XFS filesystem and fuzz every realtime bitmap field. +# Try online repair and, if necessary, offline repair, +# to test the most likely usage pattern. + +. ./common/preamble +_begin_fstest dangerous_fuzzers dangerous_scrub dangerous_bothrepair realtime + +_register_cleanup "_cleanup" BUS + +# Import common functions. +. ./common/filter +. ./common/populate +. ./common/fuzzy + +# real QA test starts here +_supported_fs xfs +_require_realtime +_require_scratch_xfs_fuzz_fields +_disable_dmesg_check + +echo "Format and populate" +_scratch_populate_cached nofill > $seqres.full 2>&1 + +echo "Fuzz rtbitmap" +is_metadir=$(_scratch_xfs_get_metadata_field "core.version" 'path -m /realtime/0.bitmap') +if [ -n "$is_metadir" ]; then + path=('path -m /realtime/0.bitmap') +else + path=('sb' 'addr rbmino') +fi +_scratch_xfs_fuzz_metadata '' 'both' "${path[@]}" 'dblock 0' >> $seqres.full +echo "Done fuzzing rtbitmap" + +# success, all done +status=0 +exit diff --git a/tests/xfs/743.out b/tests/xfs/743.out new file mode 100644 index 00000000..d4ef1fd3 --- /dev/null +++ b/tests/xfs/743.out @@ -0,0 +1,4 @@ +QA output created by 743 +Format and populate +Fuzz rtbitmap +Done fuzzing rtbitmap diff --git a/tests/xfs/744 b/tests/xfs/744 new file mode 100755 index 00000000..ea490b52 --- /dev/null +++ b/tests/xfs/744 @@ -0,0 +1,42 @@ +#! /bin/bash +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Oracle. All Rights Reserved. +# +# FS QA Test No. 744 +# +# Populate a XFS filesystem and fuzz every realtime summary field. +# Try online repair and, if necessary, offline repair, +# to test the most likely usage pattern. + +. ./common/preamble +_begin_fstest dangerous_fuzzers dangerous_scrub dangerous_bothrepair realtime + +_register_cleanup "_cleanup" BUS + +# Import common functions. +. ./common/filter +. ./common/populate +. ./common/fuzzy + +# real QA test starts here +_supported_fs xfs +_require_realtime +_require_scratch_xfs_fuzz_fields +_disable_dmesg_check + +echo "Format and populate" +_scratch_populate_cached nofill > $seqres.full 2>&1 + +echo "Fuzz rtsummary" +is_metadir=$(_scratch_xfs_get_metadata_field "core.version" 'path -m /realtime/0.summary') +if [ -n "$is_metadir" ]; then + path=('path -m /realtime/0.summary') +else + path=('sb' 'addr rsumino') +fi +_scratch_xfs_fuzz_metadata '' 'both' "${path[@]}" 'dblock 0' >> $seqres.full +echo "Done fuzzing rtsummary" + +# success, all done +status=0 +exit diff --git a/tests/xfs/744.out b/tests/xfs/744.out new file mode 100644 index 00000000..99e0d489 --- /dev/null +++ b/tests/xfs/744.out @@ -0,0 +1,4 @@ +QA output created by 744 +Format and populate +Fuzz rtsummary +Done fuzzing rtsummary diff --git a/tests/xfs/745 b/tests/xfs/745 new file mode 100755 index 00000000..7621d457 --- /dev/null +++ b/tests/xfs/745 @@ -0,0 +1,41 @@ +#! /bin/bash +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Oracle. All Rights Reserved. +# +# FS QA Test No. 745 +# +# Populate a XFS filesystem and fuzz every realtime bitmap field. +# Do not fix the filesystem, to test metadata verifiers. + +. ./common/preamble +_begin_fstest dangerous_fuzzers dangerous_scrub dangerous_norepair realtime + +_register_cleanup "_cleanup" BUS + +# Import common functions. +. ./common/filter +. ./common/populate +. ./common/fuzzy + +# real QA test starts here +_supported_fs xfs +_require_realtime +_require_scratch_xfs_fuzz_fields +_disable_dmesg_check + +echo "Format and populate" +_scratch_populate_cached nofill > $seqres.full 2>&1 + +echo "Fuzz rtbitmap" +is_metadir=$(_scratch_xfs_get_metadata_field "core.version" 'path -m /realtime/0.bitmap') +if [ -n "$is_metadir" ]; then + path=('path -m /realtime/0.bitmap') +else + path=('sb' 'addr rbmino') +fi +_scratch_xfs_fuzz_metadata '' 'none' "${path[@]}" 'dblock 0' >> $seqres.full +echo "Done fuzzing rtbitmap" + +# success, all done +status=0 +exit diff --git a/tests/xfs/745.out b/tests/xfs/745.out new file mode 100644 index 00000000..0b8f2079 --- /dev/null +++ b/tests/xfs/745.out @@ -0,0 +1,4 @@ +QA output created by 745 +Format and populate +Fuzz rtbitmap +Done fuzzing rtbitmap diff --git a/tests/xfs/746 b/tests/xfs/746 new file mode 100755 index 00000000..40123316 --- /dev/null +++ b/tests/xfs/746 @@ -0,0 +1,41 @@ +#! /bin/bash +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Oracle. All Rights Reserved. +# +# FS QA Test No. 746 +# +# Populate a XFS filesystem and fuzz every realtime summary field. +# Do not fix the filesystem, to test metadata verifiers. + +. ./common/preamble +_begin_fstest dangerous_fuzzers dangerous_scrub dangerous_norepair realtime + +_register_cleanup "_cleanup" BUS + +# Import common functions. +. ./common/filter +. ./common/populate +. ./common/fuzzy + +# real QA test starts here +_supported_fs xfs +_require_realtime +_require_scratch_xfs_fuzz_fields +_disable_dmesg_check + +echo "Format and populate" +_scratch_populate_cached nofill > $seqres.full 2>&1 + +echo "Fuzz rtsummary" +is_metadir=$(_scratch_xfs_get_metadata_field "core.version" 'path -m /realtime/0.summary') +if [ -n "$is_metadir" ]; then + path=('path -m /realtime/0.summary') +else + path=('sb' 'addr rsumino') +fi +_scratch_xfs_fuzz_metadata '' 'none' "${path[@]}" 'dblock 0' >> $seqres.full +echo "Done fuzzing rtsummary" + +# success, all done +status=0 +exit diff --git a/tests/xfs/746.out b/tests/xfs/746.out new file mode 100644 index 00000000..375c7a0e --- /dev/null +++ b/tests/xfs/746.out @@ -0,0 +1,4 @@ +QA output created by 746 +Format and populate +Fuzz rtsummary +Done fuzzing rtsummary -- 2.39.5