diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2020-06-10 10:01:56 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2020-06-10 10:01:56 +0200 |
commit | 6c6a0147ce8ee79ce8176b076f7e6eb512989982 (patch) | |
tree | 4125c4d173d982441b1f878f314848e02da18b4b | |
parent | 0ce7a6b8527fbbc84add286a0efc73803a77bcab (diff) | |
download | patches-6c6a0147ce8ee79ce8176b076f7e6eb512989982.tar.gz |
add readfile patches to keep "safe"
-rw-r--r-- | 0001-readfile-implement-readfile-syscall.patch | 81 | ||||
-rw-r--r-- | 0002-arch-wire-up-the-readfile-syscall.patch | 237 | ||||
-rw-r--r-- | 0003-selftests-add-readfile-2-selftests.patch | 578 | ||||
-rw-r--r-- | series | 3 |
4 files changed, 899 insertions, 0 deletions
diff --git a/0001-readfile-implement-readfile-syscall.patch b/0001-readfile-implement-readfile-syscall.patch new file mode 100644 index 00000000000000..1393312d340858 --- /dev/null +++ b/0001-readfile-implement-readfile-syscall.patch @@ -0,0 +1,81 @@ +From 64793c95677d62753de4db132b0c85adab7aa9ab Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Date: Sun, 24 May 2020 12:37:15 +0200 +Subject: [PATCH 1/3] readfile: implement readfile syscall + +It's a tiny syscall, meant to allow a user to do a single "open this +file, read into this buffer, and close the file" all in a single shot. + +Should be good for reading "tiny" files like sysfs, procfs, and other +"small" files. + +There is no restarting the syscall, this is a "simple" syscall, with the +attempt to make reading "simple" files easier with less syscall +overhead. + +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + fs/open.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 50 insertions(+) + +diff --git a/fs/open.c b/fs/open.c +index 6cd48a61cda3..9ec18cddee18 100644 +--- a/fs/open.c ++++ b/fs/open.c +@@ -1370,3 +1370,53 @@ int stream_open(struct inode *inode, struct file *filp) + } + + EXPORT_SYMBOL(stream_open); ++ ++static struct file *readfile_open(int dfd, const char __user *filename, ++ struct open_flags *op) ++{ ++ struct filename *tmp; ++ struct file *f; ++ ++ tmp = getname(filename); ++ if (IS_ERR(tmp)) ++ return (struct file *)tmp; ++ ++ f = do_filp_open(dfd, tmp, op); ++ if (!IS_ERR(f)) ++ fsnotify_open(f); ++ ++ putname(tmp); ++ return f; ++} ++ ++SYSCALL_DEFINE5(readfile, int, dfd, const char __user *, filename, ++ char __user *, buffer, size_t, bufsize, int, flags) ++{ ++ struct open_flags op; ++ struct open_how how; ++ struct file *file; ++ loff_t pos = 0; ++ int retval; ++ ++ /* only accept a small subset of O_ flags that make sense */ ++ if ((flags | O_NOFOLLOW | O_NOATIME) != flags) ++ return -EINVAL; ++ ++ /* add some needed flags to be able to open the file properly */ ++ flags |= O_RDONLY | O_LARGEFILE; ++ ++ how = build_open_how(flags, 0000); ++ retval = build_open_flags(&how, &op); ++ if (retval) ++ return retval; ++ ++ file = readfile_open(dfd, filename, &op); ++ if (IS_ERR(file)) ++ return PTR_ERR(file); ++ ++ retval = vfs_read(file, buffer, bufsize, &pos); ++ ++ filp_close(file, NULL); ++ ++ return retval; ++} +-- +2.27.0 + diff --git a/0002-arch-wire-up-the-readfile-syscall.patch b/0002-arch-wire-up-the-readfile-syscall.patch new file mode 100644 index 00000000000000..34e76f3e4c134a --- /dev/null +++ b/0002-arch-wire-up-the-readfile-syscall.patch @@ -0,0 +1,237 @@ +From ef5dc99f43ca5c982c124ff6ac7acf0c1151d5bf Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Date: Sun, 24 May 2020 12:36:21 +0200 +Subject: [PATCH 2/3] arch: wire up the readfile syscall + +This wires up the readfile syscall for all architectures + +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + arch/alpha/kernel/syscalls/syscall.tbl | 1 + + arch/arm/tools/syscall.tbl | 1 + + arch/arm64/include/asm/unistd.h | 2 +- + arch/arm64/include/asm/unistd32.h | 2 ++ + arch/ia64/kernel/syscalls/syscall.tbl | 1 + + arch/m68k/kernel/syscalls/syscall.tbl | 1 + + arch/microblaze/kernel/syscalls/syscall.tbl | 1 + + arch/mips/kernel/syscalls/syscall_n32.tbl | 1 + + arch/mips/kernel/syscalls/syscall_n64.tbl | 1 + + arch/mips/kernel/syscalls/syscall_o32.tbl | 1 + + arch/parisc/kernel/syscalls/syscall.tbl | 1 + + arch/powerpc/kernel/syscalls/syscall.tbl | 1 + + arch/s390/kernel/syscalls/syscall.tbl | 1 + + arch/sh/kernel/syscalls/syscall.tbl | 1 + + arch/sparc/kernel/syscalls/syscall.tbl | 1 + + arch/x86/entry/syscalls/syscall_32.tbl | 1 + + arch/x86/entry/syscalls/syscall_64.tbl | 1 + + arch/xtensa/kernel/syscalls/syscall.tbl | 1 + + include/linux/syscalls.h | 2 ++ + include/uapi/asm-generic/unistd.h | 4 +++- + 20 files changed, 24 insertions(+), 2 deletions(-) + +diff --git a/arch/alpha/kernel/syscalls/syscall.tbl b/arch/alpha/kernel/syscalls/syscall.tbl +index 5ddd128d4b7a..4132380e997f 100644 +--- a/arch/alpha/kernel/syscalls/syscall.tbl ++++ b/arch/alpha/kernel/syscalls/syscall.tbl +@@ -478,3 +478,4 @@ + 547 common openat2 sys_openat2 + 548 common pidfd_getfd sys_pidfd_getfd + 549 common faccessat2 sys_faccessat2 ++550 common readfile sys_readfile +diff --git a/arch/arm/tools/syscall.tbl b/arch/arm/tools/syscall.tbl +index d5cae5ffede0..454873892ba3 100644 +--- a/arch/arm/tools/syscall.tbl ++++ b/arch/arm/tools/syscall.tbl +@@ -452,3 +452,4 @@ + 437 common openat2 sys_openat2 + 438 common pidfd_getfd sys_pidfd_getfd + 439 common faccessat2 sys_faccessat2 ++440 common readfile sys_readfile +diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h +index 3b859596840d..b3b2019f8d16 100644 +--- a/arch/arm64/include/asm/unistd.h ++++ b/arch/arm64/include/asm/unistd.h +@@ -38,7 +38,7 @@ + #define __ARM_NR_compat_set_tls (__ARM_NR_COMPAT_BASE + 5) + #define __ARM_NR_COMPAT_END (__ARM_NR_COMPAT_BASE + 0x800) + +-#define __NR_compat_syscalls 440 ++#define __NR_compat_syscalls 441 + #endif + + #define __ARCH_WANT_SYS_CLONE +diff --git a/arch/arm64/include/asm/unistd32.h b/arch/arm64/include/asm/unistd32.h +index 6d95d0c8bf2f..524d19779612 100644 +--- a/arch/arm64/include/asm/unistd32.h ++++ b/arch/arm64/include/asm/unistd32.h +@@ -885,6 +885,8 @@ __SYSCALL(__NR_openat2, sys_openat2) + __SYSCALL(__NR_pidfd_getfd, sys_pidfd_getfd) + #define __NR_faccessat2 439 + __SYSCALL(__NR_faccessat2, sys_faccessat2) ++#define __NR_readfile 440 ++__SYSCALL(__NR_readfile, sys_readfile) + + /* + * Please add new compat syscalls above this comment and update +diff --git a/arch/ia64/kernel/syscalls/syscall.tbl b/arch/ia64/kernel/syscalls/syscall.tbl +index 49e325b604b3..b188f03736bb 100644 +--- a/arch/ia64/kernel/syscalls/syscall.tbl ++++ b/arch/ia64/kernel/syscalls/syscall.tbl +@@ -359,3 +359,4 @@ + 437 common openat2 sys_openat2 + 438 common pidfd_getfd sys_pidfd_getfd + 439 common faccessat2 sys_faccessat2 ++440 common readfile sys_readfile +diff --git a/arch/m68k/kernel/syscalls/syscall.tbl b/arch/m68k/kernel/syscalls/syscall.tbl +index f71b1bbcc198..ab24bcb91344 100644 +--- a/arch/m68k/kernel/syscalls/syscall.tbl ++++ b/arch/m68k/kernel/syscalls/syscall.tbl +@@ -438,3 +438,4 @@ + 437 common openat2 sys_openat2 + 438 common pidfd_getfd sys_pidfd_getfd + 439 common faccessat2 sys_faccessat2 ++440 common readfile sys_readfile +diff --git a/arch/microblaze/kernel/syscalls/syscall.tbl b/arch/microblaze/kernel/syscalls/syscall.tbl +index edacc4561f2b..46c06f800e8e 100644 +--- a/arch/microblaze/kernel/syscalls/syscall.tbl ++++ b/arch/microblaze/kernel/syscalls/syscall.tbl +@@ -444,3 +444,4 @@ + 437 common openat2 sys_openat2 + 438 common pidfd_getfd sys_pidfd_getfd + 439 common faccessat2 sys_faccessat2 ++440 common readfile sys_readfile +diff --git a/arch/mips/kernel/syscalls/syscall_n32.tbl b/arch/mips/kernel/syscalls/syscall_n32.tbl +index f777141f5256..552ba4dafbef 100644 +--- a/arch/mips/kernel/syscalls/syscall_n32.tbl ++++ b/arch/mips/kernel/syscalls/syscall_n32.tbl +@@ -377,3 +377,4 @@ + 437 n32 openat2 sys_openat2 + 438 n32 pidfd_getfd sys_pidfd_getfd + 439 n32 faccessat2 sys_faccessat2 ++440 n32 readfile sys_readfile +diff --git a/arch/mips/kernel/syscalls/syscall_n64.tbl b/arch/mips/kernel/syscalls/syscall_n64.tbl +index da8c76394e17..e12581bf900b 100644 +--- a/arch/mips/kernel/syscalls/syscall_n64.tbl ++++ b/arch/mips/kernel/syscalls/syscall_n64.tbl +@@ -353,3 +353,4 @@ + 437 n64 openat2 sys_openat2 + 438 n64 pidfd_getfd sys_pidfd_getfd + 439 n64 faccessat2 sys_faccessat2 ++440 n64 readfile sys_readfile +diff --git a/arch/mips/kernel/syscalls/syscall_o32.tbl b/arch/mips/kernel/syscalls/syscall_o32.tbl +index 13280625d312..67cb8f8fbdb2 100644 +--- a/arch/mips/kernel/syscalls/syscall_o32.tbl ++++ b/arch/mips/kernel/syscalls/syscall_o32.tbl +@@ -426,3 +426,4 @@ + 437 o32 openat2 sys_openat2 + 438 o32 pidfd_getfd sys_pidfd_getfd + 439 o32 faccessat2 sys_faccessat2 ++440 o32 readfile sys_readfile +diff --git a/arch/parisc/kernel/syscalls/syscall.tbl b/arch/parisc/kernel/syscalls/syscall.tbl +index 5a758fa6ec52..775e5228ab51 100644 +--- a/arch/parisc/kernel/syscalls/syscall.tbl ++++ b/arch/parisc/kernel/syscalls/syscall.tbl +@@ -436,3 +436,4 @@ + 437 common openat2 sys_openat2 + 438 common pidfd_getfd sys_pidfd_getfd + 439 common faccessat2 sys_faccessat2 ++440 common readfile sys_readfile +diff --git a/arch/powerpc/kernel/syscalls/syscall.tbl b/arch/powerpc/kernel/syscalls/syscall.tbl +index f833a3190822..d452db708635 100644 +--- a/arch/powerpc/kernel/syscalls/syscall.tbl ++++ b/arch/powerpc/kernel/syscalls/syscall.tbl +@@ -528,3 +528,4 @@ + 437 common openat2 sys_openat2 + 438 common pidfd_getfd sys_pidfd_getfd + 439 common faccessat2 sys_faccessat2 ++440 common readfile sys_readfile +diff --git a/arch/s390/kernel/syscalls/syscall.tbl b/arch/s390/kernel/syscalls/syscall.tbl +index bfdcb7633957..7ab529813a42 100644 +--- a/arch/s390/kernel/syscalls/syscall.tbl ++++ b/arch/s390/kernel/syscalls/syscall.tbl +@@ -441,3 +441,4 @@ + 437 common openat2 sys_openat2 sys_openat2 + 438 common pidfd_getfd sys_pidfd_getfd sys_pidfd_getfd + 439 common faccessat2 sys_faccessat2 sys_faccessat2 ++440 common readfile sys_readfile sys_readfile +diff --git a/arch/sh/kernel/syscalls/syscall.tbl b/arch/sh/kernel/syscalls/syscall.tbl +index acc35daa1b79..ce8862cdb707 100644 +--- a/arch/sh/kernel/syscalls/syscall.tbl ++++ b/arch/sh/kernel/syscalls/syscall.tbl +@@ -441,3 +441,4 @@ + 437 common openat2 sys_openat2 + 438 common pidfd_getfd sys_pidfd_getfd + 439 common faccessat2 sys_faccessat2 ++440 common readfile sys_readfile +diff --git a/arch/sparc/kernel/syscalls/syscall.tbl b/arch/sparc/kernel/syscalls/syscall.tbl +index 8004a276cb74..d89e7224bb0f 100644 +--- a/arch/sparc/kernel/syscalls/syscall.tbl ++++ b/arch/sparc/kernel/syscalls/syscall.tbl +@@ -484,3 +484,4 @@ + 437 common openat2 sys_openat2 + 438 common pidfd_getfd sys_pidfd_getfd + 439 common faccessat2 sys_faccessat2 ++440 common readfile sys_readfile +diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl +index d8f8a1a69ed1..6f8d0b0acb6a 100644 +--- a/arch/x86/entry/syscalls/syscall_32.tbl ++++ b/arch/x86/entry/syscalls/syscall_32.tbl +@@ -443,3 +443,4 @@ + 437 i386 openat2 sys_openat2 + 438 i386 pidfd_getfd sys_pidfd_getfd + 439 i386 faccessat2 sys_faccessat2 ++440 i386 readfile sys_readfile +diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl +index 78847b32e137..9c54081b7c14 100644 +--- a/arch/x86/entry/syscalls/syscall_64.tbl ++++ b/arch/x86/entry/syscalls/syscall_64.tbl +@@ -360,6 +360,7 @@ + 437 common openat2 sys_openat2 + 438 common pidfd_getfd sys_pidfd_getfd + 439 common faccessat2 sys_faccessat2 ++440 common readfile sys_readfile + + # + # x32-specific system call numbers start at 512 to avoid cache impact +diff --git a/arch/xtensa/kernel/syscalls/syscall.tbl b/arch/xtensa/kernel/syscalls/syscall.tbl +index 69d0d73876b3..7b1f2ea76621 100644 +--- a/arch/xtensa/kernel/syscalls/syscall.tbl ++++ b/arch/xtensa/kernel/syscalls/syscall.tbl +@@ -409,3 +409,4 @@ + 437 common openat2 sys_openat2 + 438 common pidfd_getfd sys_pidfd_getfd + 439 common faccessat2 sys_faccessat2 ++440 common readfile sys_readfile +diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h +index 7c354c2955f5..b5cb9425c0f4 100644 +--- a/include/linux/syscalls.h ++++ b/include/linux/syscalls.h +@@ -1005,6 +1005,8 @@ asmlinkage long sys_pidfd_send_signal(int pidfd, int sig, + siginfo_t __user *info, + unsigned int flags); + asmlinkage long sys_pidfd_getfd(int pidfd, int fd, unsigned int flags); ++asmlinkage long sys_readfile(int dfd, const char __user *filename, ++ char __user *buffer, size_t bufsize, int flags); + + /* + * Architecture-specific system calls +diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h +index f4a01305d9a6..81b677c01266 100644 +--- a/include/uapi/asm-generic/unistd.h ++++ b/include/uapi/asm-generic/unistd.h +@@ -857,9 +857,11 @@ __SYSCALL(__NR_openat2, sys_openat2) + __SYSCALL(__NR_pidfd_getfd, sys_pidfd_getfd) + #define __NR_faccessat2 439 + __SYSCALL(__NR_faccessat2, sys_faccessat2) ++#define __NR_readfile 440 ++__SYSCALL(__NR_readfile, sys_readfile) + + #undef __NR_syscalls +-#define __NR_syscalls 440 ++#define __NR_syscalls 441 + + /* + * 32 bit systems traditionally used different +-- +2.27.0 + diff --git a/0003-selftests-add-readfile-2-selftests.patch b/0003-selftests-add-readfile-2-selftests.patch new file mode 100644 index 00000000000000..c3a405403a0e70 --- /dev/null +++ b/0003-selftests-add-readfile-2-selftests.patch @@ -0,0 +1,578 @@ +From 2a133d8e0cb79bc7566c39aae1191a7118a1202e Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Date: Sun, 8 Mar 2020 09:54:45 +0100 +Subject: [PATCH 3/3] selftests: add readfile(2) selftests + +Test the functionality of readfile(2) in various ways. + +Also provide a simple speed test program to benchmark using readfile() +instead of using open()/read()/close(). + +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + tools/testing/selftests/Makefile | 1 + + tools/testing/selftests/readfile/.gitignore | 3 + + tools/testing/selftests/readfile/Makefile | 7 + + tools/testing/selftests/readfile/readfile.c | 285 ++++++++++++++++++ + .../selftests/readfile/readfile_speed.c | 221 ++++++++++++++ + 5 files changed, 517 insertions(+) + create mode 100644 tools/testing/selftests/readfile/.gitignore + create mode 100644 tools/testing/selftests/readfile/Makefile + create mode 100644 tools/testing/selftests/readfile/readfile.c + create mode 100644 tools/testing/selftests/readfile/readfile_speed.c + +diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile +index 1195bd85af38..82359233b945 100644 +--- a/tools/testing/selftests/Makefile ++++ b/tools/testing/selftests/Makefile +@@ -46,6 +46,7 @@ TARGETS += ptrace + TARGETS += openat2 + TARGETS += rseq + TARGETS += rtc ++TARGETS += readfile + TARGETS += seccomp + TARGETS += sigaltstack + TARGETS += size +diff --git a/tools/testing/selftests/readfile/.gitignore b/tools/testing/selftests/readfile/.gitignore +new file mode 100644 +index 000000000000..f0e758d437e4 +--- /dev/null ++++ b/tools/testing/selftests/readfile/.gitignore +@@ -0,0 +1,3 @@ ++# SPDX-License-Identifier: GPL-2.0 ++readfile ++readfile_speed +diff --git a/tools/testing/selftests/readfile/Makefile b/tools/testing/selftests/readfile/Makefile +new file mode 100644 +index 000000000000..1bf1bdec40f8 +--- /dev/null ++++ b/tools/testing/selftests/readfile/Makefile +@@ -0,0 +1,7 @@ ++# SPDX-License-Identifier: GPL-2.0 ++CFLAGS += -g -I../../../../usr/include/ ++CFLAGS += -O2 -Wl,-no-as-needed -Wall ++ ++TEST_GEN_PROGS := readfile readfile_speed ++ ++include ../lib.mk +diff --git a/tools/testing/selftests/readfile/readfile.c b/tools/testing/selftests/readfile/readfile.c +new file mode 100644 +index 000000000000..f0736c6dfa69 +--- /dev/null ++++ b/tools/testing/selftests/readfile/readfile.c +@@ -0,0 +1,285 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (c) 2020 Greg Kroah-Hartman <gregkh@linuxfoundation.org> ++ * Copyright (c) 2020 The Linux Foundation ++ * ++ * Test the readfile() syscall in various ways. ++ */ ++#define _GNU_SOURCE ++#include <stdio.h> ++#include <stdlib.h> ++#include <sys/syscall.h> ++#include <sys/types.h> ++#include <dirent.h> ++#include <fcntl.h> ++#include <limits.h> ++#include <string.h> ++#include <syscall.h> ++ ++#include "../kselftest.h" ++ ++//#ifndef __NR_readfile ++//#define __NR_readfile -1 ++//#endif ++ ++#define __NR_readfile 440 ++ ++#define TEST_FILE1 "/sys/devices/system/cpu/vulnerabilities/meltdown" ++#define TEST_FILE2 "/sys/devices/system/cpu/vulnerabilities/spectre_v1" ++#define TEST_FILE4 "/sys/kernel/debug/usb/devices" ++ ++static int sys_readfile(int fd, const char *filename, unsigned char *buffer, ++ size_t bufsize, int flags) ++{ ++ return syscall(__NR_readfile, fd, filename, buffer, bufsize, flags); ++} ++ ++/* ++ * Test that readfile() is even in the running kernel or not. ++ */ ++static void test_readfile_supported(void) ++{ ++ const char *proc_map = "/proc/self/maps"; ++ unsigned char buffer[10]; ++ int retval; ++ ++ if (__NR_readfile < 0) ++ ksft_exit_skip("readfile() syscall is not defined for the kernel this test was built against\n"); ++ ++ /* ++ * Do a simple test to see if the syscall really is present in the ++ * running kernel ++ */ ++ retval = sys_readfile(0, proc_map, &buffer[0], sizeof(buffer), 0); ++ if (retval == -1) ++ ksft_exit_skip("readfile() syscall not present on running kernel\n"); ++ ++ ksft_test_result_pass("readfile() syscall present\n"); ++} ++ ++/* ++ * Open all files in a specific sysfs directory and read from them ++ * ++ * This tests the "openat" type functionality of opening all files relative to a ++ * directory. We don't care at the moment about the contents. ++ */ ++static void test_sysfs_files(void) ++{ ++ static unsigned char buffer[8000]; ++ const char *sysfs_dir = "/sys/devices/system/cpu/vulnerabilities/"; ++ struct dirent *dirent; ++ DIR *vuln_sysfs_dir; ++ int sysfs_fd; ++ int retval; ++ ++ sysfs_fd = open(sysfs_dir, O_PATH | O_DIRECTORY); ++ if (sysfs_fd == -1) { ++ ksft_test_result_skip("unable to open %s directory\n", ++ sysfs_dir); ++ return; ++ } ++ ++ vuln_sysfs_dir = opendir(sysfs_dir); ++ if (!vuln_sysfs_dir) { ++ ksft_test_result_skip("%s unable to be opened, skipping test\n"); ++ return; ++ } ++ ++ ksft_print_msg("readfile: testing relative path functionality by reading files in %s\n", ++ sysfs_dir); ++ /* open all sysfs file in this directory and read the whole thing */ ++ while ((dirent = readdir(vuln_sysfs_dir))) { ++ /* ignore . and .. */ ++ if (strcmp(dirent->d_name, ".") == 0 || ++ strcmp(dirent->d_name, "..") == 0) ++ continue; ++ ++ retval = sys_readfile(sysfs_fd, dirent->d_name, &buffer[0], ++ sizeof(buffer), 0); ++ ++ if (retval <= 0) { ++ ksft_test_result_fail("readfile(%s) failed with %d\n", ++ dirent->d_name, retval); ++ goto exit; ++ } ++ ++ /* cut off trailing \n character */ ++ buffer[retval - 1] = 0x00; ++ ksft_print_msg(" '%s' contains \"%s\"\n", dirent->d_name, ++ buffer); ++ } ++ ++ ksft_test_result_pass("readfile() relative path functionality passed\n"); ++ ++exit: ++ closedir(vuln_sysfs_dir); ++ close(sysfs_fd); ++} ++ ++/* Temporary directory variables */ ++static int root_fd; /* test root directory file handle */ ++static char tmpdir[PATH_MAX]; ++ ++static void setup_tmpdir(void) ++{ ++ char *tmpdir_root; ++ ++ tmpdir_root = getenv("TMPDIR"); ++ if (!tmpdir_root) ++ tmpdir_root = "/tmp"; ++ ++ snprintf(tmpdir, PATH_MAX, "%s/readfile.XXXXXX", tmpdir_root); ++ if (!mkdtemp(tmpdir)) { ++ ksft_test_result_fail("mkdtemp(%s) failed\n", tmpdir); ++ ksft_exit_fail(); ++ } ++ ++ root_fd = open(tmpdir, O_PATH | O_DIRECTORY); ++ if (root_fd == -1) { ++ ksft_exit_fail_msg("%s unable to be opened, error = %d\n", ++ tmpdir, root_fd); ++ ksft_exit_fail(); ++ } ++ ++ ksft_print_msg("%s created to use for testing\n", tmpdir); ++} ++ ++static void teardown_tmpdir(void) ++{ ++ int retval; ++ ++ close(root_fd); ++ ++ retval = rmdir(tmpdir); ++ if (retval) { ++ ksft_exit_fail_msg("%s removed with return value %d\n", ++ tmpdir, retval); ++ ksft_exit_fail(); ++ } ++ ksft_print_msg("%s cleaned up and removed\n", tmpdir); ++ ++} ++ ++static void test_filesize(size_t size) ++{ ++ char filename[PATH_MAX]; ++ unsigned char *write_data; ++ unsigned char *read_data; ++ int fd; ++ int retval; ++ size_t i; ++ ++ snprintf(filename, PATH_MAX, "size-%ld", size); ++ ++ read_data = malloc(size); ++ write_data = malloc(size); ++ if (!read_data || !write_data) ++ ksft_exit_fail_msg("Unable to allocate %ld bytes\n", size); ++ ++ fd = openat(root_fd, filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); ++ if (fd < 0) ++ ksft_exit_fail_msg("Unable to create file %s\n", filename); ++ ++ ksft_print_msg("%s created\n", filename); ++ ++ for (i = 0; i < size; ++i) ++ write_data[i] = (unsigned char)(0xff & i); ++ ++ write(fd, write_data, size); ++ close(fd); ++ ++ retval = sys_readfile(root_fd, filename, read_data, size, 0); ++ ++ if (retval != size) { ++ ksft_test_result_fail("Read %d bytes but wanted to read %ld bytes.\n", ++ retval, size); ++ goto exit; ++ } ++ ++ if (memcmp(read_data, write_data, size) != 0) { ++ ksft_test_result_fail("Read data of buffer size %d did not match written data\n", ++ size); ++ goto exit; ++ } ++ ++ ksft_test_result_pass("readfile() of size %ld succeeded.\n", size); ++ ++exit: ++ unlinkat(root_fd, filename, 0); ++ free(write_data); ++ free(read_data); ++} ++ ++ ++/* ++ * Create a bunch of differently sized files, and verify we read the correct ++ * amount of data from them. ++ */ ++static void test_filesizes(void) ++{ ++ setup_tmpdir(); ++ ++ test_filesize(0x10); ++ test_filesize(0x100); ++ test_filesize(0x1000); ++ test_filesize(0x10000); ++ test_filesize(0x100000); ++ test_filesize(0x1000000); ++ ++ teardown_tmpdir(); ++ ++} ++ ++static void readfile(const char *filename) ++{ ++// int root_fd; ++ unsigned char buffer[16000]; ++ int retval; ++ ++ memset(buffer, 0x00, sizeof(buffer)); ++ ++// root_fd = open("/", O_DIRECTORY); ++// if (root_fd == -1) ++// ksft_exit_fail_msg("error with root_fd\n"); ++ ++ retval = sys_readfile(root_fd, filename, &buffer[0], sizeof(buffer), 0); ++ ++// close(root_fd); ++ ++ if (retval <= 0) ++ ksft_test_result_fail("readfile() test of filename=%s failed with retval %d\n", ++ filename, retval); ++ else ++ ksft_test_result_pass("readfile() test of filename=%s succeeded with retval=%d\n", ++ filename, retval); ++// buffer='%s'\n", ++// filename, retval, &buffer[0]); ++ ++} ++ ++ ++int main(int argc, char *argv[]) ++{ ++ ksft_print_header(); ++ ksft_set_plan(10); ++ ++ test_readfile_supported(); // 1 test ++ ++ test_sysfs_files(); // 1 test ++ ++ test_filesizes(); // 6 tests ++ ++ setup_tmpdir(); ++ ++ readfile(TEST_FILE1); ++ readfile(TEST_FILE2); ++// readfile(TEST_FILE4); ++ ++ teardown_tmpdir(); ++ ++ if (ksft_get_fail_cnt()) ++ return ksft_exit_fail(); ++ ++ return ksft_exit_pass(); ++} ++ +diff --git a/tools/testing/selftests/readfile/readfile_speed.c b/tools/testing/selftests/readfile/readfile_speed.c +new file mode 100644 +index 000000000000..bbf985b30d1b +--- /dev/null ++++ b/tools/testing/selftests/readfile/readfile_speed.c +@@ -0,0 +1,221 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (c) 2020 Greg Kroah-Hartman <gregkh@linuxfoundation.org> ++ * Copyright (c) 2020 The Linux Foundation ++ * ++ * Tiny test program to try to benchmark the speed of the readfile syscall vs. ++ * the open/read/close sequence it replaces. ++ */ ++#define _GNU_SOURCE ++#include <stdio.h> ++#include <stdlib.h> ++#include <sys/syscall.h> ++#include <sys/types.h> ++#include <sys/stat.h> ++#include <dirent.h> ++#include <fcntl.h> ++#include <limits.h> ++#include <string.h> ++#include <syscall.h> ++#include <errno.h> ++#include <unistd.h> ++#include <stdarg.h> ++ ++//#ifndef __NR_readfile ++//#define __NR_readfile -1 ++//#endif ++ ++#define __NR_readfile 440 ++ ++#define TEST_FILE "/sys/devices/system/cpu/vulnerabilities/meltdown" ++ ++static int sys_readfile(int fd, const char *filename, unsigned char *buffer, ++ size_t bufsize, int flags) ++{ ++ return syscall(__NR_readfile, fd, filename, buffer, bufsize, flags); ++} ++ ++/* taken from all-io.h from util-linux repo */ ++static inline ssize_t read_all(int fd, unsigned char *buf, size_t count) ++{ ++ ssize_t ret; ++ ssize_t c = 0; ++ int tries = 0; ++ ++ //memset(buf, 0, count); ++ while (count > 0) { ++ ret = read(fd, buf, count); ++ if (ret <= 0) { ++ if (ret < 0 && (errno == EAGAIN || errno == EINTR) && ++ (tries++ < 5)) { ++ usleep(250000); ++ continue; ++ } ++ return c ? c : -1; ++ } ++ tries = 0; ++ count -= ret; ++ buf += ret; ++ c += ret; ++ } ++ return c; ++} ++ ++static int openreadclose(const char *filename, unsigned char *buffer, ++ size_t bufsize) ++{ ++ size_t count; ++ int fd; ++ ++ fd = openat(0, filename, O_RDONLY); ++ if (fd < 0) { ++ printf("error opening %s\n", filename); ++ return fd; ++ } ++ ++ count = read_all(fd, buffer, bufsize); ++ if (count < 0) { ++ printf("Error %ld reading from %s\n", count, filename); ++ } ++ ++ close(fd); ++ return count; ++} ++ ++enum test_type { ++ READFILE, ++ OPENREADCLOSE, ++}; ++ ++static int do_read_file_test(int loops, enum test_type test_type, ++ const char *filename, ++ unsigned char *buffer, size_t bufsize) ++{ ++ char *test; ++ int retval; ++ int i; ++ ++ switch (test_type) { ++ case READFILE: ++ test = "readfile"; ++ break; ++ ++ case OPENREADCLOSE: ++ test = "open/read/close"; ++ break; ++ default: ++ fprintf(stderr, "wrong test type"); ++ return -1; ++ } ++ ++ fprintf(stdout, ++ "Running %s test on file %s for %d loops...\n", ++ test, filename, loops); ++ ++ for (i = 0; i < loops; ++i) { ++ switch (test_type) { ++ case READFILE: ++ retval = sys_readfile(0, filename, buffer, bufsize, O_RDONLY); ++ break; ++ ++ case OPENREADCLOSE: ++ retval = openreadclose(filename, buffer, bufsize); ++ break; ++ } ++ if (retval < 0) { ++ fprintf(stderr, ++ "test failed on loop %d with error %d\n", ++ i, retval); ++ return retval; ++ } ++ } ++ return 0; ++} ++ ++static int check_file_present(const char *filename) ++{ ++ struct stat sb; ++ int retval; ++ ++ retval = stat(filename, &sb); ++ if (retval == -1) { ++ fprintf(stderr, ++ "filename %s is not present\n", filename); ++ return retval; ++ } ++ ++ if ((sb.st_mode & S_IFMT) != S_IFREG) { ++ fprintf(stderr, ++ "filename %s must be a real file, not anything else.\n", ++ filename); ++ return -1; ++ } ++ return 0; ++} ++ ++static void usage(char *progname) ++{ ++ fprintf(stderr, ++ "usage: %s [options]\n" ++ " -l loops Number of loops to run the test for.\n" ++ " default is 10'000\n" ++ " -t testtype Test type to run\n" ++ " types are: readfile, openreadclose\n" ++ " default is readfile\n", ++ progname); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ int loops = 10000; ++ unsigned char buffer[10000]; ++ char c; ++ char *testtype = "readfile"; ++ char *progname; ++ char *filename; ++ enum test_type test_type; ++ int retval; ++ ++ progname = strrchr(argv[0], '/'); ++ progname = progname ? 1+progname : argv[0]; ++ ++ while (EOF != (c = getopt(argc, argv, "t:hl:"))) { ++ switch (c) { ++ case 'l': ++ loops = atoi(optarg); ++ break; ++ ++ case 't': ++ testtype = optarg; ++ break; ++ ++ case 'h': ++ usage(progname); ++ return 0; ++ ++ default: ++ usage(progname); ++ return -1; ++ } ++ } ++ ++ if (strcmp(testtype, "readfile") == 0) ++ test_type = READFILE; ++ else if (strcmp(testtype, "openreadclose") == 0) ++ test_type = OPENREADCLOSE; ++ else { ++ usage(progname); ++ return -1; ++ } ++ ++ filename = TEST_FILE; ++ ++ retval = check_file_present(filename); ++ if (retval) ++ return retval; ++ ++ retval = do_read_file_test(loops, test_type, TEST_FILE, ++ &buffer[0], sizeof(buffer)); ++ ++ return retval; ++} +-- +2.27.0 + @@ -1,4 +1,7 @@ # +0001-readfile-implement-readfile-syscall.patch +0002-arch-wire-up-the-readfile-syscall.patch +0003-selftests-add-readfile-2-selftests.patch spdxcheck-print-out-files-without-any-spdx-lines.patch 0001-tty-n_r3964-locking-fixups.patch |