selftests: splice: Adjust for handler fallback removal
authorKees Cook <keescook@chromium.org>
Thu, 27 May 2021 03:25:37 +0000 (20:25 -0700)
committerShuah Khan <skhan@linuxfoundation.org>
Tue, 8 Jun 2021 00:39:43 +0000 (18:39 -0600)
Some pseudo-filesystems do not have an explicit splice fops since adding
commit 36e2c7421f02 ("fs: don't allow splice read/write without explicit ops"),
and now will reject attempts to use splice() in those filesystem paths.

Reported-by: kernel test robot <rong.a.chen@intel.com>
Link: https://lore.kernel.org/lkml/202009181443.C2179FB@keescook/
Fixes: 36e2c7421f02 ("fs: don't allow splice read/write without explicit ops")
Cc: Christoph Hellwig <hch@lst.de>
Cc: Shuah Khan <shuah@kernel.org>
Cc: linux-kselftest@vger.kernel.org
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
tools/testing/selftests/splice/short_splice_read.sh

index 7810d35..22b6c89 100755 (executable)
@@ -1,21 +1,87 @@
 #!/bin/sh
 # SPDX-License-Identifier: GPL-2.0
+#
+# Test for mishandling of splice() on pseudofilesystems, which should catch
+# bugs like 11990a5bd7e5 ("module: Correctly truncate sysfs sections output")
+#
+# Since splice fallback was removed as part of the set_fs() rework, many of these
+# tests expect to fail now. See https://lore.kernel.org/lkml/202009181443.C2179FB@keescook/
 set -e
 
+DIR=$(dirname "$0")
+
 ret=0
 
+expect_success()
+{
+       title="$1"
+       shift
+
+       echo "" >&2
+       echo "$title ..." >&2
+
+       set +e
+       "$@"
+       rc=$?
+       set -e
+
+       case "$rc" in
+       0)
+               echo "ok: $title succeeded" >&2
+               ;;
+       1)
+               echo "FAIL: $title should work" >&2
+               ret=$(( ret + 1 ))
+               ;;
+       *)
+               echo "FAIL: something else went wrong" >&2
+               ret=$(( ret + 1 ))
+               ;;
+       esac
+}
+
+expect_failure()
+{
+       title="$1"
+       shift
+
+       echo "" >&2
+       echo "$title ..." >&2
+
+       set +e
+       "$@"
+       rc=$?
+       set -e
+
+       case "$rc" in
+       0)
+               echo "FAIL: $title unexpectedly worked" >&2
+               ret=$(( ret + 1 ))
+               ;;
+       1)
+               echo "ok: $title correctly failed" >&2
+               ;;
+       *)
+               echo "FAIL: something else went wrong" >&2
+               ret=$(( ret + 1 ))
+               ;;
+       esac
+}
+
 do_splice()
 {
        filename="$1"
        bytes="$2"
        expected="$3"
+       report="$4"
 
-       out=$(./splice_read "$filename" "$bytes" | cat)
+       out=$("$DIR"/splice_read "$filename" "$bytes" | cat)
        if [ "$out" = "$expected" ] ; then
-               echo "ok: $filename $bytes"
+               echo "      matched $report" >&2
+               return 0
        else
-               echo "FAIL: $filename $bytes"
-               ret=1
+               echo "      no match: '$out' vs $report" >&2
+               return 1
        fi
 }
 
@@ -23,34 +89,45 @@ test_splice()
 {
        filename="$1"
 
+       echo "  checking $filename ..." >&2
+
        full=$(cat "$filename")
+       rc=$?
+       if [ $rc -ne 0 ] ; then
+               return 2
+       fi
+
        two=$(echo "$full" | grep -m1 . | cut -c-2)
 
        # Make sure full splice has the same contents as a standard read.
-       do_splice "$filename" 4096 "$full"
+       echo "    splicing 4096 bytes ..." >&2
+       if ! do_splice "$filename" 4096 "$full" "full read" ; then
+               return 1
+       fi
 
        # Make sure a partial splice see the first two characters.
-       do_splice "$filename" 2 "$two"
+       echo "    splicing 2 bytes ..." >&2
+       if ! do_splice "$filename" 2 "$two" "'$two'" ; then
+               return 1
+       fi
+
+       return 0
 }
 
-# proc_single_open(), seq_read()
-test_splice /proc/$$/limits
-# special open, seq_read()
-test_splice /proc/$$/comm
+### /proc/$pid/ has no splice interface; these should all fail.
+expect_failure "proc_single_open(), seq_read() splice" test_splice /proc/$$/limits
+expect_failure "special open(), seq_read() splice" test_splice /proc/$$/comm
 
-# proc_handler, proc_dointvec_minmax
-test_splice /proc/sys/fs/nr_open
-# proc_handler, proc_dostring
-test_splice /proc/sys/kernel/modprobe
-# proc_handler, special read
-test_splice /proc/sys/kernel/version
+### /proc/sys/ has a splice interface; these should all succeed.
+expect_success "proc_handler: proc_dointvec_minmax() splice" test_splice /proc/sys/fs/nr_open
+expect_success "proc_handler: proc_dostring() splice" test_splice /proc/sys/kernel/modprobe
+expect_success "proc_handler: special read splice" test_splice /proc/sys/kernel/version
 
+### /sys/ has no splice interface; these should all fail.
 if ! [ -d /sys/module/test_module/sections ] ; then
-       modprobe test_module
+       expect_success "test_module kernel module load" modprobe test_module
 fi
-# kernfs, attr
-test_splice /sys/module/test_module/coresize
-# kernfs, binattr
-test_splice /sys/module/test_module/sections/.init.text
+expect_failure "kernfs attr splice" test_splice /sys/module/test_module/coresize
+expect_failure "kernfs binattr splice" test_splice /sys/module/test_module/sections/.init.text
 
 exit $ret