Thread (7 messages) 7 messages, 3 authors, 2020-08-21

Re: [PATCH 1/3] lib, include/linux: add usercopy failure capability

From: Marco Elver <elver@google.com>
Date: 2020-08-21 13:31:50
Also in: linux-arch, lkml

On Fri, Aug 21, 2020 at 01:51PM +0200, Dmitry Vyukov wrote:
...
quoted
+++ 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);
Marco, what's the right way to annotate these concurrent accesses for KCSAN?
For debugfs variables that are accessed concurrently, the only
non-data-racy option (currently) is to use debugfs_create_atomic_t() and
make the variable an atomic_t.

If it's read-mostly as is the case here, and given that atomic_read() is
cheap (it maps to READ_ONCE on x86 and arm64), that'd be reasonable even
if performance is a concern.
quoted
+       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);
If you wanted to retain the u32 in debugfs, you can mark this
'data_race(fail_usercopy.failsize)' -- since what we're doing here is
probabilistic anyway, reading a garbage value won't affect things much.

Alternatively, just switch to atomic_t and it'll just be an
atomic_read().

Thanks,
-- Marco
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help