summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoryang.zhang <[email protected]>2026-05-03 08:58:55 +0800
committerRbb666 <[email protected]>2026-05-26 16:56:36 +0800
commitd4f4c50b9e60223078a7178e47d338ca484bcbc0 (patch)
treebaeb59660a6014fe26c91b2775c727463d5b0a73
parent208a09e074cf67879b31925ff5d25328781afc2b (diff)
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 <[email protected]>
-rw-r--r--components/lwp/lwp.c8
-rw-r--r--components/lwp/lwp_pid.c29
-rw-r--r--components/lwp/lwp_pid.h1
3 files changed, 34 insertions, 4 deletions
diff --git a/components/lwp/lwp.c b/components/lwp/lwp.c
index 4e58978899..f3841bb4c1 100644
--- a/components/lwp/lwp.c
+++ b/components/lwp/lwp.c
@@ -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;
}
diff --git a/components/lwp/lwp_pid.c b/components/lwp/lwp_pid.c
index c992f1da8c..82f205a694 100644
--- a/components/lwp/lwp_pid.c
+++ b/components/lwp/lwp_pid.c
@@ -336,6 +336,35 @@ void lwp_pid_put(struct rt_lwp *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
*
* @param[in] pid The process ID to set the LWP for
diff --git a/components/lwp/lwp_pid.h b/components/lwp/lwp_pid.h
index 4901fd4392..5b85b32197 100644
--- a/components/lwp/lwp_pid.h
+++ b/components/lwp/lwp_pid.h
@@ -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);