linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/6] arm64: untag user pointers passed to the kernel
@ 2018-05-25 17:21 Andrey Konovalov
  2018-05-25 17:21 ` [PATCH v3 1/6] arm64: add type casts to untagged_addr macro Andrey Konovalov
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Andrey Konovalov @ 2018-05-25 17:21 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Mark Rutland, Robin Murphy,
	Al Viro, Andrey Konovalov, Kees Cook, Kate Stewart,
	Greg Kroah-Hartman, Andrew Morton, Ingo Molnar,
	Kirill A . Shutemov, linux-arm-kernel, linux-doc, linux-mm,
	linux-arch, linux-kernel
  Cc: Dmitry Vyukov, Kostya Serebryany, Evgeniy Stepanov, Lee Smith,
	Ramana Radhakrishnan, Jacob Bramley, Ruben Ayrapetyan,
	Chintan Pandya

arm64 has a feature called Top Byte Ignore, which allows to embed pointer
tags into the top byte of each pointer. Userspace programs (such as
HWASan, a memory debugging tool [1]) might use this feature and pass
tagged user pointers to the kernel through syscalls or other interfaces.

This patch makes a few of the kernel interfaces accept tagged user
pointers. The kernel is already able to handle user faults with tagged
pointers and has the untagged_addr macro, which this patchset reuses.

We're not trying to cover all possible ways the kernel accepts user
pointers in one patchset, so this one should be considered as a start.

Thanks!

[1] http://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html

Changes in v3:
- Rebased onto e5c51f30 (4.17-rc6+).
- Added linux-arch@ to the list of recipients.

Changes in v2:
- Rebased onto 2d618bdf (4.17-rc3+).
- Removed excessive untagging in gup.c.
- Removed untagging pointers returned from __uaccess_mask_ptr.

Changes in v1:
- Rebased onto 4.17-rc1.

Changes in RFC v2:
- Added "#ifndef untagged_addr..." fallback in linux/uaccess.h instead of
  defining it for each arch individually.
- Updated Documentation/arm64/tagged-pointers.txt.
- Dropped “mm, arm64: untag user addresses in memory syscalls”.
- Rebased onto 3eb2ce82 (4.16-rc7).

Andrey Konovalov (6):
  arm64: add type casts to untagged_addr macro
  uaccess: add untagged_addr definition for other arches
  arm64: untag user addresses in access_ok and __uaccess_mask_ptr
  mm, arm64: untag user addresses in mm/gup.c
  lib, arm64: untag addrs passed to strncpy_from_user and strnlen_user
  arm64: update Documentation/arm64/tagged-pointers.txt

 Documentation/arm64/tagged-pointers.txt |  5 +++--
 arch/arm64/include/asm/uaccess.h        | 14 +++++++++-----
 include/linux/uaccess.h                 |  4 ++++
 lib/strncpy_from_user.c                 |  2 ++
 lib/strnlen_user.c                      |  2 ++
 mm/gup.c                                |  4 ++++
 6 files changed, 24 insertions(+), 7 deletions(-)

-- 
2.17.0.921.gf22659ad46-goog

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v3 1/6] arm64: add type casts to untagged_addr macro
  2018-05-25 17:21 [PATCH v3 0/6] arm64: untag user pointers passed to the kernel Andrey Konovalov
@ 2018-05-25 17:21 ` Andrey Konovalov
  2018-05-25 17:21 ` [PATCH v3 2/6] uaccess: add untagged_addr definition for other arches Andrey Konovalov
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Andrey Konovalov @ 2018-05-25 17:21 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Mark Rutland, Robin Murphy,
	Al Viro, Andrey Konovalov, Kees Cook, Kate Stewart,
	Greg Kroah-Hartman, Andrew Morton, Ingo Molnar,
	Kirill A . Shutemov, linux-arm-kernel, linux-doc, linux-mm,
	linux-arch, linux-kernel
  Cc: Dmitry Vyukov, Kostya Serebryany, Evgeniy Stepanov, Lee Smith,
	Ramana Radhakrishnan, Jacob Bramley, Ruben Ayrapetyan,
	Chintan Pandya

This patch makes the untagged_addr macro accept all kinds of address types
(void *, unsigned long, etc.) and allows not to specify type casts in each
place where it is used. This is done by using __typeof__.

Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
---
 arch/arm64/include/asm/uaccess.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
index e66b0fca99c2..2d6451cbaa86 100644
--- a/arch/arm64/include/asm/uaccess.h
+++ b/arch/arm64/include/asm/uaccess.h
@@ -102,7 +102,8 @@ static inline unsigned long __range_ok(const void __user *addr, unsigned long si
  * up with a tagged userland pointer. Clear the tag to get a sane pointer to
  * pass on to access_ok(), for instance.
  */
-#define untagged_addr(addr)		sign_extend64(addr, 55)
+#define untagged_addr(addr)		\
+	((__typeof__(addr))sign_extend64((__u64)(addr), 55))
 
 #define access_ok(type, addr, size)	__range_ok(addr, size)
 #define user_addr_max			get_fs
-- 
2.17.0.921.gf22659ad46-goog

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v3 2/6] uaccess: add untagged_addr definition for other arches
  2018-05-25 17:21 [PATCH v3 0/6] arm64: untag user pointers passed to the kernel Andrey Konovalov
  2018-05-25 17:21 ` [PATCH v3 1/6] arm64: add type casts to untagged_addr macro Andrey Konovalov
