Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8c9ff5c7 authored by Amanieu d'Antras's avatar Amanieu d'Antras Committed by Greg Kroah-Hartman
Browse files

um: Implement copy_thread_tls



commit 457677c70c7672a4586b0b8abc396cc1ecdd376d upstream.

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

Signed-off-by: default avatarAmanieu 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: default avatarChristian Brauner <christian.brauner@ubuntu.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 4f43cdc7
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@ config UML
	select HAVE_FUTEX_CMPXCHG if FUTEX
	select HAVE_DEBUG_KMEMLEAK
	select HAVE_DEBUG_BUGVERBOSE
	select HAVE_COPY_THREAD_TLS
	select GENERIC_IRQ_SHOW
	select GENERIC_CPU_DEVICES
	select GENERIC_CLOCKEVENTS
+1 −1
Original line number Diff line number Diff line
@@ -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 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 int syscall_trace_enter(struct pt_regs *regs);
extern void syscall_trace_leave(struct pt_regs *regs);
+3 −3
Original line number Diff line number Diff line
@@ -153,8 +153,8 @@ void fork_handler(void)
	userspace(&current->thread.regs.regs, current_thread_info()->aux_fp_regs);
}

int copy_thread(unsigned long clone_flags, unsigned long sp,
		unsigned long arg, struct task_struct * p)
int copy_thread_tls(unsigned long clone_flags, unsigned long sp,
		unsigned long arg, struct task_struct * p, unsigned long tls)
{
	void (*handler)(void);
	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?
		 */
		if (clone_flags & CLONE_SETTLS)
			ret = arch_copy_tls(p);
			ret = arch_set_tls(p, tls);
	}

	return ret;
+2 −4
Original line number Diff line number Diff line
@@ -215,14 +215,12 @@ static int set_tls_entry(struct task_struct* task, struct user_desc *info,
	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;
	int idx, ret = -EFAULT;

	if (copy_from_user(&info,
			   (void __user *) UPT_SI(&new->thread.regs.regs),
			   sizeof(info)))
	if (copy_from_user(&info, (void __user *) tls, sizeof(info)))
		goto out;

	ret = -EINVAL;
+3 −4
Original line number Diff line number Diff line
@@ -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
	 * (which is argument 5, child_tid, of clone) so it can be set
	 * during context switches.
	 * so it can be set during context switches.
	 */
	t->thread.arch.fs = t->thread.regs.regs.gp[R8 / sizeof(long)];
	t->thread.arch.fs = tls;

	return 0;
}