From 0f906993b8b17088af06e4b25ee74c2c158bc24c Mon Sep 17 00:00:00 2001 From: "yang.zhang" Date: Sun, 3 May 2026 08:58:55 +0800 Subject: [PATCH 1/2] 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 --- components/lwp/lwp.c | 8 ++++---- components/lwp/lwp_pid.c | 29 +++++++++++++++++++++++++++++ components/lwp/lwp_pid.h | 1 + 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/components/lwp/lwp.c b/components/lwp/lwp.c index 4e589788993..f3841bb4c10 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 c992f1da8c3..82f205a694e 100644 --- a/components/lwp/lwp_pid.c +++ b/components/lwp/lwp_pid.c @@ -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 * diff --git a/components/lwp/lwp_pid.h b/components/lwp/lwp_pid.h index 4901fd4392d..5b85b321977 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); From 4b4a6b0d3a9d0aa97cacb0e5df60df646875eb6a Mon Sep 17 00:00:00 2001 From: zhangyangysu Date: Wed, 1 Jul 2026 14:26:39 +0800 Subject: [PATCH 2/2] [drivers][sdio] avoid SDHCI device name stack overflow rt_sdhci_init_host() allocated a fixed 32-byte buffer for device-derived object names, but sdio_host_set_name() may copy up to RT_NAME_MAX bytes into the output buffer. When RT_NAME_MAX is larger than 32, this can overwrite the stack and corrupt nearby locals. Size the temporary name buffer with RT_NAME_MAX, force it to be NUL-terminated, and derive the append offset from the actual string length. Also replace the suffix rt_sprintf() calls with bounded rt_snprintf() so timer and workqueue suffixes cannot overflow the buffer when the base name is already close to RT_NAME_MAX. Signed-off-by: zhangyangysu --- components/drivers/sdio/dev_sdhci.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/components/drivers/sdio/dev_sdhci.c b/components/drivers/sdio/dev_sdhci.c index c8fd0646fa2..6fbe13b1857 100755 --- a/components/drivers/sdio/dev_sdhci.c +++ b/components/drivers/sdio/dev_sdhci.c @@ -3535,10 +3535,12 @@ static void sdhci_reinit(struct rt_sdhci_host *host) int rt_sdhci_init_host(struct rt_sdhci_host *host) { int ret, len; - char dev_name[32]; + char dev_name[RT_NAME_MAX]; struct rt_mmc_host *mmc = host->mmc; len = sdio_host_set_name(&mmc->rthost, dev_name); + dev_name[sizeof(dev_name) - 1] = '\0'; + len = rt_strlen(dev_name); if ((mmc->caps2 & MMC_CAP2_CQE) && (host->quirks & RT_SDHCI_QUIRK_BROKEN_CQE)) { @@ -3553,10 +3555,10 @@ int rt_sdhci_init_host(struct rt_sdhci_host *host) rt_work_init(&host->complete_work, sdhci_complete_work, host); - rt_sprintf(&dev_name[len], "-timer"); + rt_snprintf(&dev_name[len], sizeof(dev_name) - len, "-timer"); rt_timer_init(&host->timer, dev_name, sdhci_timeout_timer, host, 0, RT_TIMER_FLAG_SOFT_TIMER); - rt_sprintf(&dev_name[len], "-data-timer"); + rt_snprintf(&dev_name[len], sizeof(dev_name) - len, "-data-timer"); rt_timer_init(&host->data_timer, dev_name, sdhci_timeout_data_timer, host, 0, RT_TIMER_FLAG_SOFT_TIMER); @@ -3564,7 +3566,7 @@ int rt_sdhci_init_host(struct rt_sdhci_host *host) sdhci_init(host, 0); - rt_sprintf(&dev_name[len], "-irq"); + rt_snprintf(&dev_name[len], sizeof(dev_name) - len, "-irq"); host->irq_wq = rt_workqueue_create(dev_name, RT_SYSTEM_WORKQUEUE_STACKSIZE, 1); rt_work_init(&host->irq_work, sdhci_thread_irq, host); rt_hw_interrupt_install(host->irq, sdhci_irq, host, mmc_hostname(mmc));