Commit 65896545 authored by Dave Martin's avatar Dave Martin Committed by Will Deacon

arm64: uaccess: Fix omissions from usercopy whitelist

When the hardend usercopy support was added for arm64, it was
concluded that all cases of usercopy into and out of thread_struct
were statically sized and so didn't require explicit whitelisting
of the appropriate fields in thread_struct.

Testing with usercopy hardening enabled has revealed that this is
not the case for certain ptrace regset manipulation calls on arm64.
This occurs because the sizes of usercopies associated with the
regset API are dynamic by construction, and because arm64 does not
always stage such copies via the stack: indeed the regset API is
designed to avoid the need for that by adding some bounds checking.

This is currently believed to affect only the fpsimd and TLS
registers.

Because the whitelisted fields in thread_struct must be contiguous,
this patch groups them together in a nested struct.  It is also
necessary to be able to determine the location and size of that
struct, so rather than making the struct anonymous (which would
save on edits elsewhere) or adding an anonymous union containing
named and unnamed instances of the same struct (gross), this patch
gives the struct a name and makes the necessary edits to code that
references it (noisy but simple).

Care is needed to ensure that the new struct does not contain
padding (which the usercopy hardening would fail to protect).

For this reason, the presence of tp2_value is made unconditional,
since a padding field would be needed there in any case.  This pads
up to the 16-byte alignment required by struct user_fpsimd_state.
Acked-by: default avatarKees Cook <keescook@chromium.org>
Reported-by: default avatarMark Rutland <mark.rutland@arm.com>
Fixes: 9e8084d3 ("arm64: Implement thread_struct whitelist for hardened usercopy")
Signed-off-by: default avatarDave Martin <Dave.Martin@arm.com>
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
parent 20b85472
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
#ifdef __KERNEL__ #ifdef __KERNEL__
#include <linux/build_bug.h>
#include <linux/stddef.h>
#include <linux/string.h> #include <linux/string.h>
#include <asm/alternative.h> #include <asm/alternative.h>
...@@ -103,11 +105,18 @@ struct cpu_context { ...@@ -103,11 +105,18 @@ struct cpu_context {
struct thread_struct { struct thread_struct {
struct cpu_context cpu_context; /* cpu context */ struct cpu_context cpu_context; /* cpu context */
unsigned long tp_value; /* TLS register */
#ifdef CONFIG_COMPAT /*
unsigned long tp2_value; * Whitelisted fields for hardened usercopy:
#endif * Maintainers must ensure manually that this contains no
struct user_fpsimd_state fpsimd_state; * implicit padding.
*/
struct {
unsigned long tp_value; /* TLS register */
unsigned long tp2_value;
struct user_fpsimd_state fpsimd_state;
} uw;
unsigned int fpsimd_cpu; unsigned int fpsimd_cpu;
void *sve_state; /* SVE registers, if any */ void *sve_state; /* SVE registers, if any */
unsigned int sve_vl; /* SVE vector length */ unsigned int sve_vl; /* SVE vector length */
...@@ -117,14 +126,17 @@ struct thread_struct { ...@@ -117,14 +126,17 @@ struct thread_struct {
struct debug_info debug; /* debugging */ struct debug_info debug; /* debugging */
}; };
/*
* Everything usercopied to/from thread_struct is statically-sized, so
* no hardened usercopy whitelist is needed.
*/
static inline void arch_thread_struct_whitelist(unsigned long *offset, static inline void arch_thread_struct_whitelist(unsigned long *offset,
unsigned long *size) unsigned long *size)
{ {
*offset = *size = 0; /* Verify that there is no padding among the whitelisted fields: */
BUILD_BUG_ON(sizeof_field(struct thread_struct, uw) !=
sizeof_field(struct thread_struct, uw.tp_value) +
sizeof_field(struct thread_struct, uw.tp2_value) +
sizeof_field(struct thread_struct, uw.fpsimd_state));
*offset = offsetof(struct thread_struct, uw);
*size = sizeof_field(struct thread_struct, uw);
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
...@@ -132,13 +144,13 @@ static inline void arch_thread_struct_whitelist(unsigned long *offset, ...@@ -132,13 +144,13 @@ static inline void arch_thread_struct_whitelist(unsigned long *offset,
({ \ ({ \
unsigned long *__tls; \ unsigned long *__tls; \
if (is_compat_thread(task_thread_info(t))) \ if (is_compat_thread(task_thread_info(t))) \
__tls = &(t)->thread.tp2_value; \ __tls = &(t)->thread.uw.tp2_value; \
else \ else \
__tls = &(t)->thread.tp_value; \ __tls = &(t)->thread.uw.tp_value; \
__tls; \ __tls; \
}) })
#else #else
#define task_user_tls(t) (&(t)->thread.tp_value) #define task_user_tls(t) (&(t)->thread.uw.tp_value)
#endif #endif
/* Sync TPIDR_EL0 back to thread_struct for current */ /* Sync TPIDR_EL0 back to thread_struct for current */
......
...@@ -224,7 +224,7 @@ static void sve_user_enable(void) ...@@ -224,7 +224,7 @@ static void sve_user_enable(void)
* sets TIF_SVE. * sets TIF_SVE.
* *
* When stored, FPSIMD registers V0-V31 are encoded in * When stored, FPSIMD registers V0-V31 are encoded in
* task->fpsimd_state; bits [max : 128] for each of Z0-Z31 are * task->thread.uw.fpsimd_state; bits [max : 128] for each of Z0-Z31 are
* logically zero but not stored anywhere; P0-P15 and FFR are not * logically zero but not stored anywhere; P0-P15 and FFR are not
* stored and have unspecified values from userspace's point of * stored and have unspecified values from userspace's point of
* view. For hygiene purposes, the kernel zeroes them on next use, * view. For hygiene purposes, the kernel zeroes them on next use,
...@@ -233,9 +233,9 @@ static void sve_user_enable(void) ...@@ -233,9 +233,9 @@ static void sve_user_enable(void)
* task->thread.sve_state does not need to be non-NULL, valid or any * task->thread.sve_state does not need to be non-NULL, valid or any
* particular size: it must not be dereferenced. * particular size: it must not be dereferenced.
* *
* * FPSR and FPCR are always stored in task->fpsimd_state irrespctive of * * FPSR and FPCR are always stored in task->thread.uw.fpsimd_state
* whether TIF_SVE is clear or set, since these are not vector length * irrespective of whether TIF_SVE is clear or set, since these are
* dependent. * not vector length dependent.
*/ */
/* /*
...@@ -253,10 +253,10 @@ static void task_fpsimd_load(void) ...@@ -253,10 +253,10 @@ static void task_fpsimd_load(void)
if (system_supports_sve() && test_thread_flag(TIF_SVE)) if (system_supports_sve() && test_thread_flag(TIF_SVE))
sve_load_state(sve_pffr(current), sve_load_state(sve_pffr(current),
&current->thread.fpsimd_state.fpsr, &current->thread.uw.fpsimd_state.fpsr,
sve_vq_from_vl(current->thread.sve_vl) - 1); sve_vq_from_vl(current->thread.sve_vl) - 1);
else else
fpsimd_load_state(&current->thread.fpsimd_state); fpsimd_load_state(&current->thread.uw.fpsimd_state);
if (system_supports_sve()) { if (system_supports_sve()) {
/* Toggle SVE trapping for userspace if needed */ /* Toggle SVE trapping for userspace if needed */
...@@ -292,9 +292,9 @@ static void task_fpsimd_save(void) ...@@ -292,9 +292,9 @@ static void task_fpsimd_save(void)
} }
sve_save_state(sve_pffr(current), sve_save_state(sve_pffr(current),
&current->thread.fpsimd_state.fpsr); &current->thread.uw.fpsimd_state.fpsr);
} else } else
fpsimd_save_state(&current->thread.fpsimd_state); fpsimd_save_state(&current->thread.uw.fpsimd_state);
} }
} }
...@@ -405,20 +405,21 @@ static int __init sve_sysctl_init(void) { return 0; } ...@@ -405,20 +405,21 @@ static int __init sve_sysctl_init(void) { return 0; }
(SVE_SIG_ZREG_OFFSET(vq, n) - SVE_SIG_REGS_OFFSET)) (SVE_SIG_ZREG_OFFSET(vq, n) - SVE_SIG_REGS_OFFSET))
/* /*
* Transfer the FPSIMD state in task->thread.fpsimd_state to * Transfer the FPSIMD state in task->thread.uw.fpsimd_state to
* task->thread.sve_state. * task->thread.sve_state.
* *
* Task can be a non-runnable task, or current. In the latter case, * Task can be a non-runnable task, or current. In the latter case,
* softirqs (and preemption) must be disabled. * softirqs (and preemption) must be disabled.
* task->thread.sve_state must point to at least sve_state_size(task) * task->thread.sve_state must point to at least sve_state_size(task)
* bytes of allocated kernel memory. * bytes of allocated kernel memory.
* task->thread.fpsimd_state must be up to date before calling this function. * task->thread.uw.fpsimd_state must be up to date before calling this
* function.
*/ */
static void fpsimd_to_sve(struct task_struct *task) static void fpsimd_to_sve(struct task_struct *task)
{ {
unsigned int vq; unsigned int vq;
void *sst = task->thread.sve_state; void *sst = task->thread.sve_state;
struct user_fpsimd_state const *fst = &task->thread.fpsimd_state; struct user_fpsimd_state const *fst = &task->thread.uw.fpsimd_state;
unsigned int i; unsigned int i;
if (!system_supports_sve()) if (!system_supports_sve())
...@@ -432,7 +433,7 @@ static void fpsimd_to_sve(struct task_struct *task) ...@@ -432,7 +433,7 @@ static void fpsimd_to_sve(struct task_struct *task)
/* /*
* Transfer the SVE state in task->thread.sve_state to * Transfer the SVE state in task->thread.sve_state to
* task->thread.fpsimd_state. * task->thread.uw.fpsimd_state.
* *
* Task can be a non-runnable task, or current. In the latter case, * Task can be a non-runnable task, or current. In the latter case,
* softirqs (and preemption) must be disabled. * softirqs (and preemption) must be disabled.
...@@ -444,7 +445,7 @@ static void sve_to_fpsimd(struct task_struct *task) ...@@ -444,7 +445,7 @@ static void sve_to_fpsimd(struct task_struct *task)
{ {
unsigned int vq; unsigned int vq;
void const *sst = task->thread.sve_state; void const *sst = task->thread.sve_state;
struct user_fpsimd_state *fst = &task->thread.fpsimd_state; struct user_fpsimd_state *fst = &task->thread.uw.fpsimd_state;
unsigned int i; unsigned int i;
if (!system_supports_sve()) if (!system_supports_sve())
...@@ -511,7 +512,7 @@ void fpsimd_sync_to_sve(struct task_struct *task) ...@@ -511,7 +512,7 @@ void fpsimd_sync_to_sve(struct task_struct *task)
} }
/* /*
* Ensure that task->thread.fpsimd_state is up to date with respect to * Ensure that task->thread.uw.fpsimd_state is up to date with respect to
* the user task, irrespective of whether SVE is in use or not. * the user task, irrespective of whether SVE is in use or not.
* *
* This should only be called by ptrace. task must be non-runnable. * This should only be called by ptrace. task must be non-runnable.
...@@ -526,21 +527,21 @@ void sve_sync_to_fpsimd(struct task_struct *task) ...@@ -526,21 +527,21 @@ void sve_sync_to_fpsimd(struct task_struct *task)
/* /*
* Ensure that task->thread.sve_state is up to date with respect to * Ensure that task->thread.sve_state is up to date with respect to
* the task->thread.fpsimd_state. * the task->thread.uw.fpsimd_state.
* *
* This should only be called by ptrace to merge new FPSIMD register * This should only be called by ptrace to merge new FPSIMD register
* values into a task for which SVE is currently active. * values into a task for which SVE is currently active.
* task must be non-runnable. * task must be non-runnable.
* task->thread.sve_state must point to at least sve_state_size(task) * task->thread.sve_state must point to at least sve_state_size(task)
* bytes of allocated kernel memory. * bytes of allocated kernel memory.
* task->thread.fpsimd_state must already have been initialised with * task->thread.uw.fpsimd_state must already have been initialised with
* the new FPSIMD register values to be merged in. * the new FPSIMD register values to be merged in.
*/ */
void sve_sync_from_fpsimd_zeropad(struct task_struct *task) void sve_sync_from_fpsimd_zeropad(struct task_struct *task)
{ {
unsigned int vq; unsigned int vq;
void *sst = task->thread.sve_state; void *sst = task->thread.sve_state;
struct user_fpsimd_state const *fst = &task->thread.fpsimd_state; struct user_fpsimd_state const *fst = &task->thread.uw.fpsimd_state;
unsigned int i; unsigned int i;
if (!test_tsk_thread_flag(task, TIF_SVE)) if (!test_tsk_thread_flag(task, TIF_SVE))
...@@ -910,7 +911,7 @@ void fpsimd_thread_switch(struct task_struct *next) ...@@ -910,7 +911,7 @@ void fpsimd_thread_switch(struct task_struct *next)
* upon the next return to userland. * upon the next return to userland.
*/ */
if (__this_cpu_read(fpsimd_last_state.st) == if (__this_cpu_read(fpsimd_last_state.st) ==
&next->thread.fpsimd_state &next->thread.uw.fpsimd_state
&& next->thread.fpsimd_cpu == smp_processor_id()) && next->thread.fpsimd_cpu == smp_processor_id())
clear_tsk_thread_flag(next, TIF_FOREIGN_FPSTATE); clear_tsk_thread_flag(next, TIF_FOREIGN_FPSTATE);
else else
...@@ -927,8 +928,8 @@ void fpsimd_flush_thread(void) ...@@ -927,8 +928,8 @@ void fpsimd_flush_thread(void)
local_bh_disable(); local_bh_disable();
memset(&current->thread.fpsimd_state, 0, memset(&current->thread.uw.fpsimd_state, 0,
sizeof(current->thread.fpsimd_state)); sizeof(current->thread.uw.fpsimd_state));
fpsimd_flush_task_state(current); fpsimd_flush_task_state(current);
if (system_supports_sve()) { if (system_supports_sve()) {
...@@ -987,7 +988,7 @@ void fpsimd_preserve_current_state(void) ...@@ -987,7 +988,7 @@ void fpsimd_preserve_current_state(void)
/* /*
* Like fpsimd_preserve_current_state(), but ensure that * Like fpsimd_preserve_current_state(), but ensure that
* current->thread.fpsimd_state is updated so that it can be copied to * current->thread.uw.fpsimd_state is updated so that it can be copied to
* the signal frame. * the signal frame.
*/ */
void fpsimd_signal_preserve_current_state(void) void fpsimd_signal_preserve_current_state(void)
...@@ -1006,7 +1007,7 @@ static void fpsimd_bind_to_cpu(void) ...@@ -1006,7 +1007,7 @@ static void fpsimd_bind_to_cpu(void)
struct fpsimd_last_state_struct *last = struct fpsimd_last_state_struct *last =
this_cpu_ptr(&fpsimd_last_state); this_cpu_ptr(&fpsimd_last_state);
last->st = &current->thread.fpsimd_state; last->st = &current->thread.uw.fpsimd_state;
last->sve_in_use = test_thread_flag(TIF_SVE); last->sve_in_use = test_thread_flag(TIF_SVE);
current->thread.fpsimd_cpu = smp_processor_id(); current->thread.fpsimd_cpu = smp_processor_id();
} }
...@@ -1043,7 +1044,7 @@ void fpsimd_update_current_state(struct user_fpsimd_state const *state) ...@@ -1043,7 +1044,7 @@ void fpsimd_update_current_state(struct user_fpsimd_state const *state)
local_bh_disable(); local_bh_disable();
current->thread.fpsimd_state = *state; current->thread.uw.fpsimd_state = *state;
if (system_supports_sve() && test_thread_flag(TIF_SVE)) if (system_supports_sve() && test_thread_flag(TIF_SVE))
fpsimd_to_sve(current); fpsimd_to_sve(current);
......
...@@ -257,7 +257,7 @@ static void tls_thread_flush(void) ...@@ -257,7 +257,7 @@ static void tls_thread_flush(void)
write_sysreg(0, tpidr_el0); write_sysreg(0, tpidr_el0);
if (is_compat_task()) { if (is_compat_task()) {
current->thread.tp_value = 0; current->thread.uw.tp_value = 0;
/* /*
* We need to ensure ordering between the shadow state and the * We need to ensure ordering between the shadow state and the
...@@ -351,7 +351,7 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start, ...@@ -351,7 +351,7 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
* for the new thread. * for the new thread.
*/ */
if (clone_flags & CLONE_SETTLS) if (clone_flags & CLONE_SETTLS)
p->thread.tp_value = childregs->regs[3]; p->thread.uw.tp_value = childregs->regs[3];
} else { } else {
memset(childregs, 0, sizeof(struct pt_regs)); memset(childregs, 0, sizeof(struct pt_regs));
childregs->pstate = PSR_MODE_EL1h; childregs->pstate = PSR_MODE_EL1h;
...@@ -379,7 +379,7 @@ static void tls_thread_switch(struct task_struct *next) ...@@ -379,7 +379,7 @@ static void tls_thread_switch(struct task_struct *next)
tls_preserve_current_state(); tls_preserve_current_state();
if (is_compat_thread(task_thread_info(next))) if (is_compat_thread(task_thread_info(next)))
write_sysreg(next->thread.tp_value, tpidrro_el0); write_sysreg(next->thread.uw.tp_value, tpidrro_el0);
else if (!arm64_kernel_unmapped_at_el0()) else if (!arm64_kernel_unmapped_at_el0())
write_sysreg(0, tpidrro_el0); write_sysreg(0, tpidrro_el0);
......
...@@ -629,7 +629,7 @@ static int __fpr_get(struct task_struct *target, ...@@ -629,7 +629,7 @@ static int __fpr_get(struct task_struct *target,
sve_sync_to_fpsimd(target); sve_sync_to_fpsimd(target);
uregs = &target->thread.fpsimd_state; uregs = &target->thread.uw.fpsimd_state;
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs,
start_pos, start_pos + sizeof(*uregs)); start_pos, start_pos + sizeof(*uregs));
...@@ -655,19 +655,19 @@ static int __fpr_set(struct task_struct *target, ...@@ -655,19 +655,19 @@ static int __fpr_set(struct task_struct *target,
struct user_fpsimd_state newstate; struct user_fpsimd_state newstate;
/* /*
* Ensure target->thread.fpsimd_state is up to date, so that a * Ensure target->thread.uw.fpsimd_state is up to date, so that a
* short copyin can't resurrect stale data. * short copyin can't resurrect stale data.
*/ */
sve_sync_to_fpsimd(target); sve_sync_to_fpsimd(target);
newstate = target->thread.fpsimd_state; newstate = target->thread.uw.fpsimd_state;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newstate, ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newstate,
start_pos, start_pos + sizeof(newstate)); start_pos, start_pos + sizeof(newstate));
if (ret) if (ret)
return ret; return ret;
target->thread.fpsimd_state = newstate; target->thread.uw.fpsimd_state = newstate;
return ret; return ret;
} }
...@@ -692,7 +692,7 @@ static int tls_get(struct task_struct *target, const struct user_regset *regset, ...@@ -692,7 +692,7 @@ static int tls_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count, unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf) void *kbuf, void __user *ubuf)
{ {
unsigned long *tls = &target->thread.tp_value; unsigned long *tls = &target->thread.uw.tp_value;
if (target == current) if (target == current)
tls_preserve_current_state(); tls_preserve_current_state();
...@@ -705,13 +705,13 @@ static int tls_set(struct task_struct *target, const struct user_regset *regset, ...@@ -705,13 +705,13 @@ static int tls_set(struct task_struct *target, const struct user_regset *regset,
const void *kbuf, const void __user *ubuf) const void *kbuf, const void __user *ubuf)
{ {
int ret; int ret;
unsigned long tls = target->thread.tp_value; unsigned long tls = target->thread.uw.tp_value;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &tls, 0, -1); ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
if (ret) if (ret)
return ret; return ret;
target->thread.tp_value = tls; target->thread.uw.tp_value = tls;
return ret; return ret;
} }
...@@ -842,7 +842,7 @@ static int sve_get(struct task_struct *target, ...@@ -842,7 +842,7 @@ static int sve_get(struct task_struct *target,
start = end; start = end;
end = SVE_PT_SVE_FPCR_OFFSET(vq) + SVE_PT_SVE_FPCR_SIZE; end = SVE_PT_SVE_FPCR_OFFSET(vq) + SVE_PT_SVE_FPCR_SIZE;
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&target->thread.fpsimd_state.fpsr, &target->thread.uw.fpsimd_state.fpsr,
start, end); start, end);
if (ret) if (ret)
return ret; return ret;
...@@ -941,7 +941,7 @@ static int sve_set(struct task_struct *target, ...@@ -941,7 +941,7 @@ static int sve_set(struct task_struct *target,
start = end; start = end;
end = SVE_PT_SVE_FPCR_OFFSET(vq) + SVE_PT_SVE_FPCR_SIZE; end = SVE_PT_SVE_FPCR_OFFSET(vq) + SVE_PT_SVE_FPCR_SIZE;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&target->thread.fpsimd_state.fpsr, &target->thread.uw.fpsimd_state.fpsr,
start, end); start, end);
out: out:
...@@ -1169,7 +1169,7 @@ static int compat_vfp_get(struct task_struct *target, ...@@ -1169,7 +1169,7 @@ static int compat_vfp_get(struct task_struct *target,
compat_ulong_t fpscr; compat_ulong_t fpscr;
int ret, vregs_end_pos; int ret, vregs_end_pos;
uregs = &target->thread.fpsimd_state; uregs = &target->thread.uw.fpsimd_state;
if (target == current) if (target == current)
fpsimd_preserve_current_state(); fpsimd_preserve_current_state();
...@@ -1202,7 +1202,7 @@ static int compat_vfp_set(struct task_struct *target, ...@@ -1202,7 +1202,7 @@ static int compat_vfp_set(struct task_struct *target,
compat_ulong_t fpscr; compat_ulong_t fpscr;
int ret, vregs_end_pos; int ret, vregs_end_pos;
uregs = &target->thread.fpsimd_state; uregs = &target->thread.uw.fpsimd_state;
vregs_end_pos = VFP_STATE_SIZE - sizeof(compat_ulong_t); vregs_end_pos = VFP_STATE_SIZE - sizeof(compat_ulong_t);
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0, ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0,
...@@ -1225,7 +1225,7 @@ static int compat_tls_get(struct task_struct *target, ...@@ -1225,7 +1225,7 @@ static int compat_tls_get(struct task_struct *target,
const struct user_regset *regset, unsigned int pos, const struct user_regset *regset, unsigned int pos,
unsigned int count, void *kbuf, void __user *ubuf) unsigned int count, void *kbuf, void __user *ubuf)
{ {
compat_ulong_t tls = (compat_ulong_t)target->thread.tp_value; compat_ulong_t tls = (compat_ulong_t)target->thread.uw.tp_value;
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &tls, 0, -1); return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
} }
...@@ -1235,13 +1235,13 @@ static int compat_tls_set(struct task_struct *target, ...@@ -1235,13 +1235,13 @@ static int compat_tls_set(struct task_struct *target,
const void __user *ubuf) const void __user *ubuf)
{ {
int ret; int ret;
compat_ulong_t tls = target->thread.tp_value; compat_ulong_t tls = target->thread.uw.tp_value;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &tls, 0, -1); ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
if (ret) if (ret)
return ret; return ret;
target->thread.tp_value = tls; target->thread.uw.tp_value = tls;
return ret; return ret;
} }
...@@ -1538,7 +1538,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, ...@@ -1538,7 +1538,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
break; break;
case COMPAT_PTRACE_GET_THREAD_AREA: case COMPAT_PTRACE_GET_THREAD_AREA:
ret = put_user((compat_ulong_t)child->thread.tp_value, ret = put_user((compat_ulong_t)child->thread.uw.tp_value,
(compat_ulong_t __user *)datap); (compat_ulong_t __user *)datap);
break; break;
......
...@@ -179,7 +179,8 @@ static void __user *apply_user_offset( ...@@ -179,7 +179,8 @@ static void __user *apply_user_offset(
static int preserve_fpsimd_context(struct fpsimd_context __user *ctx) static int preserve_fpsimd_context(struct fpsimd_context __user *ctx)
{ {
struct user_fpsimd_state const *fpsimd = &current->thread.fpsimd_state; struct user_fpsimd_state const *fpsimd =
&current->thread.uw.fpsimd_state;
int err; int err;
/* copy the FP and status/control registers */ /* copy the FP and status/control registers */
......
...@@ -149,7 +149,8 @@ union __fpsimd_vreg { ...@@ -149,7 +149,8 @@ union __fpsimd_vreg {
static int compat_preserve_vfp_context(struct compat_vfp_sigframe __user *frame) static int compat_preserve_vfp_context(struct compat_vfp_sigframe __user *frame)
{ {
struct user_fpsimd_state const *fpsimd = &current->thread.fpsimd_state; struct user_fpsimd_state const *fpsimd =
&current->thread.uw.fpsimd_state;
compat_ulong_t magic = VFP_MAGIC; compat_ulong_t magic = VFP_MAGIC;
compat_ulong_t size = VFP_STORAGE_SIZE; compat_ulong_t size = VFP_STORAGE_SIZE;
compat_ulong_t fpscr, fpexc; compat_ulong_t fpscr, fpexc;
......
...@@ -90,7 +90,7 @@ long compat_arm_syscall(struct pt_regs *regs) ...@@ -90,7 +90,7 @@ long compat_arm_syscall(struct pt_regs *regs)
return do_compat_cache_op(regs->regs[0], regs->regs[1], regs->regs[2]); return do_compat_cache_op(regs->regs[0], regs->regs[1], regs->regs[2]);
case __ARM_NR_compat_set_tls: case __ARM_NR_compat_set_tls:
current->thread.tp_value = regs->regs[0]; current->thread.uw.tp_value = regs->regs[0];
/* /*
* Protect against register corruption from context switch. * Protect against register corruption from context switch.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment