um: Implement copy_thread_tls
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>
This commit is contained in:
parent
dd499f7a7e
commit
457677c70c
5 changed files with 10 additions and 12 deletions
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -153,8 +153,8 @@ void fork_handler(void)
|
||||||
userspace(¤t->thread.regs.regs, current_thread_info()->aux_fp_regs);
|
userspace(¤t->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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue