From: albert.linde@gmail.com
To: akpm@linux-foundation.org, bp@alien8.de, mingo@redhat.com,
corbet@lwn.net, tglx@linutronix.de, arnd@arndb.de
Cc: akinobu.mita@gmail.com, hpa@zytor.com, viro@zeniv.linux.org.uk,
glider@google.com, andreyknvl@google.com, dvyukov@google.com,
elver@google.com, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-arch@vger.kernel.org,
x86@kernel.org, Albert van der Linde <alinde@google.com>
Subject: [PATCH 1/3] lib, include/linux: add usercopy failure capability
Date: Fri, 21 Aug 2020 10:49:23 +0000 [thread overview]
Message-ID: <20200821104926.828511-2-alinde@google.com> (raw)
In-Reply-To: <20200821104926.828511-1-alinde@google.com>
From: Albert van der Linde <alinde@google.com>
Add a failure injection capability to improve testing of fault-tolerance
in usages of user memory access functions.
Adds CONFIG_FAULT_INJECTION_USERCOPY to enable faults in usercopy
functions. By default functions are to either fail with -EFAULT or
return that no bytes were copied. To use partial copies (e.g.,
copy_from_user permits partial failures) the number of bytes not to copy
must be written to /sys/kernel/debug/fail_usercopy/failsize.
Signed-off-by: Albert van der Linde <alinde@google.com>
---
.../fault-injection/fault-injection.rst | 64 ++++++++++++++++++
include/linux/fault-inject-usercopy.h | 20 ++++++
lib/Kconfig.debug | 7 ++
lib/Makefile | 1 +
lib/fault-inject-usercopy.c | 66 +++++++++++++++++++
5 files changed, 158 insertions(+)
create mode 100644 include/linux/fault-inject-usercopy.h
create mode 100644 lib/fault-inject-usercopy.c
diff --git a/Documentation/fault-injection/fault-injection.rst b/Documentation/fault-injection/fault-injection.rst
index f850ad018b70..cf52eabde332 100644
--- a/Documentation/fault-injection/fault-injection.rst
+++ b/Documentation/fault-injection/fault-injection.rst
@@ -16,6 +16,10 @@ Available fault injection capabilities
injects page allocation failures. (alloc_pages(), get_free_pages(), ...)
+- fail_usercopy
+
+ injects failures in user memory access functions. (copy_from_user(), get_user(), ...)
+
- fail_futex
injects futex deadlock and uaddr fault errors.
@@ -138,6 +142,12 @@ configuration of fault-injection capabilities.
specifies the minimum page allocation order to be injected
failures.
+- /sys/kernel/debug/fail_usercopy/failsize:
+
+ specifies the error code to return or amount of bytes not to copy.
+ If set to 0 then -EFAULT is returned instead. Positive values can be
+ used to inject partial copies (copy_from_user(), ...)
+
- /sys/kernel/debug/fail_futex/ignore-private:
Format: { 'Y' | 'N' }
@@ -177,6 +187,7 @@ use the boot option::
failslab=
fail_page_alloc=
+ fail_usercopy=
fail_make_request=
fail_futex=
mmc_core.fail_request=<interval>,<probability>,<space>,<times>
@@ -383,6 +394,59 @@ allocation failure::
./tools/testing/fault-injection/failcmd.sh --times=100 \
-- make -C tools/testing/selftests/ run_tests
+
+Fail usercopy functions
+---------------------------------
+
+The following code fails the usercopy call in stat: copy_to_user is only
+partially completed.
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/sendfile.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+void inject_size()
+{
+ int fd = open("/sys/kernel/debug/fail_usercopy/failsize", O_RDWR);
+ char buf[16];
+ sprintf(buf, "%d", 60);
+ write(fd, buf, strlen(buf));
+}
+
+void inject_fault()
+{
+ int fd = open("/proc/thread-self/fail-nth", O_RDWR);
+ char buf[16];
+ sprintf(buf, "%d", 4);
+ write(fd, buf, strlen(buf));
+}
+
+int main()
+{
+ struct stat sb;
+ inject_size();
+ inject_fault();
+ stat(".", &sb);
+ printf("Stat error code: %d\n", errno);
+ printf("Last status change: %s", ctime(&sb.st_ctime));
+ printf("Last file access: %s", ctime(&sb.st_atime));
+ printf("Last file modification: %s", ctime(&sb.st_mtime));
+ return 0;
+}
+
+Example output:
+Stat error code: 14
+Last status change: Thu Jan 1 00:00:00 1970
+Last file access: Tue Aug 18 14:09:34 2020
+Last file modification: Sun Dec 12 00:19:57 2989041
+
Systematic faults using fail-nth
---------------------------------
diff --git a/include/linux/fault-inject-usercopy.h b/include/linux/fault-inject-usercopy.h
new file mode 100644
index 000000000000..95dad8ddb56f
--- /dev/null
+++ b/include/linux/fault-inject-usercopy.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * This header provides a wrapper for partial failures on usercopy functions.
+ * For usage see Documentation/fault-injection/fault-injection.rst
+ */
+#ifndef __LINUX_FAULT_INJECT_USERCOPY_H__
+#define __LINUX_FAULT_INJECT_USERCOPY_H__
+
+#ifdef CONFIG_FAULT_INJECTION_USERCOPY
+
+long should_fail_usercopy(unsigned long n);
+
+#else
+
+static inline long should_fail_usercopy(unsigned long n) { return 0; }
+
+#endif /* CONFIG_FAULT_INJECTION_USERCOPY */
+
+#endif /* __LINUX_FAULT_INJECT_USERCOPY_H__ */
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index e068c3c7189a..bd0ec3ddb459 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1770,6 +1770,13 @@ config FAIL_PAGE_ALLOC
help
Provide fault-injection capability for alloc_pages().
+config FAULT_INJECTION_USERCOPY
+ bool "Fault injection capability for usercopy functions"
+ depends on FAULT_INJECTION
+ help
+ Provides fault-injection capability to inject failures and
+ partial copies in usercopy functions.
+
config FAIL_MAKE_REQUEST
bool "Fault-injection capability for disk IO"
depends on FAULT_INJECTION && BLOCK
diff --git a/lib/Makefile b/lib/Makefile
index a4a4c6864f51..18daad2bc606 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -207,6 +207,7 @@ obj-$(CONFIG_AUDIT_COMPAT_GENERIC) += compat_audit.o
obj-$(CONFIG_IOMMU_HELPER) += iommu-helper.o
obj-$(CONFIG_FAULT_INJECTION) += fault-inject.o
+obj-$(CONFIG_FAULT_INJECTION_USERCOPY) += fault-inject-usercopy.o
obj-$(CONFIG_NOTIFIER_ERROR_INJECTION) += notifier-error-inject.o
obj-$(CONFIG_PM_NOTIFIER_ERROR_INJECT) += pm-notifier-error-inject.o
obj-$(CONFIG_NETDEV_NOTIFIER_ERROR_INJECT) += netdev-notifier-error-inject.o
diff --git a/lib/fault-inject-usercopy.c b/lib/fault-inject-usercopy.c
new file mode 100644
index 000000000000..c151e0817ca7
--- /dev/null
+++ b/lib/fault-inject-usercopy.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/fault-inject.h>
+#include <linux/fault-inject-usercopy.h>
+#include <linux/random.h>
+
+static struct {
+ struct fault_attr attr;
+ u32 failsize;
+} fail_usercopy = {
+ .attr = FAULT_ATTR_INITIALIZER,
+ .failsize = 0,
+};
+
+static int __init setup_fail_usercopy(char *str)
+{
+ return setup_fault_attr(&fail_usercopy.attr, str);
+}
+__setup("fail_usercopy=", setup_fail_usercopy);
+
+#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
+
+static int __init fail_usercopy_debugfs(void)
+{
+ umode_t mode = S_IFREG | 0600;
+ struct dentry *dir;
+
+ dir = fault_create_debugfs_attr("fail_usercopy", NULL,
+ &fail_usercopy.attr);
+ if (IS_ERR(dir))
+ return PTR_ERR(dir);
+
+ debugfs_create_u32("failsize", mode, dir,
+ &fail_usercopy.failsize);
+ return 0;
+}
+
+late_initcall(fail_usercopy_debugfs);
+
+#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */
+
+/**
+ * should_fail_usercopy() - Failure code or amount of bytes not to copy.
+ * @n: Size of the original copy call.
+ *
+ * The general idea is to have a method which returns the amount of bytes not
+ * to copy, a failure to return, or 0 if the calling function should progress
+ * without a failure. E.g., copy_{to,from}_user should NOT copy the amount of
+ * bytes returned by should_fail_usercopy, returning this value (in addition
+ * to any bytes that could actually not be copied) or a failure.
+ *
+ * Return: one of:
+ * negative, failure to return;
+ * 0, progress normally;
+ * a number in ]0, n], the number of bytes not to copy.
+ *
+ */
+long should_fail_usercopy(unsigned long n)
+{
+ if (should_fail(&fail_usercopy.attr, n)) {
+ if (fail_usercopy.failsize > 0)
+ return fail_usercopy.failsize % (n + 1);
+ return -EFAULT;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(should_fail_usercopy);
--
2.28.0.297.g1956fa8f8d-goog
next prev parent reply other threads:[~2020-08-21 10:50 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-08-21 10:49 [PATCH 0/3] add fault injection to user memory access functions albert.linde
2020-08-21 10:49 ` albert.linde [this message]
2020-08-21 11:51 ` [PATCH 1/3] lib, include/linux: add usercopy failure capability Dmitry Vyukov
2020-08-21 13:31 ` Marco Elver
2020-08-21 10:49 ` [PATCH 2/3] lib, uaccess: add failure injection to usercopy functions albert.linde
2020-08-21 11:46 ` Dmitry Vyukov
2020-08-21 10:49 ` [PATCH 3/3] x86: add failure injection to get/put/clear_user albert.linde
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200821104926.828511-2-alinde@google.com \
--to=albert.linde@gmail.com \
--cc=akinobu.mita@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=alinde@google.com \
--cc=andreyknvl@google.com \
--cc=arnd@arndb.de \
--cc=bp@alien8.de \
--cc=corbet@lwn.net \
--cc=dvyukov@google.com \
--cc=elver@google.com \
--cc=glider@google.com \
--cc=hpa@zytor.com \
--cc=linux-arch@vger.kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=tglx@linutronix.de \
--cc=viro@zeniv.linux.org.uk \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.