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:
yang.zhang
2026-05-26 16:56:36 +08:00
committed by Rbb666
parent 208a09e074
commit d4f4c50b9e
3 changed files with 34 additions and 4 deletions
+4 -4
View File
@@ -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;
}
+29
View File
@@ -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
*
+1
View File
@@ -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);