Re: [PATCH] Replace vfork() with fork() to fix unshare crash on ppc64le
Hello Denys, Thank you for the update.
I checked with the latest changes, the binaries are working fine now. I
am not seeing crash anymore.
On 13/10/25 07:07, Denys Vlasenko wrote:
Please try current git, it contains a fix. Let me know if it doesn't work.
On Mon, Sep 15, 2025 at 7:57 AM tshah wrote:
Hello Denys,
Can you please look into this change and let me know your thoughts on
this once you get chance.
Thanks.
On 09/09/25 15:50, tshah wrote:
Hello,
This patch address the issue:
https://lists.busybox.net/pipermail/busybox/2025-September/091718.html.
The patch replaces the use of vfork() with fork() on MMU-enabled
targets in the xvfork() macro.
This change is necessary to resolve a segmentation fault observed on
ppc64le when running: "unshare -mrpf sh".
According to POSIX, there is an udefined behaviour if the child
process created by vfork() either modifies the data other than a
variable of type pid_t or calls any other functions before
successfully calling exec (3) or _exit(2) family functions.
From the strace logs,it looks like the child after vfork performed
syscalls like writing uid_map, gid_map, mounting, etc, which violates
the minimal action requirements of vfork() resulting in a SIGSEGV
maybe due to race conditions.
[ 189] [3fff9376726c] vfork(strace: Process 376786 attached
[pid 376786] [ 286] [3fff936d7a80] openat(AT_FDCWD,
"/proc/self/setgroups", O_WRONLY) = 3
[pid 376786] [ 4] [3fff936d7a80] write(3, "deny", 4) = 4
[pid 376786] [ 6] [3fff936d7a80] close(3) = 0
[pid 376786] [ 286] [3fff936d7a80] openat(AT_FDCWD,
"/proc/self/uid_map", O_WRONLY) = 3
[pid 376786] [ 4] [3fff936d7a80] write(3, "0 1000 1", 8) = 8
[pid 376786] [ 6] [3fff936d7a80] close(3) = 0
[pid 376786] [ 286] [3fff936d7a80] openat(AT_FDCWD,
"/proc/self/gid_map", O_WRONLY) = 3
[pid 376786] [ 4] [3fff936d7a80] write(3, "0 1000 1", 8) = 8
[pid 376786] [ 6] [3fff936d7a80] close(3) = 0
[pid 376786] [ 21] [3fff937890fc] mount("none", "/", NULL,
MS_REC|MS_PRIVATE, NULL) = 0
[pid 376786] [ 11] [3fff93741230] execve("/usr/local/bin/bash",
["bash", "-c", "ls"], 0x3fffe38b2780 /* 22 vars */) = -1 ENOENT (No
such file or directory)
[pid 376786] [ 11] [3fff93741230] execve("/usr/bin/bash",
["bash", "-c", "ls"], 0x3fffe38b2780 /* 22 vars */
[pid 376785] [ 189] [3fff9376726c] <... vfork resumed>) = 376786
[pid 376785] [ 189] [f37838210030e840] --- SIGSEGV {si_signo=SIGSEGV,
si_code=SEGV_BNDERR, si_addr=0xf37838210030e840, si_lower=NULL,
si_upper=NULL} ---
[pid 376786] [ 11] [3fffaf368aa0] <... execve resumed>) = 0
[pid 376786] [ 45] [3fffaf371188] brk(NULL) = 0x100157a6000
[pid 376786] [ 90] [3fffaf374638] mmap(NULL, 8192,
PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x3fffaf391000
[pid 376786] [ 33] [3fffaf373e90] access("/etc/ld.so.preload",
R_OK) = -1 ENOENT (No such file or directory)
[pid 376786] [ 286] [3fffaf374340] openat(AT_FDCWD,
"/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
[pid 376785] [ 189] [] +++ killed by SIGSEGV +++
Replacing vfork() with fork() will eliminate this issue because fork()
creates a separate memory space, so the child’s operations cannot
corrupt the parent’s stack and both processes operate independently.
___
busybox mailing list
[email protected]
https://lists.busybox.net/mailman/listinfo/busybox
___
busybox mailing list
[email protected]
https://lists.busybox.net/mailman/listinfo/busybox
Re: [PATCH] Replace vfork() with fork() to fix unshare crash on ppc64le
Please try current git, it contains a fix. Let me know if it doesn't work.
On Mon, Sep 15, 2025 at 7:57 AM tshah wrote:
>
> Hello Denys,
>
> Can you please look into this change and let me know your thoughts on
> this once you get chance.
>
> Thanks.
>
> On 09/09/25 15:50, tshah wrote:
> > Hello,
> >
> > This patch address the issue:
> > https://lists.busybox.net/pipermail/busybox/2025-September/091718.html.
> > The patch replaces the use of vfork() with fork() on MMU-enabled
> > targets in the xvfork() macro.
> > This change is necessary to resolve a segmentation fault observed on
> > ppc64le when running: "unshare -mrpf sh".
> >
> > According to POSIX, there is an udefined behaviour if the child
> > process created by vfork() either modifies the data other than a
> > variable of type pid_t or calls any other functions before
> > successfully calling exec (3) or _exit(2) family functions.
> > From the strace logs,it looks like the child after vfork performed
> > syscalls like writing uid_map, gid_map, mounting, etc, which violates
> > the minimal action requirements of vfork() resulting in a SIGSEGV
> > maybe due to race conditions.
> >
> > [ 189] [3fff9376726c] vfork(strace: Process 376786 attached
> >
> > [pid 376786] [ 286] [3fff936d7a80] openat(AT_FDCWD,
> > "/proc/self/setgroups", O_WRONLY) = 3
> > [pid 376786] [ 4] [3fff936d7a80] write(3, "deny", 4) = 4
> > [pid 376786] [ 6] [3fff936d7a80] close(3) = 0
> > [pid 376786] [ 286] [3fff936d7a80] openat(AT_FDCWD,
> > "/proc/self/uid_map", O_WRONLY) = 3
> > [pid 376786] [ 4] [3fff936d7a80] write(3, "0 1000 1", 8) = 8
> > [pid 376786] [ 6] [3fff936d7a80] close(3) = 0
> > [pid 376786] [ 286] [3fff936d7a80] openat(AT_FDCWD,
> > "/proc/self/gid_map", O_WRONLY) = 3
> > [pid 376786] [ 4] [3fff936d7a80] write(3, "0 1000 1", 8) = 8
> > [pid 376786] [ 6] [3fff936d7a80] close(3) = 0
> > [pid 376786] [ 21] [3fff937890fc] mount("none", "/", NULL,
> > MS_REC|MS_PRIVATE, NULL) = 0
> > [pid 376786] [ 11] [3fff93741230] execve("/usr/local/bin/bash",
> > ["bash", "-c", "ls"], 0x3fffe38b2780 /* 22 vars */) = -1 ENOENT (No
> > such file or directory)
> > [pid 376786] [ 11] [3fff93741230] execve("/usr/bin/bash",
> > ["bash", "-c", "ls"], 0x3fffe38b2780 /* 22 vars */
> > [pid 376785] [ 189] [3fff9376726c] <... vfork resumed>) = 376786
> > [pid 376785] [ 189] [f37838210030e840] --- SIGSEGV {si_signo=SIGSEGV,
> > si_code=SEGV_BNDERR, si_addr=0xf37838210030e840, si_lower=NULL,
> > si_upper=NULL} ---
> > [pid 376786] [ 11] [3fffaf368aa0] <... execve resumed>) = 0
> > [pid 376786] [ 45] [3fffaf371188] brk(NULL) = 0x100157a6000
> > [pid 376786] [ 90] [3fffaf374638] mmap(NULL, 8192,
> > PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x3fffaf391000
> > [pid 376786] [ 33] [3fffaf373e90] access("/etc/ld.so.preload",
> > R_OK) = -1 ENOENT (No such file or directory)
> > [pid 376786] [ 286] [3fffaf374340] openat(AT_FDCWD,
> > "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
> > [pid 376785] [ 189] [] +++ killed by SIGSEGV +++
> >
> >
> > Replacing vfork() with fork() will eliminate this issue because fork()
> > creates a separate memory space, so the child’s operations cannot
> > corrupt the parent’s stack and both processes operate independently.
> >
> > ___
> > busybox mailing list
> > [email protected]
> > https://lists.busybox.net/mailman/listinfo/busybox
___
busybox mailing list
[email protected]
https://lists.busybox.net/mailman/listinfo/busybox
Re: [PATCH] Replace vfork() with fork() to fix unshare crash on ppc64le
Resending the patch inline as a diff instead of an attachment, to follow
mailing list conventions.
diff --git a/include/libbb.h b/include/libbb.h
index 1962d93..76a04c3 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -1234,6 +1234,7 @@ int BB_EXECVP(const char *file, char *const
argv[]) FAST_FUNC;
#endif
void BB_EXECVP_or_die(char **argv) NORETURN FAST_FUNC;
+#if !BB_MMU
/* xvfork() can't be a _function_, return after vfork in child mangles
stack
* in the parent. It must be a macro. */
#define xvfork() \
@@ -1243,8 +1244,12 @@ void BB_EXECVP_or_die(char **argv) NORETURN
FAST_FUNC;
bb_simple_perror_msg_and_die("vfork"); \
bb__xvfork_pid; \
})
-#if BB_MMU
+#else
pid_t xfork(void) FAST_FUNC;
+/* Using fork instead of vfork on MMU-enabled targets to avoid segmentation
+ * fault.
+ */
+#define xvfork() xfork()
#endif
void xvfork_parent_waits_and_exits(void) FAST_FUNC;
On 09/09/25 15:50, tshah wrote:
Hello,
This patch address the issue:
https://lists.busybox.net/pipermail/busybox/2025-September/091718.html.
The patch replaces the use of vfork() with fork() on MMU-enabled
targets in the xvfork() macro.
This change is necessary to resolve a segmentation fault observed on
ppc64le when running: "unshare -mrpf sh".
According to POSIX, there is an udefined behaviour if the child
process created by vfork() either modifies the data other than a
variable of type pid_t or calls any other functions before
successfully calling exec (3) or _exit(2) family functions.
From the strace logs,it looks like the child after vfork performed
syscalls like writing uid_map, gid_map, mounting, etc, which violates
the minimal action requirements of vfork() resulting in a SIGSEGV
maybe due to race conditions.
[ 189] [3fff9376726c] vfork(strace: Process 376786 attached
[pid 376786] [ 286] [3fff936d7a80] openat(AT_FDCWD,
"/proc/self/setgroups", O_WRONLY) = 3
[pid 376786] [ 4] [3fff936d7a80] write(3, "deny", 4) = 4
[pid 376786] [ 6] [3fff936d7a80] close(3) = 0
[pid 376786] [ 286] [3fff936d7a80] openat(AT_FDCWD,
"/proc/self/uid_map", O_WRONLY) = 3
[pid 376786] [ 4] [3fff936d7a80] write(3, "0 1000 1", 8) = 8
[pid 376786] [ 6] [3fff936d7a80] close(3) = 0
[pid 376786] [ 286] [3fff936d7a80] openat(AT_FDCWD,
"/proc/self/gid_map", O_WRONLY) = 3
[pid 376786] [ 4] [3fff936d7a80] write(3, "0 1000 1", 8) = 8
[pid 376786] [ 6] [3fff936d7a80] close(3) = 0
[pid 376786] [ 21] [3fff937890fc] mount("none", "/", NULL,
MS_REC|MS_PRIVATE, NULL) = 0
[pid 376786] [ 11] [3fff93741230] execve("/usr/local/bin/bash",
["bash", "-c", "ls"], 0x3fffe38b2780 /* 22 vars */) = -1 ENOENT (No
such file or directory)
[pid 376786] [ 11] [3fff93741230] execve("/usr/bin/bash",
["bash", "-c", "ls"], 0x3fffe38b2780 /* 22 vars */
[pid 376785] [ 189] [3fff9376726c] <... vfork resumed>) = 376786
[pid 376785] [ 189] [f37838210030e840] --- SIGSEGV {si_signo=SIGSEGV,
si_code=SEGV_BNDERR, si_addr=0xf37838210030e840, si_lower=NULL,
si_upper=NULL} ---
[pid 376786] [ 11] [3fffaf368aa0] <... execve resumed>) = 0
[pid 376786] [ 45] [3fffaf371188] brk(NULL) = 0x100157a6000
[pid 376786] [ 90] [3fffaf374638] mmap(NULL, 8192,
PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x3fffaf391000
[pid 376786] [ 33] [3fffaf373e90] access("/etc/ld.so.preload",
R_OK) = -1 ENOENT (No such file or directory)
[pid 376786] [ 286] [3fffaf374340] openat(AT_FDCWD,
"/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
[pid 376785] [ 189] [] +++ killed by SIGSEGV +++
Replacing vfork() with fork() will eliminate this issue because fork()
creates a separate memory space, so the child’s operations cannot
corrupt the parent’s stack and both processes operate independently.
___
busybox mailing list
[email protected]
https://lists.busybox.net/mailman/listinfo/busybox
___
busybox mailing list
[email protected]
https://lists.busybox.net/mailman/listinfo/busybox
Re: [PATCH] Replace vfork() with fork() to fix unshare crash on ppc64le
Hello Denys,
Can you please look into this change and let me know your thoughts on
this once you get chance.
Thanks.
On 09/09/25 15:50, tshah wrote:
Hello,
This patch address the issue:
https://lists.busybox.net/pipermail/busybox/2025-September/091718.html.
The patch replaces the use of vfork() with fork() on MMU-enabled
targets in the xvfork() macro.
This change is necessary to resolve a segmentation fault observed on
ppc64le when running: "unshare -mrpf sh".
According to POSIX, there is an udefined behaviour if the child
process created by vfork() either modifies the data other than a
variable of type pid_t or calls any other functions before
successfully calling exec (3) or _exit(2) family functions.
From the strace logs,it looks like the child after vfork performed
syscalls like writing uid_map, gid_map, mounting, etc, which violates
the minimal action requirements of vfork() resulting in a SIGSEGV
maybe due to race conditions.
[ 189] [3fff9376726c] vfork(strace: Process 376786 attached
[pid 376786] [ 286] [3fff936d7a80] openat(AT_FDCWD,
"/proc/self/setgroups", O_WRONLY) = 3
[pid 376786] [ 4] [3fff936d7a80] write(3, "deny", 4) = 4
[pid 376786] [ 6] [3fff936d7a80] close(3) = 0
[pid 376786] [ 286] [3fff936d7a80] openat(AT_FDCWD,
"/proc/self/uid_map", O_WRONLY) = 3
[pid 376786] [ 4] [3fff936d7a80] write(3, "0 1000 1", 8) = 8
[pid 376786] [ 6] [3fff936d7a80] close(3) = 0
[pid 376786] [ 286] [3fff936d7a80] openat(AT_FDCWD,
"/proc/self/gid_map", O_WRONLY) = 3
[pid 376786] [ 4] [3fff936d7a80] write(3, "0 1000 1", 8) = 8
[pid 376786] [ 6] [3fff936d7a80] close(3) = 0
[pid 376786] [ 21] [3fff937890fc] mount("none", "/", NULL,
MS_REC|MS_PRIVATE, NULL) = 0
[pid 376786] [ 11] [3fff93741230] execve("/usr/local/bin/bash",
["bash", "-c", "ls"], 0x3fffe38b2780 /* 22 vars */) = -1 ENOENT (No
such file or directory)
[pid 376786] [ 11] [3fff93741230] execve("/usr/bin/bash",
["bash", "-c", "ls"], 0x3fffe38b2780 /* 22 vars */
[pid 376785] [ 189] [3fff9376726c] <... vfork resumed>) = 376786
[pid 376785] [ 189] [f37838210030e840] --- SIGSEGV {si_signo=SIGSEGV,
si_code=SEGV_BNDERR, si_addr=0xf37838210030e840, si_lower=NULL,
si_upper=NULL} ---
[pid 376786] [ 11] [3fffaf368aa0] <... execve resumed>) = 0
[pid 376786] [ 45] [3fffaf371188] brk(NULL) = 0x100157a6000
[pid 376786] [ 90] [3fffaf374638] mmap(NULL, 8192,
PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x3fffaf391000
[pid 376786] [ 33] [3fffaf373e90] access("/etc/ld.so.preload",
R_OK) = -1 ENOENT (No such file or directory)
[pid 376786] [ 286] [3fffaf374340] openat(AT_FDCWD,
"/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
[pid 376785] [ 189] [] +++ killed by SIGSEGV +++
Replacing vfork() with fork() will eliminate this issue because fork()
creates a separate memory space, so the child’s operations cannot
corrupt the parent’s stack and both processes operate independently.
___
busybox mailing list
[email protected]
https://lists.busybox.net/mailman/listinfo/busybox
___
busybox mailing list
[email protected]
https://lists.busybox.net/mailman/listinfo/busybox
Re: [PATCH] Replace vfork() with fork() to fix unshare crash on ppc64le
Thanks for the feedback. Yes, agreed, the root issue is the unsafe use of vfork() with global variable manipulation before exec(), and not specific to ppc64le. On 10/09/25 01:09, Ben Collins wrote: On Tue, Sep 09, 2025 at 03:50:48PM -0500, tshah wrote: Hello, This patch address the issue: https://lists.busybox.net/pipermail/busybox/2025-September/091718.html. The patch replaces the use of vfork() with fork() on MMU-enabled targets in the xvfork() macro. This change is necessary to resolve a segmentation fault observed on ppc64le when running: "unshare -mrpf sh". According to POSIX, there is an udefined behaviour if the child process created by vfork() either modifies the data other than a variable of type pid_t or calls any other functions before successfully calling exec (3) or _exit(2) family functions. From the strace logs,it looks like the child after vfork performed syscalls like writing uid_map, gid_map, mounting, etc, which violates the minimal action requirements of vfork() resulting in a SIGSEGV maybe due to race conditions. From my understanding of the problem, vfork() usage, even on non-MMU, is broken because of the way busybox manipulates globals, affecting the parent stack. The fact that it crashes on ppc64le is likely just because of some architectural differences that make it more likely to happen, but it's still buggy the way busybox uses it, either way. The fact the xvfork() is a macro leads me to believe someone (in 2004) noticed this problem, and using the macro papered over it just enough to "fix" it. That being said, it seems everywhere else in busybox uses fork() on MMU systems, so I guess it makes sense to do the same for xvfork(). ___ busybox mailing list [email protected] https://lists.busybox.net/mailman/listinfo/busybox
