Re: [PATCH 33/38] arm64: Implement thread_struct whitelist for hardened usercopy

From: Dave Martin
Date: Tue Jan 16 2018 - 07:33:58 EST


On Mon, Jan 15, 2018 at 12:06:17PM -0800, Kees Cook wrote:
> On Mon, Jan 15, 2018 at 4:24 AM, Dave P Martin <Dave.Martin@xxxxxxx> wrote:
> > On Thu, Jan 11, 2018 at 02:03:05AM +0000, Kees Cook wrote:
> >> This whitelists the FPU register state portion of the thread_struct for
> >> copying to userspace, instead of the default entire structure.
> >>
> >> Cc: Catalin Marinas <catalin.marinas@xxxxxxx>
> >> Cc: Will Deacon <will.deacon@xxxxxxx>
> >> Cc: Christian Borntraeger <borntraeger@xxxxxxxxxx>
> >> Cc: Ingo Molnar <mingo@xxxxxxxxxx>
> >> Cc: James Morse <james.morse@xxxxxxx>
> >> Cc: "Peter Zijlstra (Intel)" <peterz@xxxxxxxxxxxxx>
> >> Cc: Dave Martin <Dave.Martin@xxxxxxx>
> >> Cc: zijun_hu <zijun_hu@xxxxxxx>
> >> Cc: linux-arm-kernel@xxxxxxxxxxxxxxxxxxx
> >> Signed-off-by: Kees Cook <keescook@xxxxxxxxxxxx>
> >> ---
> >> arch/arm64/Kconfig | 1 +
> >> arch/arm64/include/asm/processor.h | 8 ++++++++
> >> 2 files changed, 9 insertions(+)
> >>
> >> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> >> index a93339f5178f..c84477e6a884 100644
> >> --- a/arch/arm64/Kconfig
> >> +++ b/arch/arm64/Kconfig
> >> @@ -90,6 +90,7 @@ config ARM64
> >> select HAVE_ARCH_MMAP_RND_BITS
> >> select HAVE_ARCH_MMAP_RND_COMPAT_BITS if COMPAT
> >> select HAVE_ARCH_SECCOMP_FILTER
> >> + select HAVE_ARCH_THREAD_STRUCT_WHITELIST
> >> select HAVE_ARCH_TRACEHOOK
> >> select HAVE_ARCH_TRANSPARENT_HUGEPAGE
> >> select HAVE_ARCH_VMAP_STACK
> >> diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
> >> index 023cacb946c3..e58a5864ec89 100644
> >> --- a/arch/arm64/include/asm/processor.h
> >> +++ b/arch/arm64/include/asm/processor.h
> >> @@ -113,6 +113,14 @@ struct thread_struct {
> >> struct debug_info debug; /* debugging */
> >> };
> >>
> >> +/* Whitelist the fpsimd_state for copying to userspace. */
> >> +static inline void arch_thread_struct_whitelist(unsigned long *offset,
> >> + unsigned long *size)
> >> +{
> >> + *offset = offsetof(struct thread_struct, fpsimd_state);
> >> + *size = sizeof(struct fpsimd_state);
> >
> > This should be fpsimd_state.user_fpsimd (fpsimd_state.cpu is important
> > for correctly context switching and not supposed to be user-accessible.
> > A user copy that encompasses that is definitely a bug).
>
> So, I actually spent some more time looking at this due to the
> comments from rmk on arm32, and I don't think any whitelist is needed
> here at all. (i.e. it can be *offset = *size = 0) This is because all
> the usercopying I could find uses static sizes or bounce buffers, both
> of which bypass the dynamic-size hardened usercopy checks.

Why do static sizes bypass these checks? Just for efficiency?

> I've been running some arm64 builds now with this change, and I
> haven't tripped over any problems yet...

Sounds fair enough for now.

I haven't ruled out getting rid of the bounce buffers for FPSIMD
copy-in/out. They add stack and runtime overhead, and don't seem
to bring benefits.

Bounce buffers enable copies to succeed or fail atomically, rather
than being half-done and then faulting. This feels cleaner, but
In practice this doesn't seem to matter in real situations.

For SVE there are no bounce buffers, because the register data
can be unreasonably large (at least in theory).

Cheers
---Dave