@ 2018-05-25 17:21 ` Andrey Konovalov
  2018-05-25 17:21 ` [PATCH v3 3/6] arm64: untag user addresses in access_ok and __uaccess_mask_ptr Andrey Konovalov
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Andrey Konovalov @ 2018-05-25 17:21 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Mark Rutland, Robin Murphy,
	Al Viro, Andrey Konovalov, Kees Cook, Kate Stewart,
	Greg Kroah-Hartman, Andrew Morton, Ingo Molnar,
	Kirill A . Shutemov, linux-arm-kernel, linux-doc, linux-mm,
	linux-arch, linux-kernel
  Cc: Dmitry Vyukov, Kostya Serebryany, Evgeniy Stepanov, Lee Smith,
	Ramana Radhakrishnan, Jacob Bramley, Ruben Ayrapetyan,
	Chintan Pandya

To allow arm64 syscalls accept tagged pointers from userspace, we must
untag them when they are passed to the kernel. Since untagging is done in
generic parts of the kernel (like the mm subsystem), the untagged_addr
macro should be defined for all architectures.

Define it as a noop for other architectures besides arm64.

Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
---
 include/linux/uaccess.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h
index efe79c1cdd47..c045b4eff95e 100644
--- a/include/linux/uaccess.h
+++ b/include/linux/uaccess.h
@@ -13,6 +13,10 @@
 
 #include <asm/uaccess.h>
 
