Skip to content

Commit 16a2e8b

Browse files
committed
Sync with grandchild
Without this, it's possible that father process exit with 0 before grandchild exit with error. Signed-off-by: Qiang Huang <[email protected]>
1 parent e7abf30 commit 16a2e8b

File tree

1 file changed

+23
-6
lines changed

1 file changed

+23
-6
lines changed

libcontainer/nsenter/nsexec.c

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ enum sync_t {
3333
SYNC_USERMAP_ACK = 0x41, /* Mapping finished by the parent. */
3434
SYNC_RECVPID_PLS = 0x42, /* Tell parent we're sending the PID. */
3535
SYNC_RECVPID_ACK = 0x43, /* PID was correctly received by parent. */
36+
SYNC_CHILD_READY = 0x44, /* The grandchild is ready to return. */
3637

3738
/* XXX: This doesn't help with segfaults and other such issues. */
3839
SYNC_ERR = 0xFF, /* Fatal error, no turning back. The error code follows. */
@@ -497,7 +498,7 @@ void nsexec(void)
497498
* process.
498499
*/
499500
case JUMP_PARENT: {
500-
int len;
501+
int len, ready = 0;
501502
pid_t child;
502503
char buf[JSON_MAX];
503504

@@ -509,8 +510,14 @@ void nsexec(void)
509510
if (child < 0)
510511
bail("unable to fork: child_func");
511512

512-
/* State machine for synchronisation with the children. */
513-
while (true) {
513+
/*
514+
* State machine for synchronisation with the children.
515+
*
516+
* Father only return when both child and grandchild are
517+
* ready, so we can receive all possible error codes
518+
* generated by children.
519+
*/
520+
while (ready < 2) {
514521
enum sync_t s;
515522

516523
/* This doesn't need to be global, we're in the parent. */
@@ -568,17 +575,22 @@ void nsexec(void)
568575
}
569576
}
570577

571-
/* Leave the loop. */
572-
goto out;
578+
ready++;
579+
break;
573580
case SYNC_RECVPID_ACK:
574581
/* We should _never_ receive acks. */
575582
kill(child, SIGKILL);
576583
bail("failed to sync with child: unexpected SYNC_RECVPID_ACK");
577584
break;
585+
case SYNC_CHILD_READY:
586+
ready++;
587+
break;
588+
default:
589+
bail("unexpected sync value");
590+
break;
578591
}
579592
}
580593

581-
out:
582594
/* Send the init_func pid back to our parent. */
583595
len = snprintf(buf, JSON_MAX, "{\"pid\": %d}\n", child);
584596
if (len < 0) {
@@ -700,6 +712,7 @@ void nsexec(void)
700712
* start_child() code after forking in the parent.
701713
*/
702714
int consolefd = config.consolefd;
715+
enum sync_t s;
703716

704717
/* We're in a child and thus need to tell the parent if we die. */
705718
syncfd = syncpipe[0];
@@ -730,6 +743,10 @@ void nsexec(void)
730743
bail("failed to dup stderr");
731744
}
732745

746+
s = SYNC_CHILD_READY;
747+
if (write(syncfd, &s, sizeof(s)) != sizeof(s))
748+
bail("failed to sync with patent: write(SYNC_CHILD_READY)");
749+
733750
/* Close sync pipes. */
734751
close(syncpipe[0]);
735752
close(syncpipe[1]);

0 commit comments

Comments
 (0)