From: Thomas Garnier <hidden> Date: 2017-03-09 01:24:53
This patch ensures a syscall does not return to user-mode with a kernel
address limit. If that happened, a process can corrupt kernel-mode
memory and elevate privileges.
For example, it would mitigation this bug:
- https://bugs.chromium.org/p/project-zero/issues/detail?id=990
If the CONFIG_BUG_ON_DATA_CORRUPTION option is enabled, an incorrect
state will result in a BUG_ON.
The CONFIG_ARCH_NO_SYSCALL_VERIFY_PRE_USERMODE_STATE option is also
added so each architecture can optimize this change.
Signed-off-by: Thomas Garnier <redacted>
---
Based on next-20170308
---
include/linux/syscalls.h | 19 +++++++++++++++++++
init/Kconfig | 7 +++++++
kernel/sys.c | 8 ++++++++
3 files changed, 34 insertions(+)
@@ -1929,6 +1929,13 @@ config PROFILINGconfigTRACEPOINTSbool+#+# Set by each architecture that want to optimize how verify_pre_usermode_state+# is called.+#+configARCH_NO_SYSCALL_VERIFY_PRE_USERMODE_STATE+bool+source"arch/Kconfig"endmenu# General setup
@@ -2459,3 +2459,11 @@ COMPAT_SYSCALL_DEFINE1(sysinfo, struct compat_sysinfo __user *, info)return0;}#endif /* CONFIG_COMPAT */++/* Called before coming back to user-mode */+asmlinkagevoidverify_pre_usermode_state(void)+{+if(CHECK_DATA_CORRUPTION(!segment_eq(get_fs(),USER_DS),+"incorrect get_fs() on user-mode return"))+set_fs(USER_DS);+}
@@ -829,17 +829,6 @@ static inline void spin_lock_prefetch(const void *x)#define KSTK_ESP(task) (task_pt_regs(task)->sp)#else-/*-*Userspaceprocesssize.47bitsminusoneguardpage.Theguard-*pageisnecessaryonIntelCPUs:ifaSYSCALLinstructionisat-*thehighestpossiblecanonicaluserspaceaddress,thenthat-*syscallwillenterthekernelwithanon-canonicalreturn-*address,andSYSRETwillexplodedangerously.Weavoidthis-*particularproblembypreventinganythingfrombeingmapped-*atthemaximumcanonicaladdress.-*/-#define TASK_SIZE_MAX ((1UL << 47) - PAGE_SIZE)-/* This decides where the kernel will search for a free chunk of vm*spaceduringmmap's.*/
From: Thomas Garnier <hidden> Date: 2017-03-09 01:24:55
Implement specific usage of verify_pre_usermode_state for user-mode
returns for arm.
---
Based on next-20170308
---
arch/arm/Kconfig | 1 +
arch/arm/kernel/entry-common.S | 21 +++++++++++++++++++++
2 files changed, 22 insertions(+)
From: Thomas Garnier <hidden> Date: 2017-03-09 01:24:56
Implement specific usage of verify_pre_usermode_state for user-mode
returns for arm64.
---
Based on next-20170308
---
arch/arm64/Kconfig | 1 +
arch/arm64/kernel/entry.S | 15 +++++++++++++++
2 files changed, 16 insertions(+)
... and then you could slim down the ifdeffery a bit:
static inline bool has_user_ds(void) {
bool ret = false;
#ifndef CONFIG_ARCH_NO_SYSCALL_VERIFY_PRE_USERMODE_STATE
ret = segment_eq(get_fs(), USER_DS);
/* Prevent re-ordering the call. */
barrier();
#endif
return ret;
}
--
Regards/Gruss,
Boris.
Good mailing practices for 400: avoid top-posting and trim the reply.
This patch ensures a syscall does not return to user-mode with a kernel
address limit. If that happened, a process can corrupt kernel-mode
memory and elevate privileges.
I like the patch set.
a side note (perhaps a bit irrelevant), the WARN backtrace does not
really tell more than "incorrect get_fs() on user-mode return" message
does
incorrect get_fs() on user-mode return
------------[ cut here ]------------
kernel BUG at kernel/sys.c:2467!
invalid opcode: 0000 [#1] PREEMPT SMP
Modules linked in: FOO
CPU: 2 PID: 355 Comm: BAR
Hardware name: BUZ
task: ffff8801329f4e00 task.stack: ffffc900005d8000
RIP: 0010:verify_pre_usermode_state+0x31/0x34
RSP: 0018:ffffc900005dbf48 EFLAGS: 00010096
RAX: 0000000000000026 RBX: 0000000000000002 RCX: 0000000000000001
RDX: 0000000000000046 RSI: ffff880130cead88 RDI: ffffffff81095594
RBP: ffffc900005dbf48 R08: 0000000000000001 R09: 0000000000000001
R10: ffffc900005dbd58 R11: ffff8801329f4e00 R12: 0000000000000002
R13: 0000000000000001 R14: 00007fb6c6a7b5e0 R15: 0000000000000002
FS: 00007fb6c70d3b40(0000) GS:ffff880137d00000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007ffd9d94f8f8 CR3: 00000001295b2000 CR4: 00000000000006e0
Call Trace:
entry_SYSCALL_64_fastpath+0x3a/0xb2
RIP: 0033:0x7fb6c67ba3c0
RSP: 002b:00007ffd9d94f5c8 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
RAX: 0000000000000002 RBX: 0000000000000000 RCX: 00007fb6c67ba3c0
RDX: 0000000000000002 RSI: 0000000000ba7310 RDI: 0000000000000001
RBP: 0000000000000001 R08: 00007fb6c6a7c740 R09: 00007fb6c70d3b40
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000
Code: 48 8b 14 25 40 c5 00 00 48 b8 00 f0 ff ff ff 7f 00 00 48 39 82 28 11 00 00 74 12 55 48 c7 c7 9b f5 78 81 48 89 e5 e8 14 19 0b 00 <0f> 0b c3 66 66 66 66 90 55 48 89 e5 53 48 8b 47 50 48 89 fb 48
may be some day someone would be interested in something like
"incorrect get_fs() on user-mode return from %pS"
and set_fs() would save _RET_IP_.
just a side note.
-ss
Hi,
On Wed, Mar 08, 2017 at 05:24:53PM -0800, Thomas Garnier wrote:
This patch ensures a syscall does not return to user-mode with a kernel
address limit. If that happened, a process can corrupt kernel-mode
memory and elevate privileges.
For example, it would mitigation this bug:
- https://bugs.chromium.org/p/project-zero/issues/detail?id=990
If the CONFIG_BUG_ON_DATA_CORRUPTION option is enabled, an incorrect
state will result in a BUG_ON.
The CONFIG_ARCH_NO_SYSCALL_VERIFY_PRE_USERMODE_STATE option is also
added so each architecture can optimize this change.
What ordering are we trying to ensure, that isn't otherwise given?
We expect get_fs() and set_fs() to be ordered w.r.t. each other and
w.r.t. uaccess uses, or we'd need barriers all over the place.
Given that, I can't see why we need a barrier here. So this needs a
better comment, at least.
It would be simpler to wrap the call entirely, e.g. have:
#ifdef CONFIG_WHATEVER
static inline void verify_pre_usermode_state(void)
{
if (segment_eq(get_fs(), USER_DS))
__verify_pre_usermode_state();
}
#else
static inline void verify_pre_usermode_state(void) { }
#endif
quoted hunk
@@ -199,7 +215,10 @@ extern struct trace_event_functions exit_syscall_print_funcs; asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \ asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ { \+ bool user_caller = has_user_ds(); \ long ret = SYSC##name(__MAP(x,__SC_CAST,__VA_ARGS__)); \+ if (user_caller) \+ verify_pre_usermode_state(); \
... then we can unconditionally use verify_pre_usermode_state() here ...
On Wed, Mar 08, 2017 at 05:24:56PM -0800, Thomas Garnier wrote:
quoted hunk
Implement specific usage of verify_pre_usermode_state for user-mode
returns for arm64.
---
Based on next-20170308
---
arch/arm64/Kconfig | 1 +
arch/arm64/kernel/entry.S | 15 +++++++++++++++
2 files changed, 16 insertions(+)
We generally stick to lower case for the arm64 assembly macros. If we
need this, we should stick to the existing convention.
+/* Similar to set_fs(USER_DS) in verify_pre_usermode_state without a warning. */
+.macro VERIFY_PRE_USERMODE_STATE
+ mov x1, #TASK_SIZE_64
+ str x1, [tsk, #TSK_TI_ADDR_LIMIT]
+.endm
We need arm64's set_fs() to configure UAO, too, so this is much weaker
than set_fs(), and will leave __{get,put}_user and
__copy_{to,from}_user() able to access kernel memory.
We don't currently have an asm helper to clear UAO, and unconditionally
poking that on exception return is liable to be somewhat expensive.
Also, given we're only trying to catch this in syscalls, I'm afraid I
don't see what we gain by doing this in the entry assembly.
Thanks,
Mark.
quoted hunk
+#endif
+
+
/*
* This is the fast syscall return path. We do as little as possible here,
* and this includes saving x0 back into the kernel stack.
From: Christian Borntraeger <hidden> Date: 2017-03-09 12:32:46
On 03/09/2017 02:24 AM, Thomas Garnier wrote:
quoted hunk
This patch ensures a syscall does not return to user-mode with a kernel
address limit. If that happened, a process can corrupt kernel-mode
memory and elevate privileges.
For example, it would mitigation this bug:
- https://bugs.chromium.org/p/project-zero/issues/detail?id=990
If the CONFIG_BUG_ON_DATA_CORRUPTION option is enabled, an incorrect
state will result in a BUG_ON.
The CONFIG_ARCH_NO_SYSCALL_VERIFY_PRE_USERMODE_STATE option is also
added so each architecture can optimize this change.
Signed-off-by: Thomas Garnier <redacted>
---
Based on next-20170308
---
include/linux/syscalls.h | 19 +++++++++++++++++++
init/Kconfig | 7 +++++++
kernel/sys.c | 8 ++++++++
3 files changed, 34 insertions(+)
Can you please disable that for s390? (e.g. by setting
CONFIG_ARCH_NO_SYSCALL_VERIFY_PRE_USERMODE_STATE for s390)
We have a separate address space for kernel/user so the logic will
be slightly different and is already handled in
commit b5a882fcf146c87cb6b67c6df353e1c042b8773d
Author: Heiko Carstens [off-list ref]
Date: Fri Feb 17 08:13:28 2017 +0100
s390: restore address space when returning to user space
@@ -1929,6 +1929,13 @@ config PROFILINGconfigTRACEPOINTSbool+#+# Set by each architecture that want to optimize how verify_pre_usermode_state+# is called.+#+configARCH_NO_SYSCALL_VERIFY_PRE_USERMODE_STATE+bool+source"arch/Kconfig"endmenu# General setup
@@ -2459,3 +2459,11 @@ COMPAT_SYSCALL_DEFINE1(sysinfo, struct compat_sysinfo __user *, info)return0;}#endif /* CONFIG_COMPAT */++/* Called before coming back to user-mode */+asmlinkagevoidverify_pre_usermode_state(void)+{+if(CHECK_DATA_CORRUPTION(!segment_eq(get_fs(),USER_DS),+"incorrect get_fs() on user-mode return"))+set_fs(USER_DS);+}
From: linux@armlinux.org.uk (Russell King - ARM Linux) Date: 2017-03-09 13:44:56
On Thu, Mar 09, 2017 at 12:09:55PM +0000, Mark Rutland wrote:
Hi,
On Wed, Mar 08, 2017 at 05:24:53PM -0800, Thomas Garnier wrote:
quoted
This patch ensures a syscall does not return to user-mode with a kernel
address limit. If that happened, a process can corrupt kernel-mode
memory and elevate privileges.
For example, it would mitigation this bug:
- https://bugs.chromium.org/p/project-zero/issues/detail?id=990
If the CONFIG_BUG_ON_DATA_CORRUPTION option is enabled, an incorrect
state will result in a BUG_ON.
The CONFIG_ARCH_NO_SYSCALL_VERIFY_PRE_USERMODE_STATE option is also
added so each architecture can optimize this change.
What ordering are we trying to ensure, that isn't otherwise given?
We expect get_fs() and set_fs() to be ordered w.r.t. each other and
w.r.t. uaccess uses, or we'd need barriers all over the place.
Given that, I can't see why we need a barrier here. So this needs a
better comment, at least.
It would be simpler to wrap the call entirely, e.g. have:
#ifdef CONFIG_WHATEVER
static inline void verify_pre_usermode_state(void)
{
if (segment_eq(get_fs(), USER_DS))
__verify_pre_usermode_state();
}
#else
static inline void verify_pre_usermode_state(void) { }
#endif
That's utterly pointless - you've missed a detail.
quoted
@@ -199,7 +215,10 @@ extern struct trace_event_functions exit_syscall_print_funcs; asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \ asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ { \+ bool user_caller = has_user_ds(); \ long ret = SYSC##name(__MAP(x,__SC_CAST,__VA_ARGS__)); \+ if (user_caller) \+ verify_pre_usermode_state(); \
... then we can unconditionally use verify_pre_usermode_state() here ...
Look at this closely. has_user_ds() is called _before_ the syscall code
is invoked. It's checking what conditions the syscall was entered from.
If the syscall was entered with the user segment selected, then we run
a check on the system state _after_ the syscall code has returned.
Putting both after the syscall code has returned is completely pointless -
it turns it into this code:
if (segment_eq(get_fs(), USER_DS))
if (CHECK_DATA_CORRUPTION(!segment_eq(get_fs(), USER_DS),
"incorrect get_fs() on user-mode return"))
set_fs(USER_DS);
which is obviously bogus (it'll never fire.)
--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
On Thu, Mar 09, 2017 at 01:44:56PM +0000, Russell King - ARM Linux wrote:
On Thu, Mar 09, 2017 at 12:09:55PM +0000, Mark Rutland wrote:
quoted
On Wed, Mar 08, 2017 at 05:24:53PM -0800, Thomas Garnier wrote:
quoted
It would be simpler to wrap the call entirely, e.g. have:
#ifdef CONFIG_WHATEVER
static inline void verify_pre_usermode_state(void)
{
if (segment_eq(get_fs(), USER_DS))
__verify_pre_usermode_state();
}
#else
static inline void verify_pre_usermode_state(void) { }
#endif
That's utterly pointless - you've missed a detail.
quoted
quoted
@@ -199,7 +215,10 @@ extern struct trace_event_functions exit_syscall_print_funcs; asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \ asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ { \+ bool user_caller = has_user_ds(); \ long ret = SYSC##name(__MAP(x,__SC_CAST,__VA_ARGS__)); \+ if (user_caller) \+ verify_pre_usermode_state(); \
... then we can unconditionally use verify_pre_usermode_state() here ...
Look at this closely. has_user_ds() is called _before_ the syscall code
is invoked. It's checking what conditions the syscall was entered from.
If the syscall was entered with the user segment selected, then we run
a check on the system state _after_ the syscall code has returned.
Indeed; I clearly did not consider this correctly.
Sorry for the noise.
Thanks,
Mark.
... and then you could slim down the ifdeffery a bit:
static inline bool has_user_ds(void) {
bool ret = false;
#ifndef CONFIG_ARCH_NO_SYSCALL_VERIFY_PRE_USERMODE_STATE
ret = segment_eq(get_fs(), USER_DS);
/* Prevent re-ordering the call. */
barrier();
#endif
return ret;
}
I agree, cleaner. I will look to do this change on next iteration.
--
Regards/Gruss,
Boris.
Good mailing practices for 400: avoid top-posting and trim the reply.
From: Thomas Garnier <hidden> Date: 2017-03-09 15:52:30
On Thu, Mar 9, 2017 at 4:09 AM, Mark Rutland [off-list ref] wrote:
Hi,
On Wed, Mar 08, 2017 at 05:24:53PM -0800, Thomas Garnier wrote:
quoted
This patch ensures a syscall does not return to user-mode with a kernel
address limit. If that happened, a process can corrupt kernel-mode
memory and elevate privileges.
For example, it would mitigation this bug:
- https://bugs.chromium.org/p/project-zero/issues/detail?id=990
If the CONFIG_BUG_ON_DATA_CORRUPTION option is enabled, an incorrect
state will result in a BUG_ON.
The CONFIG_ARCH_NO_SYSCALL_VERIFY_PRE_USERMODE_STATE option is also
added so each architecture can optimize this change.
What ordering are we trying to ensure, that isn't otherwise given?
We expect get_fs() and set_fs() to be ordered w.r.t. each other and
w.r.t. uaccess uses, or we'd need barriers all over the place.
Given that, I can't see why we need a barrier here. So this needs a
better comment, at least.
I was half sure of that so that's why I added the barrier. If it is
not needed then I can remove it. Thanks!
It would be simpler to wrap the call entirely, e.g. have:
#ifdef CONFIG_WHATEVER
static inline void verify_pre_usermode_state(void)
{
if (segment_eq(get_fs(), USER_DS))
__verify_pre_usermode_state();
}
#else
static inline void verify_pre_usermode_state(void) { }
#endif
quoted
@@ -199,7 +215,10 @@ extern struct trace_event_functions exit_syscall_print_funcs; asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \ asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ { \+ bool user_caller = has_user_ds(); \ long ret = SYSC##name(__MAP(x,__SC_CAST,__VA_ARGS__)); \+ if (user_caller) \+ verify_pre_usermode_state(); \
... then we can unconditionally use verify_pre_usermode_state() here ...
Not sure I understood that point. The goal is to see if get_fs was
changed, that's why I check before the syscall and I want to ensure
the call is not shuffled after the syscall, therefore the original
barrier.
From: Thomas Garnier <hidden> Date: 2017-03-09 15:53:54
On Thu, Mar 9, 2017 at 4:32 AM, Christian Borntraeger [off-list ref] wrote:
Can you please disable that for s390? (e.g. by setting
CONFIG_ARCH_NO_SYSCALL_VERIFY_PRE_USERMODE_STATE for s390)
We have a separate address space for kernel/user so the logic will
be slightly different and is already handled in
commit b5a882fcf146c87cb6b67c6df353e1c042b8773d
Author: Heiko Carstens [off-list ref]
Date: Fri Feb 17 08:13:28 2017 +0100
s390: restore address space when returning to user space
No problem, I will add it on the next iteration of this change.
--
Thomas
From: Thomas Garnier <hidden> Date: 2017-03-09 15:54:40
On Thu, Mar 9, 2017 at 7:21 AM, Mark Rutland [off-list ref] wrote:
On Thu, Mar 09, 2017 at 01:44:56PM +0000, Russell King - ARM Linux wrote:
quoted
On Thu, Mar 09, 2017 at 12:09:55PM +0000, Mark Rutland wrote:
quoted
On Wed, Mar 08, 2017 at 05:24:53PM -0800, Thomas Garnier wrote:
quoted
quoted
It would be simpler to wrap the call entirely, e.g. have:
#ifdef CONFIG_WHATEVER
static inline void verify_pre_usermode_state(void)
{
if (segment_eq(get_fs(), USER_DS))
__verify_pre_usermode_state();
}
#else
static inline void verify_pre_usermode_state(void) { }
#endif
That's utterly pointless - you've missed a detail.
quoted
quoted
@@ -199,7 +215,10 @@ extern struct trace_event_functions exit_syscall_print_funcs; asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \ asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ { \+ bool user_caller = has_user_ds(); \ long ret = SYSC##name(__MAP(x,__SC_CAST,__VA_ARGS__)); \+ if (user_caller) \+ verify_pre_usermode_state(); \
... then we can unconditionally use verify_pre_usermode_state() here ...
Look at this closely. has_user_ds() is called _before_ the syscall code
is invoked. It's checking what conditions the syscall was entered from.
If the syscall was entered with the user segment selected, then we run
a check on the system state _after_ the syscall code has returned.
Indeed; I clearly did not consider this correctly.
Sorry for the noise.
No problem, I missed that reply so discard my question on the email
few seconds ago.
From: Thomas Garnier <hidden> Date: 2017-03-09 15:56:49
On Thu, Mar 9, 2017 at 4:23 AM, Mark Rutland [off-list ref] wrote:
We generally stick to lower case for the arm64 assembly macros. If we
need this, we should stick to the existing convention.
quoted
+/* Similar to set_fs(USER_DS) in verify_pre_usermode_state without a warning. */
+.macro VERIFY_PRE_USERMODE_STATE
+ mov x1, #TASK_SIZE_64
+ str x1, [tsk, #TSK_TI_ADDR_LIMIT]
+.endm
We need arm64's set_fs() to configure UAO, too, so this is much weaker
than set_fs(), and will leave __{get,put}_user and
__copy_{to,from}_user() able to access kernel memory.
We don't currently have an asm helper to clear UAO, and unconditionally
poking that on exception return is liable to be somewhat expensive.
Also, given we're only trying to catch this in syscalls, I'm afraid I
don't see what we gain by doing this in the entry assembly.
I optimized all architectures from the arm (32-bit) discussion. I will
come back to a simple bl to the verify function. Thanks!
--
Thomas
On Thu, Mar 09, 2017 at 07:56:49AM -0800, Thomas Garnier wrote:
On Thu, Mar 9, 2017 at 4:23 AM, Mark Rutland [off-list ref] wrote:
quoted
We generally stick to lower case for the arm64 assembly macros. If we
need this, we should stick to the existing convention.
quoted
+/* Similar to set_fs(USER_DS) in verify_pre_usermode_state without a warning. */
+.macro VERIFY_PRE_USERMODE_STATE
+ mov x1, #TASK_SIZE_64
+ str x1, [tsk, #TSK_TI_ADDR_LIMIT]
+.endm
We need arm64's set_fs() to configure UAO, too, so this is much weaker
than set_fs(), and will leave __{get,put}_user and
__copy_{to,from}_user() able to access kernel memory.
We don't currently have an asm helper to clear UAO, and unconditionally
poking that on exception return is liable to be somewhat expensive.
Also, given we're only trying to catch this in syscalls, I'm afraid I
don't see what we gain by doing this in the entry assembly.
I optimized all architectures from the arm (32-bit) discussion. I will
come back to a simple bl to the verify function. Thanks!
What I was trying to ask was do we need to touch the assembly at all
here?
Are we trying to protect the non-syscall cases by doing this in
assembly? If so, it'd be worth calling out in the commit message.
If so, we could add the necessary helper to clear UAO.
If not, doing this in the entry assembly only saves the small overhead
of reading and comparing the addr_limit for in-kernel use of the
syscalls (e.g. in the compat wrappers), and we may as well rely on the
common !ARCH_NO_SYSCALL_VERIFY_PRE_USERMODE_STATE implementation.
Thanks,
Mark.
From: Thomas Garnier <hidden> Date: 2017-03-09 16:19:31
On Thu, Mar 9, 2017 at 8:05 AM, Mark Rutland [off-list ref] wrote:
On Thu, Mar 09, 2017 at 07:56:49AM -0800, Thomas Garnier wrote:
quoted
On Thu, Mar 9, 2017 at 4:23 AM, Mark Rutland [off-list ref] wrote:
quoted
We generally stick to lower case for the arm64 assembly macros. If we
need this, we should stick to the existing convention.
quoted
+/* Similar to set_fs(USER_DS) in verify_pre_usermode_state without a warning. */
+.macro VERIFY_PRE_USERMODE_STATE
+ mov x1, #TASK_SIZE_64
+ str x1, [tsk, #TSK_TI_ADDR_LIMIT]
+.endm
We need arm64's set_fs() to configure UAO, too, so this is much weaker
than set_fs(), and will leave __{get,put}_user and
__copy_{to,from}_user() able to access kernel memory.
We don't currently have an asm helper to clear UAO, and unconditionally
poking that on exception return is liable to be somewhat expensive.
Also, given we're only trying to catch this in syscalls, I'm afraid I
don't see what we gain by doing this in the entry assembly.
I optimized all architectures from the arm (32-bit) discussion. I will
come back to a simple bl to the verify function. Thanks!
What I was trying to ask was do we need to touch the assembly at all
here?
You don't but he generic solution add code to every single syscall.
Are we trying to protect the non-syscall cases by doing this in
assembly? If so, it'd be worth calling out in the commit message.
It is an added benefit but not required.
If so, we could add the necessary helper to clear UAO.
I can look at set_fs and fix it on the next iteraiton.
If not, doing this in the entry assembly only saves the small overhead
of reading and comparing the addr_limit for in-kernel use of the
syscalls (e.g. in the compat wrappers), and we may as well rely on the
common !ARCH_NO_SYSCALL_VERIFY_PRE_USERMODE_STATE implementation.
You also don't have the code added for each syscall and a call.
From: linux@armlinux.org.uk (Russell King - ARM Linux) Date: 2017-03-09 16:26:13
On Thu, Mar 09, 2017 at 07:56:49AM -0800, Thomas Garnier wrote:
On Thu, Mar 9, 2017 at 4:23 AM, Mark Rutland [off-list ref] wrote:
quoted
We generally stick to lower case for the arm64 assembly macros. If we
need this, we should stick to the existing convention.
quoted
+/* Similar to set_fs(USER_DS) in verify_pre_usermode_state without a warning. */
+.macro VERIFY_PRE_USERMODE_STATE
+ mov x1, #TASK_SIZE_64
+ str x1, [tsk, #TSK_TI_ADDR_LIMIT]
+.endm
We need arm64's set_fs() to configure UAO, too, so this is much weaker
than set_fs(), and will leave __{get,put}_user and
__copy_{to,from}_user() able to access kernel memory.
We don't currently have an asm helper to clear UAO, and unconditionally
poking that on exception return is liable to be somewhat expensive.
Also, given we're only trying to catch this in syscalls, I'm afraid I
don't see what we gain by doing this in the entry assembly.
I optimized all architectures from the arm (32-bit) discussion. I will
come back to a simple bl to the verify function. Thanks!
I wouldn't call what you've done on ARM an "optimisation", because my
comment about making the fast path worthless still stands.
--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
From: Thomas Garnier <hidden> Date: 2017-03-09 16:35:30
On Thu, Mar 9, 2017 at 8:26 AM, Russell King - ARM Linux
[off-list ref] wrote:
On Thu, Mar 09, 2017 at 07:56:49AM -0800, Thomas Garnier wrote:
quoted
On Thu, Mar 9, 2017 at 4:23 AM, Mark Rutland [off-list ref] wrote:
quoted
We generally stick to lower case for the arm64 assembly macros. If we
need this, we should stick to the existing convention.
quoted
+/* Similar to set_fs(USER_DS) in verify_pre_usermode_state without a warning. */
+.macro VERIFY_PRE_USERMODE_STATE
+ mov x1, #TASK_SIZE_64
+ str x1, [tsk, #TSK_TI_ADDR_LIMIT]
+.endm
We need arm64's set_fs() to configure UAO, too, so this is much weaker
than set_fs(), and will leave __{get,put}_user and
__copy_{to,from}_user() able to access kernel memory.
We don't currently have an asm helper to clear UAO, and unconditionally
poking that on exception return is liable to be somewhat expensive.
Also, given we're only trying to catch this in syscalls, I'm afraid I
don't see what we gain by doing this in the entry assembly.
I optimized all architectures from the arm (32-bit) discussion. I will
come back to a simple bl to the verify function. Thanks!
I wouldn't call what you've done on ARM an "optimisation", because my
comment about making the fast path worthless still stands.
From: linux@armlinux.org.uk (Russell King - ARM Linux) Date: 2017-03-09 17:05:53
On Thu, Mar 09, 2017 at 08:35:30AM -0800, Thomas Garnier wrote:
On Thu, Mar 9, 2017 at 8:26 AM, Russell King - ARM Linux
[off-list ref] wrote:
quoted
I wouldn't call what you've done on ARM an "optimisation", because my
comment about making the fast path worthless still stands.
Why does it still stands on the latest proposal?
It's still having to needlessly save stuff when there's nothing wrong.
Remember, syscalls are a fast path, so the minimum we can do is good.
Calling into C functions is not ideal, because they will tend to be
_very_ expensive compared to hand crafted assembly, especially for
something like this.
It's possible to check the address limit in just three instructions,
which is way less than will be incurred by calling a C function.
Note: This patch is completely untested.
arch/arm/kernel/entry-common.S | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
... and then you could slim down the ifdeffery a bit:
static inline bool has_user_ds(void) {
bool ret = false;
#ifndef CONFIG_ARCH_NO_SYSCALL_VERIFY_PRE_USERMODE_STATE
ret = segment_eq(get_fs(), USER_DS);
/* Prevent re-ordering the call. */
barrier();
#endif
return ret;
}
I don't like having any kernel configuration in which has_user_ds()
unconditionally returns false. Can we put the ifdeffery in the caller
instead?
--Andy
... and then you could slim down the ifdeffery a bit:
static inline bool has_user_ds(void) {
bool ret = false;
#ifndef CONFIG_ARCH_NO_SYSCALL_VERIFY_PRE_USERMODE_STATE
ret = segment_eq(get_fs(), USER_DS);
/* Prevent re-ordering the call. */
barrier();
#endif
return ret;
}
I don't like having any kernel configuration in which has_user_ds()
unconditionally returns false. Can we put the ifdeffery in the caller
instead?
I don't like it either to be honest. We could have something like:
#ifndef CONFIG_ARCH_NO_SYSCALL_VERIFY_PRE_USERMODE_STATE
#define CHECK_USER_CALLER(_x) bool _x = segment_eq(get_fs(), USER_DS)
#else
#define CHECK_USER_CALLER(_x) bool _x = false
#endif
// In the syscall macro:
CHECK_CALLED_BY_USER(user_caller);