+#ifndef untagged_addr
+#define untagged_addr(addr) addr
+#endif
+
 /*
  * Architectures should provide two primitives (raw_copy_{to,from}_user())
  * and get rid of their private instances of copy_{to,from}_user() and
-- 
2.17.0.921.gf22659ad46-goog

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v3 3/6] arm64: untag user addresses in access_ok and __uaccess_mask_ptr
  2018-05-25 17:21 [PATCH v3 0/6] arm64: untag user pointers passed to the kernel Andrey Konovalov
  2018-05-25 17:21 ` [PATCH v3 1/6] arm64: add type casts to untagged_addr macro Andrey Konovalov
  2018-05-25 17:21 ` [PATCH v3 2/6] uaccess: add untagged_addr definition for other arches Andrey Konovalov
@ 2018-05-25 17:21 ` Andrey Konovalov
  2018-05-25 17:21 ` [PATCH v3 4/6] mm, arm64: untag user addresses in mm/gup.c Andrey Konovalov
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Andrey Konovalov @ 2018-05-25 17:21 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Mark Rutland, Robin Murphy,
	Al Viro, Andrey Konovalov, Kees Cook, Kate Stewart,
	Greg Kroah-Hartman, Andrew Morton, Ingo Molnar,
	Kirill A . Shutemov, linux-arm-kernel, linux-doc, linux-mm,
	linux-arch, linux-kernel
  Cc: Dmitry Vyukov, Kostya Serebryany, Evgeniy Stepanov, Lee Smith,
	Ramana Radhakrishnan, Jacob Bramley, Ruben Ayrapetyan,
	Chintan Pandya

copy_from_user (and a few other similar functions) are used to copy data
from user memory into the kernel memory or vice versa. Since a user can
provided a tagged pointer to one of the syscalls that use copy_from_user,
we need to correctly handle such pointers.

Do this by untagging user pointers in access_ok and in __uaccess_mask_ptr,
before performing access validity checks.

Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
---
 arch/arm64/include/asm/uaccess.h | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
index 2d6451cbaa86..fa7318d3d7d5 100644
--- a/arch/arm64/include/asm/uaccess.h
+++ b/arch/arm64/include/asm/uaccess.h
@@ -105,7 +105,8 @@ static inline unsigned long __range_ok(const void __user *addr, unsigned long si
 #define untagged_addr(addr)		\
 	((__typeof__(addr))sign_extend64((__u64)(addr), 55))
 
-#define access_ok(type, addr, size)	__range_ok(addr, size)
+#define access_ok(type, addr, size)	\
+	__range_ok(untagged_addr(addr), size)
 #define user_addr_max			get_fs
 
 #define _ASM_EXTABLE(from, to)						\
@@ -237,7 +238,8 @@ static inline void uaccess_enable_not_uao(void)
 
 /*
  * Sanitise a uaccess pointer such that it becomes NULL if above the
- * current addr_limit.
+ * current addr_limit. In case the pointer is tagged (has the top byte set),
+ * untag the pointer before checking.
  */
 #define uaccess_mask_ptr(ptr) (__typeof__(ptr))__uaccess_mask_ptr(ptr)
 static inline void __user *__uaccess_mask_ptr(const void __user *ptr)
@@ -245,10 +247,11 @@ static inline void __user *__uaccess_mask_ptr(const void __user *ptr)
 	void __user *safe_ptr;
 
 	asm volatile(
-	"	bics	xzr, %1, %2\n"
+	"	bics	xzr, %3, %2\n"
 	"	csel	%0, %1, xzr, eq\n"
 	: "=&r" (safe_ptr)
-	: "r" (ptr), "r" (current_thread_info()->addr_limit)
+	: "r" (ptr), "r" (current_thread_info()->addr_limit),
+	  "r" (untagged_addr(ptr))
 	: "cc");
 
 	csdb();
-- 
2.17.0.921.gf22659ad46-goog

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v3 4/6] mm, arm64: untag user addresses in mm/gup.c
  2018-05-25 17:21 [PATCH v3 0/6] arm64: untag user pointers passed to the kernel Andrey Konovalov
                   ` (2 preceding siblings ...)
  2018-05-25 17:21 ` [PATCH v3 3/6] arm64: untag user addresses in access_ok and __uaccess_mask_ptr Andrey Konovalov
