Repository: opencontainers/runc
File: libcontainer/nsenter/nsexec.c (C)

Code before:
				}
			}
			write_log(DEBUG, "<- stage-1 synchronisation loop");

			/* Now sync with grandchild. */
			syncfd = sync_grandchild_pipe[1];
			if (close(sync_grandchild_pipe[0]) < 0) {
				sane_kill(stage2_pid, SIGKILL);
				bail("failed to close sync_grandchild_pipe[0] fd");
			}

			write_log(DEBUG, "-> stage-2 synchronisation loop");
			stage2_complete = false;
			while (!stage2_complete) {
				enum sync_t s;

				write_log(DEBUG, "signalling stage-2 to run");
				s = SYNC_GRANDCHILD;
				if (write(syncfd, &s, sizeof(s)) != sizeof(s)) {
					sane_kill(stage2_pid, SIGKILL);
					bail("failed to sync with child: write(SYNC_GRANDCHILD)");
				}

				if (read(syncfd, &s, sizeof(s)) != sizeof(s)) {
					sane_kill(stage2_pid, SIGKILL);
					bail("failed to sync with child: next state");
				}

				switch (s) {
				case SYNC_CHILD_FINISH:
					write_log(DEBUG, "stage-2 complete");
					stage2_complete = true;
					stage2_pid = -1;
					break;
				default:
					sane_kill(stage2_pid, SIGKILL);
					bailx("unexpected sync value: %u", s);
				}
			}
			write_log(DEBUG, "<- stage-2 synchronisation loop");
			write_log(DEBUG, "<~ nsexec stage-0");
			exit(0);
		}
		break;

		/*
		 * Stage 1: We're in the first child process. Our job is to join any
		 *          provided namespaces in the netlink payload and unshare all of
		 *          the requested namespaces. If we've been asked to CLONE_NEWUSER,
		 *          we will ask our parent (stage 0) to set up our user mappings
		 *          for us. Then, we create a new child (stage 2: STAGE_INIT) for

Review comment (bug):
I think this `if` is wrong, and it is causing a wrong bail. If read() returns -1, then we need to `bail()`. If it returns positive but different to sizeof(), we need to `bailx()`.

I guess there are way more of these occurences in the code, but I think we should fix them :(

Code after:
					stage1_complete = true;
					stage1_pid = -1;
					break;
				default:
					sane_kill(stage1_pid, SIGKILL);
					sane_kill(stage2_pid, SIGKILL);
					bailx("unexpected sync value: %u", s);
				}
			}
			write_log(DEBUG, "<- stage-1 synchronisation loop");

			/* Now sync with grandchild. */
			syncfd = sync_grandchild_pipe[1];
			if (close(sync_grandchild_pipe[0]) < 0) {
				sane_kill(stage2_pid, SIGKILL);
				bail("failed to close sync_grandchild_pipe[0] fd");
			}

			write_log(DEBUG, "-> stage-2 synchronisation loop");
			stage2_complete = false;
			while (!stage2_complete) {
				enum sync_t s;

				write_log(DEBUG, "signalling stage-2 to run");
				s = SYNC_GRANDCHILD;
				xwrite(syncfd, &s, sizeof(s),
				       "failed to sync with child: write(SYNC_GRANDCHILD)", -1, stage2_pid);

				xread(syncfd, &s, sizeof(s), "failed to sync with child: next state", -1, stage2_pid);

				switch (s) {
				case SYNC_CHILD_FINISH:
					write_log(DEBUG, "stage-2 complete");
					stage2_complete = true;
					stage2_pid = -1;
					break;
				default:
					sane_kill(stage2_pid, SIGKILL);
					bailx("unexpected sync value: %u", s);
				}
			}
			write_log(DEBUG, "<- stage-2 synchronisation loop");
			write_log(DEBUG, "<~ nsexec stage-0");
			exit(0);
		}
		break;

		/*
		 * Stage 1: We're in the first child process. Our job is to join any
		 *          provided namespaces in the netlink payload and unshare all of
		 *          the requested namespaces. If we've been asked to CLONE_NEWUSER,