Skip to content

Commit 1ec6574

Browse files
committed
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 40966e3 ("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 343f4c4 ("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
2 parents 1888e9b + b3f9916 commit 1ec6574

File tree

32 files changed

+229
-155
lines changed

32 files changed

+229
-155
lines changed

arch/alpha/kernel/process.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -233,10 +233,11 @@ release_thread(struct task_struct *dead_task)
233233
/*
234234
* Copy architecture-specific thread state
235235
*/
236-
int copy_thread(unsigned long clone_flags, unsigned long usp,
237-
unsigned long kthread_arg, struct task_struct *p,
238-
unsigned long tls)
236+
int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
239237
{
238+
unsigned long clone_flags = args->flags;
239+
unsigned long usp = args->stack;
240+
unsigned long tls = args->tls;
240241
extern void ret_from_fork(void);
241242
extern void ret_from_kernel_thread(void);
242243

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

252-
if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) {
253+
if (unlikely(args->fn)) {
253254
/* kernel thread */
254255
memset(childstack, 0,
255256
sizeof(struct switch_stack) + sizeof(struct pt_regs));
256257
childstack->r26 = (unsigned long) ret_from_kernel_thread;
257-
childstack->r9 = usp; /* function */
258-
childstack->r10 = kthread_arg;
258+
childstack->r9 = (unsigned long) args->fn;
259+
childstack->r10 = (unsigned long) args->fn_arg;
259260
childregs->hae = alpha_mv.hae_cache;
260261
childti->pcb.usp = 0;
261262
return 0;

arch/arc/kernel/process.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,11 @@ asmlinkage void ret_from_fork(void);
162162
* | user_r25 |
163163
* ------------------ <===== END of PAGE
164164
*/
165-
int copy_thread(unsigned long clone_flags, unsigned long usp,
166-
unsigned long kthread_arg, struct task_struct *p,
167-
unsigned long tls)
165+
int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
168166
{
167+
unsigned long clone_flags = args->flags;
168+
unsigned long usp = args->stack;
169+
unsigned long tls = args->tls;
169170
struct pt_regs *c_regs; /* child's pt_regs */
170171
unsigned long *childksp; /* to unwind out of __switch_to() */
171172
struct callee_regs *c_callee; /* child's callee regs */
@@ -191,11 +192,11 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
191192
childksp[0] = 0; /* fp */
192193
childksp[1] = (unsigned long)ret_from_fork; /* blink */
193194

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

197-
c_callee->r13 = kthread_arg;
198-
c_callee->r14 = usp; /* function */
198+
c_callee->r13 = (unsigned long)args->fn_arg;
199+
c_callee->r14 = (unsigned long)args->fn;
199200

200201
return 0;
201202
}

arch/arm/kernel/process.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -238,9 +238,11 @@ void release_thread(struct task_struct *dead_task)
238238

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

241-
int copy_thread(unsigned long clone_flags, unsigned long stack_start,
242-
unsigned long stk_sz, struct task_struct *p, unsigned long tls)
241+
int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
243242
{
243+
unsigned long clone_flags = args->flags;
244+
unsigned long stack_start = args->stack;
245+
unsigned long tls = args->tls;
244246
struct thread_info *thread = task_thread_info(p);
245247
struct pt_regs *childregs = task_pt_regs(p);
246248

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

259-
if (likely(!(p->flags & (PF_KTHREAD | PF_IO_WORKER)))) {
261+
if (likely(!args->fn)) {
260262
*childregs = *current_pt_regs();
261263
childregs->ARM_r0 = 0;
262264
if (stack_start)
263265
childregs->ARM_sp = stack_start;
264266
} else {
265267
memset(childregs, 0, sizeof(struct pt_regs));
266-
thread->cpu_context.r4 = stk_sz;
267-
thread->cpu_context.r5 = stack_start;
268+
thread->cpu_context.r4 = (unsigned long)args->fn_arg;
269+
thread->cpu_context.r5 = (unsigned long)args->fn;
268270
childregs->ARM_cpsr = SVC_MODE;
269271
}
270272
thread->cpu_context.pc = (unsigned long)ret_from_fork;

arch/arm64/kernel/process.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -343,9 +343,11 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
343343

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

346-
int copy_thread(unsigned long clone_flags, unsigned long stack_start,
347-
unsigned long stk_sz, struct task_struct *p, unsigned long tls)
346+
int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
348347
{
348+
unsigned long clone_flags = args->flags;
349+
unsigned long stack_start = args->stack;
350+
unsigned long tls = args->tls;
349351
struct pt_regs *childregs = task_pt_regs(p);
350352

351353
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,
361363

362364
ptrauth_thread_init_kernel(p);
363365

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

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

402-
p->thread.cpu_context.x19 = stack_start;
403-
p->thread.cpu_context.x20 = stk_sz;
404+
p->thread.cpu_context.x19 = (unsigned long)args->fn;
405+
p->thread.cpu_context.x20 = (unsigned long)args->fn_arg;
404406
}
405407
p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
406408
p->thread.cpu_context.sp = (unsigned long)childregs;

arch/csky/kernel/process.c

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,11 @@ asmlinkage void ret_from_kernel_thread(void);
2929
*/
3030
void flush_thread(void){}
3131

32-
int copy_thread(unsigned long clone_flags,
33-
unsigned long usp,
34-
unsigned long kthread_arg,
35-
struct task_struct *p,
36-
unsigned long tls)
32+
int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
3733
{
34+
unsigned long clone_flags = args->flags;
35+
unsigned long usp = args->stack;
36+
unsigned long tls = args->tls;
3837
struct switch_stack *childstack;
3938
struct pt_regs *childregs = task_pt_regs(p);
4039

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

51-
if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) {
50+
if (unlikely(args->fn)) {
5251
memset(childregs, 0, sizeof(struct pt_regs));
5352
childstack->r15 = (unsigned long) ret_from_kernel_thread;
54-
childstack->r10 = kthread_arg;
55-
childstack->r9 = usp;
53+
childstack->r10 = (unsigned long) args->fn_arg;
54+
childstack->r9 = (unsigned long) args->fn;
5655
childregs->sr = mfcr("psr");
5756
} else {
5857
*childregs = *(current_pt_regs());

arch/hexagon/kernel/process.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,11 @@ void arch_cpu_idle(void)
5050
/*
5151
* Copy architecture-specific thread state
5252
*/
53-
int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg,
54-
struct task_struct *p, unsigned long tls)
53+
int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
5554
{
55+
unsigned long clone_flags = args->flags;
56+
unsigned long usp = args->stack;
57+
unsigned long tls = args->tls;
5658
struct thread_info *ti = task_thread_info(p);
5759
struct hexagon_switch_stack *ss;
5860
struct pt_regs *childregs;
@@ -73,11 +75,11 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg,
7375
sizeof(*ss));
7476
ss->lr = (unsigned long)ret_from_fork;
7577
p->thread.switch_sp = ss;
76-
if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) {
78+
if (unlikely(args->fn)) {
7779
memset(childregs, 0, sizeof(struct pt_regs));
7880
/* r24 <- fn, r25 <- arg */
79-
ss->r24 = usp;
80-
ss->r25 = arg;
81+
ss->r24 = (unsigned long)args->fn;
82+
ss->r25 = (unsigned long)args->fn_arg;
8183
pt_set_kmode(childregs);
8284
return 0;
8385
}

arch/ia64/kernel/process.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -296,9 +296,12 @@ ia64_load_extra (struct task_struct *task)
296296
* so there is nothing to worry about.
297297
*/
298298
int
299-
copy_thread(unsigned long clone_flags, unsigned long user_stack_base,
300-
unsigned long user_stack_size, struct task_struct *p, unsigned long tls)
299+
copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
301300
{
301+
unsigned long clone_flags = args->flags;
302+
unsigned long user_stack_base = args->stack;
303+
unsigned long user_stack_size = args->stack_size;
304+
unsigned long tls = args->tls;
302305
extern char ia64_ret_from_clone;
303306
struct switch_stack *child_stack, *stack;
304307
unsigned long rbs, child_rbs, rbs_size;
@@ -339,14 +342,14 @@ copy_thread(unsigned long clone_flags, unsigned long user_stack_base,
339342

340343
ia64_drop_fpu(p); /* don't pick up stale state from a CPU's fph */
341344

342-
if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) {
343-
if (unlikely(!user_stack_base)) {
345+
if (unlikely(args->fn)) {
346+
if (unlikely(args->idle)) {
344347
/* fork_idle() called us */
345348
return 0;
346349
}
347350
memset(child_stack, 0, sizeof(*child_ptregs) + sizeof(*child_stack));
348-
child_stack->r4 = user_stack_base; /* payload */
349-
child_stack->r5 = user_stack_size; /* argument */
351+
child_stack->r4 = (unsigned long) args->fn;
352+
child_stack->r5 = (unsigned long) args->fn_arg;
350353
/*
351354
* Preserve PSR bits, except for bits 32-34 and 37-45,
352355
* which we can't read.

arch/m68k/kernel/process.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,11 @@ asmlinkage int m68k_clone3(struct pt_regs *regs)
137137
return sys_clone3((struct clone_args __user *)regs->d1, regs->d2);
138138
}
139139

140-
int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg,
141-
struct task_struct *p, unsigned long tls)
140+
int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
142141
{
142+
unsigned long clone_flags = args->flags;
143+
unsigned long usp = args->stack;
144+
unsigned long tls = args->tls;
143145
struct fork_frame {
144146
struct switch_stack sw;
145147
struct pt_regs regs;
@@ -156,12 +158,12 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg,
156158
*/
157159
p->thread.fc = USER_DATA;
158160

159-
if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) {
161+
if (unlikely(args->fn)) {
160162
/* kernel thread */
161163
memset(frame, 0, sizeof(struct fork_frame));
162164
frame->regs.sr = PS_S;
163-
frame->sw.a3 = usp; /* function */
164-
frame->sw.d7 = arg;
165+
frame->sw.a3 = (unsigned long)args->fn;
166+
frame->sw.d7 = (unsigned long)args->fn_arg;
165167
frame->sw.retpc = (unsigned long)ret_from_kernel_thread;
166168
p->thread.usp = 0;
167169
return 0;

arch/microblaze/kernel/process.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,20 +52,22 @@ void flush_thread(void)
5252
{
5353
}
5454

55-
int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg,
56-
struct task_struct *p, unsigned long tls)
55+
int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
5756
{
57+
unsigned long clone_flags = args->flags;
58+
unsigned long usp = args->stack;
59+
unsigned long tls = args->tls;
5860
struct pt_regs *childregs = task_pt_regs(p);
5961
struct thread_info *ti = task_thread_info(p);
6062

61-
if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) {
63+
if (unlikely(args->fn)) {
6264
/* if we're creating a new kernel thread then just zeroing all
6365
* the registers. That's OK for a brand new thread.*/
6466
memset(childregs, 0, sizeof(struct pt_regs));
6567
memset(&ti->cpu_context, 0, sizeof(struct cpu_context));
6668
ti->cpu_context.r1 = (unsigned long)childregs;
67-
ti->cpu_context.r20 = (unsigned long)usp; /* fn */
68-
ti->cpu_context.r19 = (unsigned long)arg;
69+
ti->cpu_context.r20 = (unsigned long)args->fn;
70+
ti->cpu_context.r19 = (unsigned long)args->fn_arg;
6971
childregs->pt_mode = 1;
7072
local_save_flags(childregs->msr);
7173
ti->cpu_context.msr = childregs->msr & ~MSR_IE;

arch/mips/kernel/process.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,11 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
105105
/*
106106
* Copy architecture-specific thread state
107107
*/
108-
int copy_thread(unsigned long clone_flags, unsigned long usp,
109-
unsigned long kthread_arg, struct task_struct *p,
110-
unsigned long tls)
108+
int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
111109
{
110+
unsigned long clone_flags = args->flags;
111+
unsigned long usp = args->stack;
112+
unsigned long tls = args->tls;
112113
struct thread_info *ti = task_thread_info(p);
113114
struct pt_regs *childregs, *regs = current_pt_regs();
114115
unsigned long childksp;
@@ -120,12 +121,12 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
120121
/* Put the stack after the struct pt_regs. */
121122
childksp = (unsigned long) childregs;
122123
p->thread.cp0_status = (read_c0_status() & ~(ST0_CU2|ST0_CU1)) | ST0_KERNEL_CUMASK;
123-
if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) {
124+
if (unlikely(args->fn)) {
124125
/* kernel thread */
125126
unsigned long status = p->thread.cp0_status;
126127
memset(childregs, 0, sizeof(struct pt_regs));
127-
p->thread.reg16 = usp; /* fn */
128-
p->thread.reg17 = kthread_arg;
128+
p->thread.reg16 = (unsigned long)args->fn;
129+
p->thread.reg17 = (unsigned long)args->fn_arg;
129130
p->thread.reg29 = childksp;
130131
p->thread.reg31 = (unsigned long) ret_from_kernel_thread;
131132
#if defined(CONFIG_CPU_R3000)

0 commit comments

Comments
 (0)