[PATCH 3/4] powerpc/uaccess: evaluate macro arguments once, before user access is allowed
Nicholas Piggin
npiggin at gmail.com
Fri Apr 3 19:58:27 AEDT 2020
Christophe Leroy's on March 27, 2020 5:21 pm:
>
>
> Le 27/03/2020 à 08:02, Nicholas Piggin a écrit :
>> get/put_user can be called with nontrivial arguments. fs/proc/page.c
>> has a good example:
>>
>> if (put_user(stable_page_flags(ppage), out)) {
>>
>> stable_page_flags is quite a lot of code, including spin locks in the
>> page allocator.
>>
>> Ensure these arguments are evaluated before user access is allowed.
>> This improves security by reducing code with access to userspace, but
>> it also fixes a PREEMPT bug with KUAP on powerpc/64s:
>> stable_page_flags is currently called with AMR set to allow writes,
>> it ends up calling spin_unlock(), which can call preempt_schedule. But
>> the task switch code can not be called with AMR set (it relies on
>> interrupts saving the register), so this blows up.
>>
>> It's fine if the code inside allow_user_access is preemptible, because
>> a timer or IPI will save the AMR, but it's not okay to explicitly
>> cause a reschedule.
>>
>> Signed-off-by: Nicholas Piggin <npiggin at gmail.com>
>> ---
>> arch/powerpc/include/asm/uaccess.h | 97 ++++++++++++++++++------------
>> 1 file changed, 59 insertions(+), 38 deletions(-)
>>
>> diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h
>> index 670910df3cc7..1cf8595aeef1 100644
>> --- a/arch/powerpc/include/asm/uaccess.h
>> +++ b/arch/powerpc/include/asm/uaccess.h
>> @@ -162,36 +162,48 @@ do { \
>> prevent_write_to_user(ptr, size); \
>> } while (0)
>>
>> -#define __put_user_nocheck(x, ptr, size, do_allow) \
>> +#define __put_user_nocheck(x, ptr, size, do_allow) \
>
> No need to touch this line. Anyway at the end, you still have several \
> which are not aligned.
>
>> ({ \
>> long __pu_err; \
>> __typeof__(*(ptr)) __user *__pu_addr = (ptr); \
>> + __typeof__(*(ptr)) __pu_val = (x); \
>> + __typeof__(size) __pu_size = (size); \
>> + \
>> if (!is_kernel_addr((unsigned long)__pu_addr)) \
>> might_fault(); \
>> - __chk_user_ptr(ptr); \
>> - if (do_allow) \
>
> No need to touch that line
>
>> - __put_user_size((x), __pu_addr, (size), __pu_err); \
>> - else \
>
> No need to touch that line
Okay fair point I can redo the patch.
Thanks,
Nick
More information about the Linuxppc-dev
mailing list