|
@@ -64,6 +64,16 @@ extern int fixup_exception(struct pt_regs *regs);
|
|
|
static inline void set_fs(mm_segment_t fs)
|
|
|
{
|
|
|
current_thread_info()->addr_limit = fs;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Enable/disable UAO so that copy_to_user() etc can access
|
|
|
+ * kernel memory with the unprivileged instructions.
|
|
|
+ */
|
|
|
+ if (IS_ENABLED(CONFIG_ARM64_UAO) && fs == KERNEL_DS)
|
|
|
+ asm(ALTERNATIVE("nop", SET_PSTATE_UAO(1), ARM64_HAS_UAO));
|
|
|
+ else
|
|
|
+ asm(ALTERNATIVE("nop", SET_PSTATE_UAO(0), ARM64_HAS_UAO,
|
|
|
+ CONFIG_ARM64_UAO));
|
|
|
}
|
|
|
|
|
|
#define segment_eq(a, b) ((a) == (b))
|
|
@@ -113,9 +123,10 @@ static inline void set_fs(mm_segment_t fs)
|
|
|
* The "__xxx_error" versions set the third argument to -EFAULT if an error
|
|
|
* occurs, and leave it unchanged on success.
|
|
|
*/
|
|
|
-#define __get_user_asm(instr, reg, x, addr, err) \
|
|
|
+#define __get_user_asm(instr, alt_instr, reg, x, addr, err, feature) \
|
|
|
asm volatile( \
|
|
|
- "1: " instr " " reg "1, [%2]\n" \
|
|
|
+ "1:"ALTERNATIVE(instr " " reg "1, [%2]\n", \
|
|
|
+ alt_instr " " reg "1, [%2]\n", feature) \
|
|
|
"2:\n" \
|
|
|
" .section .fixup, \"ax\"\n" \
|
|
|
" .align 2\n" \
|
|
@@ -138,16 +149,20 @@ do { \
|
|
|
CONFIG_ARM64_PAN)); \
|
|
|
switch (sizeof(*(ptr))) { \
|
|
|
case 1: \
|
|
|
- __get_user_asm("ldrb", "%w", __gu_val, (ptr), (err)); \
|
|
|
+ __get_user_asm("ldrb", "ldtrb", "%w", __gu_val, (ptr), \
|
|
|
+ (err), ARM64_HAS_UAO); \
|
|
|
break; \
|
|
|
case 2: \
|
|
|
- __get_user_asm("ldrh", "%w", __gu_val, (ptr), (err)); \
|
|
|
+ __get_user_asm("ldrh", "ldtrh", "%w", __gu_val, (ptr), \
|
|
|
+ (err), ARM64_HAS_UAO); \
|
|
|
break; \
|
|
|
case 4: \
|
|
|
- __get_user_asm("ldr", "%w", __gu_val, (ptr), (err)); \
|
|
|
+ __get_user_asm("ldr", "ldtr", "%w", __gu_val, (ptr), \
|
|
|
+ (err), ARM64_HAS_UAO); \
|
|
|
break; \
|
|
|
case 8: \
|
|
|
- __get_user_asm("ldr", "%", __gu_val, (ptr), (err)); \
|
|
|
+ __get_user_asm("ldr", "ldtr", "%", __gu_val, (ptr), \
|
|
|
+ (err), ARM64_HAS_UAO); \
|
|
|
break; \
|
|
|
default: \
|
|
|
BUILD_BUG(); \
|
|
@@ -181,9 +196,10 @@ do { \
|
|
|
((x) = 0, -EFAULT); \
|
|
|
})
|
|
|
|
|
|
-#define __put_user_asm(instr, reg, x, addr, err) \
|
|
|
+#define __put_user_asm(instr, alt_instr, reg, x, addr, err, feature) \
|
|
|
asm volatile( \
|
|
|
- "1: " instr " " reg "1, [%2]\n" \
|
|
|
+ "1:"ALTERNATIVE(instr " " reg "1, [%2]\n", \
|
|
|
+ alt_instr " " reg "1, [%2]\n", feature) \
|
|
|
"2:\n" \
|
|
|
" .section .fixup,\"ax\"\n" \
|
|
|
" .align 2\n" \
|
|
@@ -205,16 +221,20 @@ do { \
|
|
|
CONFIG_ARM64_PAN)); \
|
|
|
switch (sizeof(*(ptr))) { \
|
|
|
case 1: \
|
|
|
- __put_user_asm("strb", "%w", __pu_val, (ptr), (err)); \
|
|
|
+ __put_user_asm("strb", "sttrb", "%w", __pu_val, (ptr), \
|
|
|
+ (err), ARM64_HAS_UAO); \
|
|
|
break; \
|
|
|
case 2: \
|
|
|
- __put_user_asm("strh", "%w", __pu_val, (ptr), (err)); \
|
|
|
+ __put_user_asm("strh", "sttrh", "%w", __pu_val, (ptr), \
|
|
|
+ (err), ARM64_HAS_UAO); \
|
|
|
break; \
|
|
|
case 4: \
|
|
|
- __put_user_asm("str", "%w", __pu_val, (ptr), (err)); \
|
|
|
+ __put_user_asm("str", "sttr", "%w", __pu_val, (ptr), \
|
|
|
+ (err), ARM64_HAS_UAO); \
|
|
|
break; \
|
|
|
case 8: \
|
|
|
- __put_user_asm("str", "%", __pu_val, (ptr), (err)); \
|
|
|
+ __put_user_asm("str", "sttr", "%", __pu_val, (ptr), \
|
|
|
+ (err), ARM64_HAS_UAO); \
|
|
|
break; \
|
|
|
default: \
|
|
|
BUILD_BUG(); \
|