@ 2018-05-25 17:21 ` Andrey Konovalov
  2018-05-25 17:21 ` [PATCH v3 5/6] lib, arm64: untag addrs passed to strncpy_from_user and strnlen_user Andrey Konovalov
  2018-05-25 17:21 ` [PATCH v3 6/6] arm64: update Documentation/arm64/tagged-pointers.txt Andrey Konovalov
  5 siblings, 0 replies; 7+ messages in thread
From: Andrey Konovalov @ 2018-05-25 17:21 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Mark Rutland, Robin Murphy,
	Al Viro, Andrey Konovalov, Kees Cook, Kate Stewart,
	Greg Kroah-Hartman, Andrew Morton, Ingo Molnar,
	Kirill A . Shutemov, linux-arm-kernel, linux-doc, linux-mm,
	linux-arch, linux-kernel
  Cc: Dmitry Vyukov, Kostya Serebryany, Evgeniy Stepanov, Lee Smith,
	Ramana Radhakrishnan, Jacob Bramley, Ruben Ayrapetyan,
	Chintan Pandya

mm/gup.c provides a kernel interface that accepts user addresses and
manipulates user pages directly (for example get_user_pages, that is used
by the futex syscall). Here we also need to handle the case of tagged user
pointers.

Add untagging to gup.c functions that use user pointers for vma lookup.

Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
---
 mm/gup.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/mm/gup.c b/mm/gup.c
index 541904a7c60f..5d0e9715bab7 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -650,6 +650,8 @@ static long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
 	if (!nr_pages)
 		return 0;
 
+	start = untagged_addr(start);
+
 	VM_BUG_ON(!!pages != !!(gup_flags & FOLL_GET));
 
 	/*
@@ -804,6 +806,8 @@ int fixup_user_fault(struct task_struct *tsk, struct mm_struct *mm,
 	struct vm_area_struct *vma;
 	int ret, major = 0;
 
+	address = untagged_addr(address);
+
 	if (unlocked)
 		fault_flags |= FAULT_FLAG_ALLOW_RETRY;
 
-- 
2.17.0.921.gf22659ad46-goog

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v3 5/6] lib, arm64: untag addrs passed to strncpy_from_user and strnlen_user
  2018-05-25 17:21 [PATCH v3 0/6] arm64: untag user pointers passed to the kernel Andrey Konovalov
                   ` (3 preceding siblings ...)
  2018-05-25 17:21 ` [PATCH v3 4/6] mm, arm64: untag user addresses in mm/gup.c Andrey Konovalov
@ 2018-05-25 17:21 ` Andrey Konovalov
  2018-05-25 17:21 ` [PATCH v3 6/6] arm64: update Documentation/arm64/tagged-pointers.txt Andrey Konovalov
  5 siblings, 0 replies; 7+ messages in thread
From: Andrey Konovalov @ 2018-05-25 17:21 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Mark Rutland, Robin Murphy,
	Al Viro, Andrey Konovalov, Kees Cook, Kate Stewart,
	Greg Kroah-Hartman, Andrew Morton, Ingo Molnar,
	Kirill A . Shutemov, linux-arm-kernel, linux-doc, linux-mm,
	linux-arch, linux-kernel
  Cc: Dmitry Vyukov, Kostya Serebryany, Evgeniy Stepanov, Lee Smith,
	Ramana Radhakrishnan, Jacob Bramley, Ruben Ayrapetyan,
	Chintan Pandya

strncpy_from_user and strnlen_user accept user addresses as arguments, and
do not go through the same path as copy_from_user and others, so here we
need to handle the case of tagged user addresses separately.

Untag user pointers passed to these functions.

Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
---
 lib/strncpy_from_user.c | 2 ++
 lib/strnlen_user.c      | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/lib/strncpy_from_user.c b/lib/strncpy_from_user.c
index b53e1b5d80f4..97467cd2bc59 100644
--- a/lib/strncpy_from_user.c
+++ b/lib/strncpy_from_user.c
@@ -106,6 +106,8 @@ long strncpy_from_user(char *dst, const char __user *src, long count)
 	if (unlikely(count <= 0))
 		return 0;
 
+	src = untagged_addr(src);
+
 	max_addr = user_addr_max();
 	src_addr = (unsigned long)src;
 	if (likely(src_addr < max_addr)) {
diff --git a/lib/strnlen_user.c b/lib/strnlen_user.c
index 60d0bbda8f5e..8b5f56466e00 100644
--- a/lib/strnlen_user.c
+++ b/lib/strnlen_user.c
@@ -108,6 +108,8 @@ long strnlen_user(const char __user *str, long count)
 	if (unlikely(count <= 0))
 		return 0;
 
+	str = untagged_addr(str);
+
 	max_addr = user_addr_max();
 	src_addr = (unsigned long)str;
 	if (likely(src_addr < max_addr)) {
-- 
2.17.0.921.gf22659ad46-goog

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v3 6/6] arm64: update Documentation/arm64/tagged-pointers.txt
  2018-05-25 17:21 [PATCH v3 0/6] arm64: untag user pointers passed to the kernel Andrey Konovalov
                   ` (4 preceding siblings ...)
  2018-05-25 17:21 ` [PATCH v3 5/6] lib, arm64: untag addrs passed to strncpy_from_user and strnlen_user Andrey Konovalov
@ 2018-05-25 17:21 ` Andrey Konovalov
  5 siblings, 0 replies; 7+ messages in thread
