|
@@ -500,7 +500,7 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset,
|
|
if (ret)
|
|
if (ret)
|
|
return ret;
|
|
return ret;
|
|
|
|
|
|
- if (!valid_user_regs(&newregs))
|
|
|
|
|
|
+ if (!valid_user_regs(&newregs, target))
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
task_pt_regs(target)->user_regs = newregs;
|
|
task_pt_regs(target)->user_regs = newregs;
|
|
@@ -770,7 +770,7 @@ static int compat_gpr_set(struct task_struct *target,
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- if (valid_user_regs(&newregs.user_regs))
|
|
|
|
|
|
+ if (valid_user_regs(&newregs.user_regs, target))
|
|
*task_pt_regs(target) = newregs;
|
|
*task_pt_regs(target) = newregs;
|
|
else
|
|
else
|
|
ret = -EINVAL;
|
|
ret = -EINVAL;
|
|
@@ -1272,3 +1272,79 @@ asmlinkage void syscall_trace_exit(struct pt_regs *regs)
|
|
if (test_thread_flag(TIF_SYSCALL_TRACE))
|
|
if (test_thread_flag(TIF_SYSCALL_TRACE))
|
|
tracehook_report_syscall(regs, PTRACE_SYSCALL_EXIT);
|
|
tracehook_report_syscall(regs, PTRACE_SYSCALL_EXIT);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * Bits which are always architecturally RES0 per ARM DDI 0487A.h
|
|
|
|
+ * Userspace cannot use these until they have an architectural meaning.
|
|
|
|
+ * We also reserve IL for the kernel; SS is handled dynamically.
|
|
|
|
+ */
|
|
|
|
+#define SPSR_EL1_AARCH64_RES0_BITS \
|
|
|
|
+ (GENMASK_ULL(63,32) | GENMASK_ULL(27, 22) | GENMASK_ULL(20, 10) | \
|
|
|
|
+ GENMASK_ULL(5, 5))
|
|
|
|
+#define SPSR_EL1_AARCH32_RES0_BITS \
|
|
|
|
+ (GENMASK_ULL(63,32) | GENMASK_ULL(24, 22) | GENMASK_ULL(20,20))
|
|
|
|
+
|
|
|
|
+static int valid_compat_regs(struct user_pt_regs *regs)
|
|
|
|
+{
|
|
|
|
+ regs->pstate &= ~SPSR_EL1_AARCH32_RES0_BITS;
|
|
|
|
+
|
|
|
|
+ if (!system_supports_mixed_endian_el0()) {
|
|
|
|
+ if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
|
|
|
|
+ regs->pstate |= COMPAT_PSR_E_BIT;
|
|
|
|
+ else
|
|
|
|
+ regs->pstate &= ~COMPAT_PSR_E_BIT;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (user_mode(regs) && (regs->pstate & PSR_MODE32_BIT) &&
|
|
|
|
+ (regs->pstate & COMPAT_PSR_A_BIT) == 0 &&
|
|
|
|
+ (regs->pstate & COMPAT_PSR_I_BIT) == 0 &&
|
|
|
|
+ (regs->pstate & COMPAT_PSR_F_BIT) == 0) {
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Force PSR to a valid 32-bit EL0t, preserving the same bits as
|
|
|
|
+ * arch/arm.
|
|
|
|
+ */
|
|
|
|
+ regs->pstate &= COMPAT_PSR_N_BIT | COMPAT_PSR_Z_BIT |
|
|
|
|
+ COMPAT_PSR_C_BIT | COMPAT_PSR_V_BIT |
|
|
|
|
+ COMPAT_PSR_Q_BIT | COMPAT_PSR_IT_MASK |
|
|
|
|
+ COMPAT_PSR_GE_MASK | COMPAT_PSR_E_BIT |
|
|
|
|
+ COMPAT_PSR_T_BIT;
|
|
|
|
+ regs->pstate |= PSR_MODE32_BIT;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int valid_native_regs(struct user_pt_regs *regs)
|
|
|
|
+{
|
|
|
|
+ regs->pstate &= ~SPSR_EL1_AARCH64_RES0_BITS;
|
|
|
|
+
|
|
|
|
+ if (user_mode(regs) && !(regs->pstate & PSR_MODE32_BIT) &&
|
|
|
|
+ (regs->pstate & PSR_D_BIT) == 0 &&
|
|
|
|
+ (regs->pstate & PSR_A_BIT) == 0 &&
|
|
|
|
+ (regs->pstate & PSR_I_BIT) == 0 &&
|
|
|
|
+ (regs->pstate & PSR_F_BIT) == 0) {
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Force PSR to a valid 64-bit EL0t */
|
|
|
|
+ regs->pstate &= PSR_N_BIT | PSR_Z_BIT | PSR_C_BIT | PSR_V_BIT;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * Are the current registers suitable for user mode? (used to maintain
|
|
|
|
+ * security in signal handlers)
|
|
|
|
+ */
|
|
|
|
+int valid_user_regs(struct user_pt_regs *regs, struct task_struct *task)
|
|
|
|
+{
|
|
|
|
+ if (!test_tsk_thread_flag(task, TIF_SINGLESTEP))
|
|
|
|
+ regs->pstate &= ~DBG_SPSR_SS;
|
|
|
|
+
|
|
|
|
+ if (is_compat_thread(task_thread_info(task)))
|
|
|
|
+ return valid_compat_regs(regs);
|
|
|
|
+ else
|
|
|
|
+ return valid_native_regs(regs);
|
|
|
|
+}
|