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 2/3] lib, uaccess: add failure injection to usercopy functions
Date: Fri, 21 Aug 2020 10:49:24 +0000 [thread overview]
Message-ID: <20200821104926.828511-3-alinde@google.com> (raw)
In-Reply-To: <20200821104926.828511-1-alinde@google.com>
From: Albert van der Linde <alinde@google.com>
To test fault-tolerance of usercopy accesses, introduce fault injection
in usercopy functions.
Adds failure injection to usercopy functions. If a failure is expected
we return either the failure or the total amount of bytes. As many
usercopy functions can fail partially, permit also partial failures:
e.g., copy_from_user can fail copying between 0 and n.
Signed-off-by: Albert van der Linde <alinde@google.com>
---
include/linux/uaccess.h | 31 ++++++++++++++++++++++++++-----
lib/iov_iter.c | 20 +++++++++++++++++---
lib/strncpy_from_user.c | 3 +++
lib/usercopy.c | 13 +++++++++++--
4 files changed, 57 insertions(+), 10 deletions(-)
diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h
index 94b285411659..79e736077ef4 100644
--- a/include/linux/uaccess.h
+++ b/include/linux/uaccess.h
@@ -2,6 +2,7 @@
#ifndef __LINUX_UACCESS_H__
#define __LINUX_UACCESS_H__
+#include <linux/fault-inject-usercopy.h>
#include <linux/instrumented.h>
#include <linux/sched.h>
#include <linux/thread_info.h>
@@ -82,10 +83,14 @@ __copy_from_user_inatomic(void *to, const void __user *from, unsigned long n)
static __always_inline __must_check unsigned long
__copy_from_user(void *to, const void __user *from, unsigned long n)
{
+ long not_copied = should_fail_usercopy(n);
+
+ if (not_copied < 0)
+ not_copied = n;
might_fault();
instrument_copy_from_user(to, from, n);
check_object_size(to, n, false);
- return raw_copy_from_user(to, from, n);
+ return not_copied + raw_copy_from_user(to, from, n - not_copied);
}
/**
@@ -104,18 +109,26 @@ __copy_from_user(void *to, const void __user *from, unsigned long n)
static __always_inline __must_check unsigned long
__copy_to_user_inatomic(void __user *to, const void *from, unsigned long n)
{
+ long not_copied = should_fail_usercopy(n);
+
+ if (not_copied < 0)
+ not_copied = n;
instrument_copy_to_user(to, from, n);
check_object_size(from, n, true);
- return raw_copy_to_user(to, from, n);
+ return not_copied + raw_copy_to_user(to, from, n - not_copied);
}
static __always_inline __must_check unsigned long
__copy_to_user(void __user *to, const void *from, unsigned long n)
{
+ long not_copied = should_fail_usercopy(n);
+
+ if (not_copied < 0)
+ not_copied = n;
might_fault();
instrument_copy_to_user(to, from, n);
check_object_size(from, n, true);
- return raw_copy_to_user(to, from, n);
+ return not_copied + raw_copy_to_user(to, from, n - not_copied);
}
#ifdef INLINE_COPY_FROM_USER
@@ -123,10 +136,14 @@ static inline __must_check unsigned long
_copy_from_user(void *to, const void __user *from, unsigned long n)
{
unsigned long res = n;
+ long not_copied = should_fail_usercopy(n);
+
+ if (not_copied < 0)
+ not_copied = n;
might_fault();
if (likely(access_ok(from, n))) {
instrument_copy_from_user(to, from, n);
- res = raw_copy_from_user(to, from, n);
+ res = not_copied + raw_copy_from_user(to, from, n - not_copied);
}
if (unlikely(res))
memset(to + (n - res), 0, res);
@@ -141,10 +158,14 @@ _copy_from_user(void *, const void __user *, unsigned long);
static inline __must_check unsigned long
_copy_to_user(void __user *to, const void *from, unsigned long n)
{
+ long not_copied = should_fail_usercopy(n);
+
+ if (not_copied < 0)
+ not_copied = n;
might_fault();
if (access_ok(to, n)) {
instrument_copy_to_user(to, from, n);
- n = raw_copy_to_user(to, from, n);
+ n = not_copied + raw_copy_to_user(to, from, n - not_copied);
}
return n;
}
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
index 5e40786c8f12..c55c9bff9b0c 100644
--- a/lib/iov_iter.c
+++ b/lib/iov_iter.c
@@ -2,6 +2,7 @@
#include <crypto/hash.h>
#include <linux/export.h>
#include <linux/bvec.h>
+#include <linux/fault-inject-usercopy.h>
#include <linux/uio.h>
#include <linux/pagemap.h>
#include <linux/slab.h>
@@ -139,18 +140,26 @@
static int copyout(void __user *to, const void *from, size_t n)
{
+ long not_copied = should_fail_usercopy(n);
+
+ if (not_copied < 0)
+ return not_copied;
if (access_ok(to, n)) {
instrument_copy_to_user(to, from, n);
- n = raw_copy_to_user(to, from, n);
+ n = not_copied + raw_copy_to_user(to, from, n - not_copied);
}
return n;
}
static int copyin(void *to, const void __user *from, size_t n)
{
+ long not_copied = should_fail_usercopy(n);
+
+ if (not_copied < 0)
+ return not_copied;
if (access_ok(from, n)) {
instrument_copy_from_user(to, from, n);
- n = raw_copy_from_user(to, from, n);
+ n = not_copied + raw_copy_from_user(to, from, n - not_copied);
}
return n;
}
@@ -640,9 +649,14 @@ EXPORT_SYMBOL(_copy_to_iter);
#ifdef CONFIG_ARCH_HAS_UACCESS_MCSAFE
static int copyout_mcsafe(void __user *to, const void *from, size_t n)
{
+ long not_copied = should_fail_usercopy(n);
+
+ if (not_copied < 0)
+ return not_copied;
if (access_ok(to, n)) {
instrument_copy_to_user(to, from, n);
- n = copy_to_user_mcsafe((__force void *) to, from, n);
+ n = not_copied + copy_to_user_mcsafe((__force void *) to,
+ from, n - not_copied);
}
return n;
}
diff --git a/lib/strncpy_from_user.c b/lib/strncpy_from_user.c
index 34696a348864..f65973007931 100644
--- a/lib/strncpy_from_user.c
+++ b/lib/strncpy_from_user.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/compiler.h>
#include <linux/export.h>
+#include <linux/fault-inject-usercopy.h>
#include <linux/kasan-checks.h>
#include <linux/thread_info.h>
#include <linux/uaccess.h>
@@ -101,6 +102,8 @@ long strncpy_from_user(char *dst, const char __user *src, long count)
might_fault();
if (unlikely(count <= 0))
return 0;
+ if (should_fail_usercopy(count))
+ return -EFAULT;
max_addr = user_addr_max();
src_addr = (unsigned long)untagged_addr(src);
diff --git a/lib/usercopy.c b/lib/usercopy.c
index b26509f112f9..e79716b4634b 100644
--- a/lib/usercopy.c
+++ b/lib/usercopy.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/bitops.h>
+#include <linux/fault-inject-usercopy.h>
#include <linux/instrumented.h>
#include <linux/uaccess.h>
@@ -9,10 +10,14 @@
unsigned long _copy_from_user(void *to, const void __user *from, unsigned long n)
{
unsigned long res = n;
+ long not_copied = should_fail_usercopy(n);
+
+ if (not_copied < 0)
+ not_copied = n;
might_fault();
if (likely(access_ok(from, n))) {
instrument_copy_from_user(to, from, n);
- res = raw_copy_from_user(to, from, n);
+ res = not_copied + raw_copy_from_user(to, from, n - not_copied);
}
if (unlikely(res))
memset(to + (n - res), 0, res);
@@ -24,10 +29,14 @@ EXPORT_SYMBOL(_copy_from_user);
#ifndef INLINE_COPY_TO_USER
unsigned long _copy_to_user(void __user *to, const void *from, unsigned long n)
{
+ long not_copied = should_fail_usercopy(n);
+
+ if (not_copied < 0)
+ not_copied = n;
might_fault();
if (likely(access_ok(to, n))) {
instrument_copy_to_user(to, from, n);
- n = raw_copy_to_user(to, from, n);
+ n = not_copied + raw_copy_to_user(to, from, n - not_copied);
}
return n;
}
--
2.28.0.297.g1956fa8f8d-goog
next prev parent reply other threads:[~2020-08-21 10:51 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 ` [PATCH 1/3] lib, include/linux: add usercopy failure capability albert.linde
2020-08-21 11:51 ` Dmitry Vyukov
2020-08-21 13:31 ` Marco Elver
2020-08-21 10:49 ` albert.linde [this message]
2020-08-21 11:46 ` [PATCH 2/3] lib, uaccess: add failure injection to usercopy functions 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-3-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.