Date: Tue, 16 Jun 2026 22:23:15 +0000 From: bugzilla-noreply@freebsd.org To: bugs@FreeBSD.org Subject: [Bug 295991] lib/libc posix_spawnp(): PATH-search child runs on an undersized rfork_thread stack and underflows into the caller's heap (heavily-linked processes; PHP proc_open) Message-ID: <bug-295991-227-7MZkVyBDe7@https.bugs.freebsd.org/bugzilla/> In-Reply-To: <bug-295991-227@https.bugs.freebsd.org/bugzilla/>
index | next in thread | previous in thread | raw e-mail
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=295991 Bryan Drewery <bdrewery@FreeBSD.org> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |bdrewery@FreeBSD.org --- Comment #2 from Bryan Drewery <bdrewery@FreeBSD.org> --- The report is an unreadable AI mess but the point is that there is some random corruption that shows up with php on exit when loaded with many extensions. Raising the stack size in posix_spawn avoids the problem. This shows up easily with www/nextcloud port running `occ status` in a loop. The proc_open repro isn't reliable as it depends on some random mechanism and how many extensions are loaded. https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=289425 and https://github.com/php/php-src/issues/21995 have more details. https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=289425#c22 shows some ways it manifests at shutdown. The revert of the xsl shutdown function was a hack that attempted to avoid the root cause but does not. Based on the initial report this AI-generated code avoids the problem by using a 1MB stack size. ``` /* cc -O2 -fPIC -shared -Wall -o /usr/local/libexec/spawnstack.so spawnstack.c */ #include <sys/param.h> #include <sys/mman.h> #include <unistd.h> #include <stdlib.h> #include <dlfcn.h> typedef pid_t (*rfork_thread_t)(int, void *, int (*)(void *), void *); #if __FreeBSD_version >= 1600000 typedef pid_t (*pdrfork_thread_t)(int *, int, int, void *, int (*)(void *), void *); #endif static rfork_thread_t sys_rfork_thread; #if __FreeBSD_version >= 1600000 static pdrfork_thread_t sys_pdrfork_thread; #endif static size_t guard; static size_t depth; __attribute__((constructor)) static void spawnstack_init(void) { const char *s; char *end; long ps; unsigned long kb; sys_rfork_thread = (rfork_thread_t)dlsym(RTLD_NEXT, "rfork_thread"); #if __FreeBSD_version >= 1600000 sys_pdrfork_thread = (pdrfork_thread_t)dlsym(RTLD_NEXT, "pdrfork_thread"); #endif ps = sysconf(_SC_PAGESIZE); guard = ps > 0 ? (size_t)ps : 4096; kb = 1024; s = getenv("LIBC_SPAWN_STACK_KB"); if (s != NULL && *s != '\0') { unsigned long v = strtoul(s, &end, 10); if (*end == '\0' && v >= 64) kb = v; } depth = (kb * 1024 + guard - 1) & ~(guard - 1); } static void * spawnstack_alloc(size_t *len) { char *p; *len = guard + depth; p = mmap(NULL, *len, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); if (p == MAP_FAILED) return (NULL); (void)mprotect(p, guard, PROT_NONE); return (p + *len); } pid_t rfork_thread(int flags, void *stack, int (*func)(void *), void *arg) { void *top; size_t len; pid_t pid; if ((flags & RFSPAWN) == 0 || stack == NULL) return (sys_rfork_thread(flags, stack, func, arg)); top = spawnstack_alloc(&len); if (top == NULL) return (sys_rfork_thread(flags, stack, func, arg)); pid = sys_rfork_thread(flags, top, func, arg); (void)munmap((char *)top - len, len); return (pid); } #if __FreeBSD_version >= 1600000 pid_t pdrfork_thread(int *fdp, int pdflags, int rfflags, void *stack, int (*func)(void *), void *arg) { void *top; size_t len; pid_t pid; if ((rfflags & RFSPAWN) == 0 || stack == NULL) return (sys_pdrfork_thread(fdp, pdflags, rfflags, stack, func, arg)); top = spawnstack_alloc(&len); if (top == NULL) return (sys_pdrfork_thread(fdp, pdflags, rfflags, stack, func, arg)); pid = sys_pdrfork_thread(fdp, pdflags, rfflags, top, func, arg); (void)munmap((char *)top - len, len); return (pid); } #endif ``` /usr/local/bin/occ needs LD_PRELOAD added in. ``` #!/bin/sh args= for arg in "$@" ; do if [ "${arg#* }" != "${arg}" ] ; then args="${args} '${arg}'" else args="${args} ${arg}" fi done ( cd /home/nextcloud/public_html/nextcloud su -m www -c \ "/usr/bin/env LD_PRELOAD=/usr/local/libexec/spawnstack.so /usr/local/bin/php --define apc.enable_cli=1 /home/nextcloud/public_html/nextcloud/occ ${args}" ) ``` -- You are receiving this mail because: You are the assignee for the bug.home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?bug-295991-227-7MZkVyBDe7>
