* [PATCH 1/2] powerpc: Rename thread_struct.fs to addr_limit @ 2018-05-14 13:03 Michael Ellerman 2018-05-14 13:03 ` [PATCH 2/2] powerpc: Check address limit on user-mode return (TIF_FSCHECK) Michael Ellerman 2018-06-04 14:10 ` [1/2] powerpc: Rename thread_struct.fs to addr_limit Michael Ellerman 0 siblings, 2 replies; 4+ messages in thread From: Michael Ellerman @ 2018-05-14 13:03 UTC (permalink / raw) To: linuxppc-dev; +Cc: kernel-hardening, thgarnie, keescook It's called 'fs' for historical reasons, it's named after the x86 'FS' register. But we don't have to use that name for the member of thread_struct, and in fact arch/x86 doesn't even call it 'fs' anymore. So rename it to 'addr_limit', which better reflects what it's used for, and is also the name used on other arches. Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> --- arch/powerpc/include/asm/processor.h | 6 +++--- arch/powerpc/include/asm/uaccess.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index b4778cfaad5b..07167c2d1825 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h @@ -264,7 +264,7 @@ struct thread_struct { unsigned long ksp_vsid; #endif struct pt_regs *regs; /* Pointer to saved register state */ - mm_segment_t fs; /* for get_fs() validation */ + mm_segment_t addr_limit; /* for get_fs() validation */ #ifdef CONFIG_BOOKE /* BookE base exception scratch space; align on cacheline */ unsigned long normsave[8] ____cacheline_aligned; @@ -398,7 +398,7 @@ struct thread_struct { #define INIT_THREAD { \ .ksp = INIT_SP, \ .ksp_limit = INIT_SP_LIMIT, \ - .fs = KERNEL_DS, \ + .addr_limit = KERNEL_DS, \ .pgdir = swapper_pg_dir, \ .fpexc_mode = MSR_FE0 | MSR_FE1, \ SPEFSCR_INIT \ @@ -407,7 +407,7 @@ struct thread_struct { #define INIT_THREAD { \ .ksp = INIT_SP, \ .regs = (struct pt_regs *)INIT_SP - 1, /* XXX bogus, I think */ \ - .fs = KERNEL_DS, \ + .addr_limit = KERNEL_DS, \ .fpexc_mode = 0, \ .ppr = INIT_PPR, \ .fscr = FSCR_TAR | FSCR_EBB \ diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h index a62ee663b2c8..a91cea15187b 100644 --- a/arch/powerpc/include/asm/uaccess.h +++ b/arch/powerpc/include/asm/uaccess.h @@ -30,8 +30,8 @@ #endif #define get_ds() (KERNEL_DS) -#define get_fs() (current->thread.fs) -#define set_fs(val) (current->thread.fs = (val)) +#define get_fs() (current->thread.addr_limit) +#define set_fs(val) (current->thread.addr_limit = (val)) #define segment_eq(a, b) ((a).seg == (b).seg) -- 2.14.1 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 2/2] powerpc: Check address limit on user-mode return (TIF_FSCHECK) 2018-05-14 13:03 [PATCH 1/2] powerpc: Rename thread_struct.fs to addr_limit Michael Ellerman @ 2018-05-14 13:03 ` Michael Ellerman 2018-05-15 22:04 ` Thomas Garnier 2018-06-04 14:10 ` [1/2] powerpc: Rename thread_struct.fs to addr_limit Michael Ellerman 1 sibling, 1 reply; 4+ messages in thread From: Michael Ellerman @ 2018-05-14 13:03 UTC (permalink / raw) To: linuxppc-dev; +Cc: kernel-hardening, thgarnie, keescook set_fs() sets the addr_limit, which is used in access_ok() to determine if an address is a user or kernel address. Some code paths use set_fs() to temporarily elevate the addr_limit so that kernel code can read/write kernel memory as if it were user memory. That is fine as long as the code can't ever return to userspace with the addr_limit still elevated. If that did happen, then userspace can read/write kernel memory as if it were user memory, eg. just with write(2). In case it's not clear, that is very bad. It has also happened in the past due to bugs. Commit 5ea0727b163c ("x86/syscalls: Check address limit on user-mode return") added a mechanism to check the addr_limit value before returning to userspace. Any call to set_fs() sets a thread flag, TIF_FSCHECK, and if we see that on the return to userspace we go out of line to check that the addr_limit value is not elevated. For further info see the above commit, as well as: https://lwn.net/Articles/722267/ https://bugs.chromium.org/p/project-zero/issues/detail?id=990 Verified to work on 64-bit Book3S using a POC that objdumps the system call handler, and a modified lkdtm_CORRUPT_USER_DS() that doesn't kill the caller. Before: $ sudo ./test-tif-fscheck ... 0000000000000000 <.data>: 0: e1 f7 8a 79 rldicl. r10,r12,30,63 4: 80 03 82 40 bne 0x384 8: 00 40 8a 71 andi. r10,r12,16384 c: 78 0b 2a 7c mr r10,r1 10: 10 fd 21 38 addi r1,r1,-752 14: 08 00 c2 41 beq- 0x1c 18: 58 09 2d e8 ld r1,2392(r13) 1c: 00 00 41 f9 std r10,0(r1) 20: 70 01 61 f9 std r11,368(r1) 24: 78 01 81 f9 std r12,376(r1) 28: 70 00 01 f8 std r0,112(r1) 2c: 78 00 41 f9 std r10,120(r1) 30: 20 00 82 41 beq 0x50 34: a6 42 4c 7d mftb r10 After: $ sudo ./test-tif-fscheck Killed And in dmesg: Invalid address limit on user-mode return WARNING: CPU: 1 PID: 3689 at ../include/linux/syscalls.h:260 do_notify_resume+0x140/0x170 ... NIP [c00000000001ee50] do_notify_resume+0x140/0x170 LR [c00000000001ee4c] do_notify_resume+0x13c/0x170 Call Trace: do_notify_resume+0x13c/0x170 (unreliable) ret_from_except_lite+0x70/0x74 Performance overhead is essentially zero in the usual case, because the bit is checked as part of the existing _TIF_USER_WORK_MASK check. Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> --- arch/powerpc/include/asm/thread_info.h | 8 +++++--- arch/powerpc/include/asm/uaccess.h | 8 +++++++- arch/powerpc/kernel/signal.c | 4 ++++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h index 5964145db03d..f308dfeb2746 100644 --- a/arch/powerpc/include/asm/thread_info.h +++ b/arch/powerpc/include/asm/thread_info.h @@ -79,8 +79,7 @@ extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src #define TIF_SYSCALL_TRACE 0 /* syscall trace active */ #define TIF_SIGPENDING 1 /* signal pending */ #define TIF_NEED_RESCHED 2 /* rescheduling necessary */ -#define TIF_POLLING_NRFLAG 3 /* true if poll_idle() is polling - TIF_NEED_RESCHED */ +#define TIF_FSCHECK 3 /* Check FS is USER_DS on return */ #define TIF_32BIT 4 /* 32 bit binary */ #define TIF_RESTORE_TM 5 /* need to restore TM FP/VEC/VSX */ #define TIF_PATCH_PENDING 6 /* pending live patching update */ @@ -99,6 +98,7 @@ extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src #if defined(CONFIG_PPC64) #define TIF_ELF2ABI 18 /* function descriptors must die! */ #endif +#define TIF_POLLING_NRFLAG 19 /* true if poll_idle() is polling TIF_NEED_RESCHED */ /* as above, but as bit values */ #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) @@ -118,13 +118,15 @@ extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src #define _TIF_SYSCALL_TRACEPOINT (1<<TIF_SYSCALL_TRACEPOINT) #define _TIF_EMULATE_STACK_STORE (1<<TIF_EMULATE_STACK_STORE) #define _TIF_NOHZ (1<<TIF_NOHZ) +#define _TIF_FSCHECK (1<<TIF_FSCHECK) #define _TIF_SYSCALL_DOTRACE (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \ _TIF_SECCOMP | _TIF_SYSCALL_TRACEPOINT | \ _TIF_NOHZ) #define _TIF_USER_WORK_MASK (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \ _TIF_NOTIFY_RESUME | _TIF_UPROBE | \ - _TIF_RESTORE_TM | _TIF_PATCH_PENDING) + _TIF_RESTORE_TM | _TIF_PATCH_PENDING | \ + _TIF_FSCHECK) #define _TIF_PERSYSCALL_MASK (_TIF_RESTOREALL|_TIF_NOERROR) /* Bits in local_flags */ diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h index a91cea15187b..abba80f8ff04 100644 --- a/arch/powerpc/include/asm/uaccess.h +++ b/arch/powerpc/include/asm/uaccess.h @@ -31,7 +31,13 @@ #define get_ds() (KERNEL_DS) #define get_fs() (current->thread.addr_limit) -#define set_fs(val) (current->thread.addr_limit = (val)) + +static inline void set_fs(mm_segment_t fs) +{ + current->thread.addr_limit = fs; + /* On user-mode return check addr_limit (fs) is correct */ + set_thread_flag(TIF_FSCHECK); +} #define segment_eq(a, b) ((a).seg == (b).seg) diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c index 61db86ecd318..fb932f1202c7 100644 --- a/arch/powerpc/kernel/signal.c +++ b/arch/powerpc/kernel/signal.c @@ -15,6 +15,7 @@ #include <linux/key.h> #include <linux/context_tracking.h> #include <linux/livepatch.h> +#include <linux/syscalls.h> #include <asm/hw_breakpoint.h> #include <linux/uaccess.h> #include <asm/unistd.h> @@ -150,6 +151,9 @@ void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) { user_exit(); + /* Check valid addr_limit, TIF check is done there */ + addr_limit_user_check(); + if (thread_info_flags & _TIF_UPROBE) uprobe_notify_resume(regs); -- 2.14.1 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH 2/2] powerpc: Check address limit on user-mode return (TIF_FSCHECK) 2018-05-14 13:03 ` [PATCH 2/2] powerpc: Check address limit on user-mode return (TIF_FSCHECK) Michael Ellerman @ 2018-05-15 22:04 ` Thomas Garnier 0 siblings, 0 replies; 4+ messages in thread From: Thomas Garnier @ 2018-05-15 22:04 UTC (permalink / raw) To: Michael Ellerman; +Cc: linuxppc-dev, Kernel Hardening, Kees Cook On Mon, May 14, 2018 at 6:03 AM Michael Ellerman <mpe@ellerman.id.au> wrote: > set_fs() sets the addr_limit, which is used in access_ok() to > determine if an address is a user or kernel address. > Some code paths use set_fs() to temporarily elevate the addr_limit so > that kernel code can read/write kernel memory as if it were user > memory. That is fine as long as the code can't ever return to > userspace with the addr_limit still elevated. > If that did happen, then userspace can read/write kernel memory as if > it were user memory, eg. just with write(2). In case it's not clear, > that is very bad. It has also happened in the past due to bugs. > Commit 5ea0727b163c ("x86/syscalls: Check address limit on user-mode > return") added a mechanism to check the addr_limit value before > returning to userspace. Any call to set_fs() sets a thread flag, > TIF_FSCHECK, and if we see that on the return to userspace we go out > of line to check that the addr_limit value is not elevated. > For further info see the above commit, as well as: > https://lwn.net/Articles/722267/ > https://bugs.chromium.org/p/project-zero/issues/detail?id=990 > Verified to work on 64-bit Book3S using a POC that objdumps the system > call handler, and a modified lkdtm_CORRUPT_USER_DS() that doesn't kill > the caller. > Before: > $ sudo ./test-tif-fscheck > ... > 0000000000000000 <.data>: > 0: e1 f7 8a 79 rldicl. r10,r12,30,63 > 4: 80 03 82 40 bne 0x384 > 8: 00 40 8a 71 andi. r10,r12,16384 > c: 78 0b 2a 7c mr r10,r1 > 10: 10 fd 21 38 addi r1,r1,-752 > 14: 08 00 c2 41 beq- 0x1c > 18: 58 09 2d e8 ld r1,2392(r13) > 1c: 00 00 41 f9 std r10,0(r1) > 20: 70 01 61 f9 std r11,368(r1) > 24: 78 01 81 f9 std r12,376(r1) > 28: 70 00 01 f8 std r0,112(r1) > 2c: 78 00 41 f9 std r10,120(r1) > 30: 20 00 82 41 beq 0x50 > 34: a6 42 4c 7d mftb r10 > After: > $ sudo ./test-tif-fscheck > Killed > And in dmesg: > Invalid address limit on user-mode return > WARNING: CPU: 1 PID: 3689 at ../include/linux/syscalls.h:260 do_notify_resume+0x140/0x170 > ... > NIP [c00000000001ee50] do_notify_resume+0x140/0x170 > LR [c00000000001ee4c] do_notify_resume+0x13c/0x170 > Call Trace: > do_notify_resume+0x13c/0x170 (unreliable) > ret_from_except_lite+0x70/0x74 > Performance overhead is essentially zero in the usual case, because > the bit is checked as part of the existing _TIF_USER_WORK_MASK check. > Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> The change looks good to me. > --- > arch/powerpc/include/asm/thread_info.h | 8 +++++--- > arch/powerpc/include/asm/uaccess.h | 8 +++++++- > arch/powerpc/kernel/signal.c | 4 ++++ > 3 files changed, 16 insertions(+), 4 deletions(-) > diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h > index 5964145db03d..f308dfeb2746 100644 > --- a/arch/powerpc/include/asm/thread_info.h > +++ b/arch/powerpc/include/asm/thread_info.h > @@ -79,8 +79,7 @@ extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src > #define TIF_SYSCALL_TRACE 0 /* syscall trace active */ > #define TIF_SIGPENDING 1 /* signal pending */ > #define TIF_NEED_RESCHED 2 /* rescheduling necessary */ > -#define TIF_POLLING_NRFLAG 3 /* true if poll_idle() is polling > - TIF_NEED_RESCHED */ > +#define TIF_FSCHECK 3 /* Check FS is USER_DS on return */ > #define TIF_32BIT 4 /* 32 bit binary */ > #define TIF_RESTORE_TM 5 /* need to restore TM FP/VEC/VSX */ > #define TIF_PATCH_PENDING 6 /* pending live patching update */ > @@ -99,6 +98,7 @@ extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src > #if defined(CONFIG_PPC64) > #define TIF_ELF2ABI 18 /* function descriptors must die! */ > #endif > +#define TIF_POLLING_NRFLAG 19 /* true if poll_idle() is polling TIF_NEED_RESCHED */ > /* as above, but as bit values */ > #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) > @@ -118,13 +118,15 @@ extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src > #define _TIF_SYSCALL_TRACEPOINT (1<<TIF_SYSCALL_TRACEPOINT) > #define _TIF_EMULATE_STACK_STORE (1<<TIF_EMULATE_STACK_STORE) > #define _TIF_NOHZ (1<<TIF_NOHZ) > +#define _TIF_FSCHECK (1<<TIF_FSCHECK) > #define _TIF_SYSCALL_DOTRACE (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \ > _TIF_SECCOMP | _TIF_SYSCALL_TRACEPOINT | \ > _TIF_NOHZ) > #define _TIF_USER_WORK_MASK (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \ > _TIF_NOTIFY_RESUME | _TIF_UPROBE | \ > - _TIF_RESTORE_TM | _TIF_PATCH_PENDING) > + _TIF_RESTORE_TM | _TIF_PATCH_PENDING | \ > + _TIF_FSCHECK) > #define _TIF_PERSYSCALL_MASK (_TIF_RESTOREALL|_TIF_NOERROR) > /* Bits in local_flags */ > diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h > index a91cea15187b..abba80f8ff04 100644 > --- a/arch/powerpc/include/asm/uaccess.h > +++ b/arch/powerpc/include/asm/uaccess.h > @@ -31,7 +31,13 @@ > #define get_ds() (KERNEL_DS) > #define get_fs() (current->thread.addr_limit) > -#define set_fs(val) (current->thread.addr_limit = (val)) > + > +static inline void set_fs(mm_segment_t fs) > +{ > + current->thread.addr_limit = fs; > + /* On user-mode return check addr_limit (fs) is correct */ > + set_thread_flag(TIF_FSCHECK); > +} > #define segment_eq(a, b) ((a).seg == (b).seg) > diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c > index 61db86ecd318..fb932f1202c7 100644 > --- a/arch/powerpc/kernel/signal.c > +++ b/arch/powerpc/kernel/signal.c > @@ -15,6 +15,7 @@ > #include <linux/key.h> > #include <linux/context_tracking.h> > #include <linux/livepatch.h> > +#include <linux/syscalls.h> > #include <asm/hw_breakpoint.h> > #include <linux/uaccess.h> > #include <asm/unistd.h> > @@ -150,6 +151,9 @@ void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) > { > user_exit(); > + /* Check valid addr_limit, TIF check is done there */ > + addr_limit_user_check(); > + > if (thread_info_flags & _TIF_UPROBE) > uprobe_notify_resume(regs); > -- > 2.14.1 -- Thomas ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [1/2] powerpc: Rename thread_struct.fs to addr_limit 2018-05-14 13:03 [PATCH 1/2] powerpc: Rename thread_struct.fs to addr_limit Michael Ellerman 2018-05-14 13:03 ` [PATCH 2/2] powerpc: Check address limit on user-mode return (TIF_FSCHECK) Michael Ellerman @ 2018-06-04 14:10 ` Michael Ellerman 1 sibling, 0 replies; 4+ messages in thread From: Michael Ellerman @ 2018-06-04 14:10 UTC (permalink / raw) To: Michael Ellerman, linuxppc-dev; +Cc: thgarnie, keescook, kernel-hardening On Mon, 2018-05-14 at 13:03:15 UTC, Michael Ellerman wrote: > It's called 'fs' for historical reasons, it's named after the x86 'FS' > register. But we don't have to use that name for the member of > thread_struct, and in fact arch/x86 doesn't even call it 'fs' anymore. > > So rename it to 'addr_limit', which better reflects what it's used > for, and is also the name used on other arches. > > Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Series applied to powerpc next. https://git.kernel.org/powerpc/c/ba0635fcbe8c1ce83523c1ec797538 cheers ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2018-06-04 14:11 UTC | newest] Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2018-05-14 13:03 [PATCH 1/2] powerpc: Rename thread_struct.fs to addr_limit Michael Ellerman 2018-05-14 13:03 ` [PATCH 2/2] powerpc: Check address limit on user-mode return (TIF_FSCHECK) Michael Ellerman 2018-05-15 22:04 ` Thomas Garnier 2018-06-04 14:10 ` [1/2] powerpc: Rename thread_struct.fs to addr_limit Michael Ellerman
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).