Commit 1ec6574a authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'kthread-cleanups-for-v5.19' of...

Merge tag 'kthread-cleanups-for-v5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace

Pull kthread updates from Eric Biederman:
 "This updates init and user mode helper tasks to be ordinary user mode
  tasks.

  Commit 40966e31 ("kthread: Ensure struct kthread is present for
  all kthreads") caused init and the user mode helper threads that call
  kernel_execve to have struct kthread allocated for them. This struct
  kthread going away during execve in turned made a use after free of
  struct kthread possible.

  Here, commit 343f4c49 ("kthread: Don't allocate kthread_struct for
  init and umh") is enough to fix the use after free and is simple
  enough to be backportable.

  The rest of the changes pass struct kernel_clone_args to clean things
  up and cause the code to make sense.

  In making init and the user mode helpers tasks purely user mode tasks
  I ran into two complications. The function task_tick_numa was
  detecting tasks without an mm by testing for the presence of
  PF_KTHREAD. The initramfs code in populate_initrd_image was using
  flush_delayed_fput to ensuere the closing of all it's file descriptors
  was complete, and flush_delayed_fput does not work in a userspace
  thread.

  I have looked and looked and more complications and in my code review
  I have not found any, and neither has anyone else with the code
  sitting in linux-next"

* tag 'kthread-cleanups-for-v5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace:
  sched: Update task_tick_numa to ignore tasks without an mm
  fork: Stop allowing kthreads to call execve
  fork: Explicitly set PF_KTHREAD
  init: Deal with the init process being a user mode process
  fork: Generalize PF_IO_WORKER handling
  fork: Explicity test for idle tasks in copy_thread
  fork: Pass struct kernel_clone_args into copy_thread
  kthread: Don't allocate kthread_struct for init and umh
parents 1888e9b4 b3f9916d
Loading
Loading
Loading
Loading
+7 −6
Original line number Diff line number Diff line
@@ -233,10 +233,11 @@ release_thread(struct task_struct *dead_task)
/*
 * Copy architecture-specific thread state
 */
int copy_thread(unsigned long clone_flags, unsigned long usp,
		unsigned long kthread_arg, struct task_struct *p,
		unsigned long tls)
int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
{
	unsigned long clone_flags = args->flags;
	unsigned long usp = args->stack;
	unsigned long tls = args->tls;
	extern void ret_from_fork(void);
	extern void ret_from_kernel_thread(void);

@@ -249,13 +250,13 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
	childti->pcb.ksp = (unsigned long) childstack;
	childti->pcb.flags = 1;	/* set FEN, clear everything else */

	if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) {
	if (unlikely(args->fn)) {
		/* kernel thread */
		memset(childstack, 0,
			sizeof(struct switch_stack) + sizeof(struct pt_regs));
		childstack->r26 = (unsigned long) ret_from_kernel_thread;
		childstack->r9 = usp;	/* function */
		childstack->r10 = kthread_arg;
		childstack->r9 = (unsigned long) args->fn;
		childstack->r10 = (unsigned long) args->fn_arg;
		childregs->hae = alpha_mv.hae_cache;
		childti->pcb.usp = 0;
		return 0;
+7 −6
Original line number Diff line number Diff line
@@ -162,10 +162,11 @@ asmlinkage void ret_from_fork(void);
 * |    user_r25    |
 * ------------------  <===== END of PAGE
 */
int copy_thread(unsigned long clone_flags, unsigned long usp,
		unsigned long kthread_arg, struct task_struct *p,
		unsigned long tls)
int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
{
	unsigned long clone_flags = args->flags;
	unsigned long usp = args->stack;
	unsigned long tls = args->tls;
	struct pt_regs *c_regs;        /* child's pt_regs */
	unsigned long *childksp;       /* to unwind out of __switch_to() */
	struct callee_regs *c_callee;  /* child's callee regs */
@@ -191,11 +192,11 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
	childksp[0] = 0;			/* fp */
	childksp[1] = (unsigned long)ret_from_fork; /* blink */

	if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) {
	if (unlikely(args->fn)) {
		memset(c_regs, 0, sizeof(struct pt_regs));

		c_callee->r13 = kthread_arg;
		c_callee->r14 = usp;  /* function */
		c_callee->r13 = (unsigned long)args->fn_arg;
		c_callee->r14 = (unsigned long)args->fn;

		return 0;
	}
+7 −5
Original line number Diff line number Diff line
@@ -238,9 +238,11 @@ void release_thread(struct task_struct *dead_task)

asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");

int copy_thread(unsigned long clone_flags, unsigned long stack_start,
		unsigned long stk_sz, struct task_struct *p, unsigned long tls)
int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
{
	unsigned long clone_flags = args->flags;
	unsigned long stack_start = args->stack;
	unsigned long tls = args->tls;
	struct thread_info *thread = task_thread_info(p);
	struct pt_regs *childregs = task_pt_regs(p);

@@ -256,15 +258,15 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
	thread->cpu_domain = get_domain();
#endif

	if (likely(!(p->flags & (PF_KTHREAD | PF_IO_WORKER)))) {
	if (likely(!args->fn)) {
		*childregs = *current_pt_regs();
		childregs->ARM_r0 = 0;
		if (stack_start)
			childregs->ARM_sp = stack_start;
	} else {
		memset(childregs, 0, sizeof(struct pt_regs));
		thread->cpu_context.r4 = stk_sz;
		thread->cpu_context.r5 = stack_start;
		thread->cpu_context.r4 = (unsigned long)args->fn_arg;
		thread->cpu_context.r5 = (unsigned long)args->fn;
		childregs->ARM_cpsr = SVC_MODE;
	}
	thread->cpu_context.pc = (unsigned long)ret_from_fork;
+7 −5
Original line number Diff line number Diff line
@@ -343,9 +343,11 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)

asmlinkage void ret_from_fork(void) asm("ret_from_fork");

int copy_thread(unsigned long clone_flags, unsigned long stack_start,
		unsigned long stk_sz, struct task_struct *p, unsigned long tls)
int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
{
	unsigned long clone_flags = args->flags;
	unsigned long stack_start = args->stack;
	unsigned long tls = args->tls;
	struct pt_regs *childregs = task_pt_regs(p);

	memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context));
@@ -361,7 +363,7 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,

	ptrauth_thread_init_kernel(p);

	if (likely(!(p->flags & (PF_KTHREAD | PF_IO_WORKER)))) {
	if (likely(!args->fn)) {
		*childregs = *current_pt_regs();
		childregs->regs[0] = 0;

@@ -399,8 +401,8 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
		memset(childregs, 0, sizeof(struct pt_regs));
		childregs->pstate = PSR_MODE_EL1h | PSR_IL_BIT;

		p->thread.cpu_context.x19 = stack_start;
		p->thread.cpu_context.x20 = stk_sz;
		p->thread.cpu_context.x19 = (unsigned long)args->fn;
		p->thread.cpu_context.x20 = (unsigned long)args->fn_arg;
	}
	p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
	p->thread.cpu_context.sp = (unsigned long)childregs;
+7 −8
Original line number Diff line number Diff line
@@ -29,12 +29,11 @@ asmlinkage void ret_from_kernel_thread(void);
 */
void flush_thread(void){}

int copy_thread(unsigned long clone_flags,
		unsigned long usp,
		unsigned long kthread_arg,
		struct task_struct *p,
		unsigned long tls)
int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
{
	unsigned long clone_flags = args->flags;
	unsigned long usp = args->stack;
	unsigned long tls = args->tls;
	struct switch_stack *childstack;
	struct pt_regs *childregs = task_pt_regs(p);

@@ -48,11 +47,11 @@ int copy_thread(unsigned long clone_flags,
	/* setup thread.sp for switch_to !!! */
	p->thread.sp = (unsigned long)childstack;

	if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) {
	if (unlikely(args->fn)) {
		memset(childregs, 0, sizeof(struct pt_regs));
		childstack->r15 = (unsigned long) ret_from_kernel_thread;
		childstack->r10 = kthread_arg;
		childstack->r9 = usp;
		childstack->r10 = (unsigned long) args->fn_arg;
		childstack->r9 = (unsigned long) args->fn;
		childregs->sr = mfcr("psr");
	} else {
		*childregs = *(current_pt_regs());
Loading