1
0
Fork 0

um: Implement copy_thread_tls

commit 457677c70c upstream.

This is required for clone3 which passes the TLS value through a
struct rather than a register.

Signed-off-by: Amanieu d'Antras <amanieu@gmail.com>
Cc: linux-um@lists.infradead.org
Cc: <stable@vger.kernel.org> # 5.3.x
Link: https://lore.kernel.org/r/20200104123928.1048822-1-amanieu@gmail.com
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
5.4-rM2-2.2.x-imx-squashed
Amanieu d'Antras 2020-01-04 13:39:30 +01:00 committed by Greg Kroah-Hartman
parent 4f43cdc723
commit 8c9ff5c7dd
5 changed files with 10 additions and 12 deletions

View File

@ -14,6 +14,7 @@ config UML
select HAVE_FUTEX_CMPXCHG if FUTEX select HAVE_FUTEX_CMPXCHG if FUTEX
select HAVE_DEBUG_KMEMLEAK select HAVE_DEBUG_KMEMLEAK
select HAVE_DEBUG_BUGVERBOSE select HAVE_DEBUG_BUGVERBOSE
select HAVE_COPY_THREAD_TLS
select GENERIC_IRQ_SHOW select GENERIC_IRQ_SHOW
select GENERIC_CPU_DEVICES select GENERIC_CPU_DEVICES
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS

View File

@ -36,7 +36,7 @@ extern long subarch_ptrace(struct task_struct *child, long request,
extern unsigned long getreg(struct task_struct *child, int regno); extern unsigned long getreg(struct task_struct *child, int regno);
extern int putreg(struct task_struct *child, int regno, unsigned long value); extern int putreg(struct task_struct *child, int regno, unsigned long value);
extern int arch_copy_tls(struct task_struct *new); extern int arch_set_tls(struct task_struct *new, unsigned long tls);
extern void clear_flushed_tls(struct task_struct *task); extern void clear_flushed_tls(struct task_struct *task);
extern int syscall_trace_enter(struct pt_regs *regs); extern int syscall_trace_enter(struct pt_regs *regs);
extern void syscall_trace_leave(struct pt_regs *regs); extern void syscall_trace_leave(struct pt_regs *regs);

View File

@ -153,8 +153,8 @@ void fork_handler(void)
userspace(&current->thread.regs.regs, current_thread_info()->aux_fp_regs); userspace(&current->thread.regs.regs, current_thread_info()->aux_fp_regs);
} }
int copy_thread(unsigned long clone_flags, unsigned long sp, int copy_thread_tls(unsigned long clone_flags, unsigned long sp,
unsigned long arg, struct task_struct * p) unsigned long arg, struct task_struct * p, unsigned long tls)
{ {
void (*handler)(void); void (*handler)(void);
int kthread = current->flags & PF_KTHREAD; int kthread = current->flags & PF_KTHREAD;
@ -188,7 +188,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
* Set a new TLS for the child thread? * Set a new TLS for the child thread?
*/ */
if (clone_flags & CLONE_SETTLS) if (clone_flags & CLONE_SETTLS)
ret = arch_copy_tls(p); ret = arch_set_tls(p, tls);
} }
return ret; return ret;

View File

@ -215,14 +215,12 @@ static int set_tls_entry(struct task_struct* task, struct user_desc *info,
return 0; return 0;
} }
int arch_copy_tls(struct task_struct *new) int arch_set_tls(struct task_struct *new, unsigned long tls)
{ {
struct user_desc info; struct user_desc info;
int idx, ret = -EFAULT; int idx, ret = -EFAULT;
if (copy_from_user(&info, if (copy_from_user(&info, (void __user *) tls, sizeof(info)))
(void __user *) UPT_SI(&new->thread.regs.regs),
sizeof(info)))
goto out; goto out;
ret = -EINVAL; ret = -EINVAL;

View File

@ -6,14 +6,13 @@ void clear_flushed_tls(struct task_struct *task)
{ {
} }
int arch_copy_tls(struct task_struct *t) int arch_set_tls(struct task_struct *t, unsigned long tls)
{ {
/* /*
* If CLONE_SETTLS is set, we need to save the thread id * If CLONE_SETTLS is set, we need to save the thread id
* (which is argument 5, child_tid, of clone) so it can be set * so it can be set during context switches.
* during context switches.
*/ */
t->thread.arch.fs = t->thread.regs.regs.gp[R8 / sizeof(long)]; t->thread.arch.fs = tls;
return 0; return 0;
} }