Skip to content

Commit d4f4c50

Browse files
yang.zhangRbb666
authored andcommitted
lwp: fix pid leak on exec failure before task startup
When msh tries to execute a non-ELF path, lwp_execve() may allocate a PID before lwp_load() fails. The old error path only dropped the LWP reference, leaving the PID tree entry pointing to a freed LWP. In an init-less boot flow, this can poison pid 1 after a failed command from msh. A later LWP launch may then treat the stale pid 1 entry as a valid parent LWP, resulting in invalid pgrp/session state and a job-control assertion during process exit. Add lwp_pid_rollback() for exec/spawn failures before the process becomes runnable. Unlike lwp_pid_put(), it always releases the PID lock and does not enter the "no more pid allocation" state when the PID tree becomes empty. Use the rollback helper in lwp_execve() failure paths after PID allocation. Signed-off-by: zhangyang <gaoshanliukou@163.com>
1 parent 208a09e commit d4f4c50

3 files changed

Lines changed: 34 additions & 4 deletions

File tree

components/lwp/lwp.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -514,22 +514,22 @@ pid_t lwp_execve(char *filename, int debug, int argc, char **argv, char **envp)
514514

515515
if ((tid = lwp_tid_get()) == 0)
516516
{
517-
lwp_ref_dec(lwp);
517+
lwp_pid_rollback(lwp);
518518
return -ENOMEM;
519519
}
520520
#ifdef ARCH_MM_MMU
521521
if (lwp_user_space_init(lwp, 0) != 0)
522522
{
523523
lwp_tid_put(tid);
524-
lwp_ref_dec(lwp);
524+
lwp_pid_rollback(lwp);
525525
return -ENOMEM;
526526
}
527527
#endif
528528

529529
if ((aux = argscopy(lwp, argc, argv, envp)) == RT_NULL)
530530
{
531531
lwp_tid_put(tid);
532-
lwp_ref_dec(lwp);
532+
lwp_pid_rollback(lwp);
533533
return -ENOMEM;
534534
}
535535

@@ -629,7 +629,7 @@ pid_t lwp_execve(char *filename, int debug, int argc, char **argv, char **envp)
629629
}
630630

631631
lwp_tid_put(tid);
632-
lwp_ref_dec(lwp);
632+
lwp_pid_rollback(lwp);
633633

634634
return -RT_ERROR;
635635
}

components/lwp/lwp_pid.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,35 @@ void lwp_pid_put(struct rt_lwp *lwp)
335335
lwp_ref_dec(lwp);
336336
}
337337

338+
/**
339+
* @brief Roll back a PID allocated for a process that never became runnable.
340+
*
341+
* @param[in,out] lwp The lightweight process whose PID allocation should be
342+
* undone. The LWP must have been allocated a PID, but must
343+
* not have been made visible as a runnable user task.
344+
*
345+
* @note This helper is intended for exec/spawn failure paths after PID
346+
* allocation and before task startup. It removes the PID table entry,
347+
* clears lwp->pid, and drops the initial LWP reference.
348+
*
349+
* Do not use lwp_pid_put() for this case. lwp_pid_put() has process-exit
350+
* semantics: when the PID tree becomes empty it wakes waiters and keeps
351+
* the PID lock held to prevent new PID allocation. A failed exec rollback
352+
* must release the PID lock unconditionally so later LWP launches can
353+
* still allocate PIDs, especially in init-less boot flows.
354+
*/
355+
void lwp_pid_rollback(struct rt_lwp *lwp)
356+
{
357+
_free_proc_dentry(lwp);
358+
359+
lwp_pid_lock_take();
360+
lwp_pid_put_locked(lwp->pid);
361+
lwp_pid_lock_release();
362+
363+
lwp->pid = 0;
364+
lwp_ref_dec(lwp);
365+
}
366+
338367
/**
339368
* @brief Set the LWP for a given PID while holding the PID lock
340369
*

components/lwp/lwp_pid.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ int lwp_pid_init(void);
2929
int lwp_pid_wait_for_empty(int wait_flags, rt_tick_t to);
3030
int lwp_pid_for_each(int (*cb)(pid_t pid, void *data), void *data);
3131
void lwp_pid_put(struct rt_lwp *lwp);
32+
void lwp_pid_rollback(struct rt_lwp *lwp);
3233
void lwp_pid_lock_take(void);
3334
void lwp_pid_lock_release(void);
3435

0 commit comments

Comments
 (0)