In order to help catch regressions in splice vs read behavior in certain
special files, test a few with various different kinds of internal
kernel helpers.

Cc: Shuah Khan <sh...@kernel.org>
Signed-off-by: Kees Cook <keesc...@chromium.org>
---
 tools/testing/selftests/splice/.gitignore     |  1 +
 tools/testing/selftests/splice/Makefile       |  4 +-
 tools/testing/selftests/splice/config         |  1 +
 tools/testing/selftests/splice/settings       |  1 +
 .../selftests/splice/short_splice_read.sh     | 56 ++++++++++++++++++
 tools/testing/selftests/splice/splice_read.c  | 57 +++++++++++++++++++
 6 files changed, 118 insertions(+), 2 deletions(-)
 create mode 100644 tools/testing/selftests/splice/config
 create mode 100644 tools/testing/selftests/splice/settings
 create mode 100755 tools/testing/selftests/splice/short_splice_read.sh
 create mode 100644 tools/testing/selftests/splice/splice_read.c

diff --git a/tools/testing/selftests/splice/.gitignore 
b/tools/testing/selftests/splice/.gitignore
index d5a2da428752..be8266f5d04c 100644
--- a/tools/testing/selftests/splice/.gitignore
+++ b/tools/testing/selftests/splice/.gitignore
@@ -1,2 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0-only
 default_file_splice_read
+splice_read
diff --git a/tools/testing/selftests/splice/Makefile 
b/tools/testing/selftests/splice/Makefile
index e519b159b60d..541cd826d5a5 100644
--- a/tools/testing/selftests/splice/Makefile
+++ b/tools/testing/selftests/splice/Makefile
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
-TEST_PROGS := default_file_splice_read.sh
-TEST_GEN_PROGS_EXTENDED := default_file_splice_read
+TEST_PROGS := default_file_splice_read.sh short_splice_read.sh
+TEST_GEN_PROGS_EXTENDED := default_file_splice_read splice_read
 
 include ../lib.mk
diff --git a/tools/testing/selftests/splice/config 
b/tools/testing/selftests/splice/config
new file mode 100644
index 000000000000..058c928368b8
--- /dev/null
+++ b/tools/testing/selftests/splice/config
@@ -0,0 +1 @@
+CONFIG_TEST_LKM=m
diff --git a/tools/testing/selftests/splice/settings 
b/tools/testing/selftests/splice/settings
new file mode 100644
index 000000000000..89cedfc0d12b
--- /dev/null
+++ b/tools/testing/selftests/splice/settings
@@ -0,0 +1 @@
+timeout=5
diff --git a/tools/testing/selftests/splice/short_splice_read.sh 
b/tools/testing/selftests/splice/short_splice_read.sh
new file mode 100755
index 000000000000..7810d3589d9a
--- /dev/null
+++ b/tools/testing/selftests/splice/short_splice_read.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+set -e
+
+ret=0
+
+do_splice()
+{
+       filename="$1"
+       bytes="$2"
+       expected="$3"
+
+       out=$(./splice_read "$filename" "$bytes" | cat)
+       if [ "$out" = "$expected" ] ; then
+               echo "ok: $filename $bytes"
+       else
+               echo "FAIL: $filename $bytes"
+               ret=1
+       fi
+}
+
+test_splice()
+{
+       filename="$1"
+
+       full=$(cat "$filename")
+       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"
+
+       # Make sure a partial splice see the first two characters.
+       do_splice "$filename" 2 "$two"
+}
+
+# proc_single_open(), seq_read()
+test_splice /proc/$$/limits
+# special open, seq_read()
+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
+
+if ! [ -d /sys/module/test_module/sections ] ; then
+       modprobe test_module
+fi
+# kernfs, attr
+test_splice /sys/module/test_module/coresize
+# kernfs, binattr
+test_splice /sys/module/test_module/sections/.init.text
+
+exit $ret
diff --git a/tools/testing/selftests/splice/splice_read.c 
b/tools/testing/selftests/splice/splice_read.c
new file mode 100644
index 000000000000..46dae6a25cfb
--- /dev/null
+++ b/tools/testing/selftests/splice/splice_read.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0
+#define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+int main(int argc, char *argv[])
+{
+       int fd;
+       size_t size;
+       ssize_t spliced;
+
+       if (argc < 2) {
+               fprintf(stderr, "Usage: %s INPUT [BYTES]\n", argv[0]);
+               return EXIT_FAILURE;
+       }
+
+       fd = open(argv[1], O_RDONLY);
+       if (fd < 0) {
+               perror(argv[1]);
+               return EXIT_FAILURE;
+       }
+
+       if (argc == 3)
+               size = atol(argv[2]);
+       else {
+               struct stat statbuf;
+
+               if (fstat(fd, &statbuf) < 0) {
+                       perror(argv[1]);
+                       return EXIT_FAILURE;
+               }
+
+               if (statbuf.st_size > INT_MAX) {
+                       fprintf(stderr, "%s: Too big\n", argv[1]);
+                       return EXIT_FAILURE;
+               }
+
+               size = statbuf.st_size;
+       }
+
+       /* splice(2) file to stdout. */
+       spliced = splice(fd, NULL, STDOUT_FILENO, NULL,
+                     size, SPLICE_F_MOVE);
+       if (spliced < 0) {
+               perror("splice");
+               return EXIT_FAILURE;
+       }
+
+       close(fd);
+       return EXIT_SUCCESS;
+}
-- 
2.25.1

Reply via email to