From: Andrey Konovalov @ 2018-05-25 17:21 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Mark Rutland, Robin Murphy,
	Al Viro, Andrey Konovalov, Kees Cook, Kate Stewart,
	Greg Kroah-Hartman, Andrew Morton, Ingo Molnar,
	Kirill A . Shutemov, linux-arm-kernel, linux-doc, linux-mm,
	linux-arch, linux-kernel
  Cc: Dmitry Vyukov, Kostya Serebryany, Evgeniy Stepanov, Lee Smith,
	Ramana Radhakrishnan, Jacob Bramley, Ruben Ayrapetyan,
	Chintan Pandya

Add a note that work on passing tagged user pointers to the kernel via
syscalls has started, but might not be complete yet.

Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
---
 Documentation/arm64/tagged-pointers.txt | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/Documentation/arm64/tagged-pointers.txt b/Documentation/arm64/tagged-pointers.txt
index a25a99e82bb1..361481283f00 100644
--- a/Documentation/arm64/tagged-pointers.txt
+++ b/Documentation/arm64/tagged-pointers.txt
@@ -35,8 +35,9 @@ Using non-zero address tags in any of these locations may result in an
 error code being returned, a (fatal) signal being raised, or other modes
 of failure.
 
-For these reasons, passing non-zero address tags to the kernel via
-system calls is forbidden, and using a non-zero address tag for sp is
+Some initial work for supporting non-zero address tags passed to the
+kernel via system calls has been done, but the kernel doesn't provide
+any guarantees at this point. Using a non-zero address tag for sp is
 strongly discouraged.
 
 Programs maintaining a frame pointer and frame records that use non-zero
-- 
2.17.0.921.gf22659ad46-goog

^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2018-05-25 17:22 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-05-25 17:21 [PATCH v3 0/6] arm64: untag user pointers passed to the kernel Andrey Konovalov
2018-05-25 17:21 ` [PATCH v3 1/6] arm64: add type casts to untagged_addr macro Andrey Konovalov
2018-05-25 17:21 ` [PATCH v3 2/6] uaccess: add untagged_addr definition for other arches Andrey Konovalov
2018-05-25 17:21 ` [PATCH v3 3/6] arm64: untag user addresses in access_ok and __uaccess_mask_ptr Andrey Konovalov
2018-05-25 17:21 ` [PATCH v3 4/6] mm, arm64: untag user addresses in mm/gup.c Andrey Konovalov
2018-05-25 17:21 ` [PATCH v3 5/6] lib, arm64: untag addrs passed to strncpy_from_user and strnlen_user Andrey Konovalov
2018-05-25 17:21 ` [PATCH v3 6/6] arm64: update Documentation/arm64/tagged-pointers.txt Andrey Konovalov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).