mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-09-22 11:30:01 +08:00
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>
This commit is contained in:
@@ -514,14 +514,14 @@ pid_t lwp_execve(char *filename, int debug, int argc, char **argv, char **envp)
|
||||
|
||||
if ((tid = lwp_tid_get()) == 0)
|
||||
{
|
||||
lwp_ref_dec(lwp);
|
||||
lwp_pid_rollback(lwp);
|
||||
return -ENOMEM;
|
||||
}
|
||||
#ifdef ARCH_MM_MMU
|
||||
if (lwp_user_space_init(lwp, 0) != 0)
|
||||
{
|
||||
lwp_tid_put(tid);
|
||||
lwp_ref_dec(lwp);
|
||||
lwp_pid_rollback(lwp);
|
||||
return -ENOMEM;
|
||||
}
|
||||
#endif
|
||||
@@ -529,7 +529,7 @@ pid_t lwp_execve(char *filename, int debug, int argc, char **argv, char **envp)
|
||||
if ((aux = argscopy(lwp, argc, argv, envp)) == RT_NULL)
|
||||
{
|
||||
lwp_tid_put(tid);
|
||||
lwp_ref_dec(lwp);
|
||||
lwp_pid_rollback(lwp);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@@ -629,7 +629,7 @@ pid_t lwp_execve(char *filename, int debug, int argc, char **argv, char **envp)
|
||||
}
|
||||
|
||||
lwp_tid_put(tid);
|
||||
lwp_ref_dec(lwp);
|
||||
lwp_pid_rollback(lwp);
|
||||
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
@@ -335,6 +335,35 @@ void lwp_pid_put(struct rt_lwp *lwp)
|
||||
lwp_ref_dec(lwp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Roll back a PID allocated for a process that never became runnable.
|
||||
*
|
||||
* @param[in,out] lwp The lightweight process whose PID allocation should be
|
||||
* undone. The LWP must have been allocated a PID, but must
|
||||
* not have been made visible as a runnable user task.
|
||||
*
|
||||
* @note This helper is intended for exec/spawn failure paths after PID
|
||||
* allocation and before task startup. It removes the PID table entry,
|
||||
* clears lwp->pid, and drops the initial LWP reference.
|
||||
*
|
||||
* Do not use lwp_pid_put() for this case. lwp_pid_put() has process-exit
|
||||
* semantics: when the PID tree becomes empty it wakes waiters and keeps
|
||||
* the PID lock held to prevent new PID allocation. A failed exec rollback
|
||||
* must release the PID lock unconditionally so later LWP launches can
|
||||
* still allocate PIDs, especially in init-less boot flows.
|
||||
*/
|
||||
void lwp_pid_rollback(struct rt_lwp *lwp)
|
||||
{
|
||||
_free_proc_dentry(lwp);
|
||||
|
||||
lwp_pid_lock_take();
|
||||
lwp_pid_put_locked(lwp->pid);
|
||||
lwp_pid_lock_release();
|
||||
|
||||
lwp->pid = 0;
|
||||
lwp_ref_dec(lwp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the LWP for a given PID while holding the PID lock
|
||||
*
|
||||
|
||||
@@ -29,6 +29,7 @@ int lwp_pid_init(void);
|
||||
int lwp_pid_wait_for_empty(int wait_flags, rt_tick_t to);
|
||||
int lwp_pid_for_each(int (*cb)(pid_t pid, void *data), void *data);
|
||||
void lwp_pid_put(struct rt_lwp *lwp);
|
||||
void lwp_pid_rollback(struct rt_lwp *lwp);
|
||||
void lwp_pid_lock_take(void);
|
||||
void lwp_pid_lock_release(void);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user