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

Code before:
		fd = open(path, O_RDONLY);
		if (fd < 0)
			bail("failed to open %s", path);

		ns->fd = fd;
		strncpy(ns->type, namespace, PATH_MAX - 1);
		strncpy(ns->path, path, PATH_MAX - 1);
		ns->path[PATH_MAX - 1] = '\0';
	} while ((namespace = strtok_r(NULL, ",", &saveptr)) != NULL);

	/*
	 * The ordering in which we join namespaces is important. We should
	 * always join the user namespace *first*. This is all guaranteed
	 * from the container_linux.go side of this, so we're just going to
	 * follow the order given to us.
	 */

	for (i = 0; i < num; i++) {
		struct namespace_t *ns = &namespaces[i];
		int flag = nsflag(ns->type);

		write_log(DEBUG, "setns(%#x) into %s namespace (with path %s)", flag, ns->type, ns->path);
		if (setns(ns->fd, flag) < 0)
			bail("failed to setns into %s namespace", ns->type);

		/* See https://github.com/opencontainers/runc/issues/4466. */
		if (flag == CLONE_NEWUSER) {
			if (setresuid(0, 0, 0) < 0)
				bail("failed to become root in user namespace");
		}

		close(ns->fd);
	}

	free(namespaces);
}

static inline int sane_kill(pid_t pid, int signum)
{
	if (pid > 0)
		return kill(pid, signum);
	else
		return 0;
}

void try_unshare(int flags, const char *msg)
{
	write_log(DEBUG, "unshare %s", msg);
	/*
	 * Kernels prior to v4.3 may return EINVAL on unshare when another process
	 * reads runc's /proc/$PID/status or /proc/$PID/maps. To work around this,

Review comment (suggestion):
This actually isn't specific to that issue, the actual issue is that we forgot to do `setresuid` in this case. A more descriptive comment like

```suggestion
		/*
		 * If we change user namespaces, make sure we switch to root in the
		 * namespace (this matches the logic for unshare(CLONE_NEWUSER)). Lots
		 * of things can break if we aren't the right user. See
		 * <https://github.com/opencontainers/runc/issues/4466> for one
		 * example.
		 */
```

would be nice.

Code after:
		fd = open(path, O_RDONLY);
		if (fd < 0)
			bail("failed to open %s", path);

		ns->fd = fd;
		strncpy(ns->type, namespace, PATH_MAX - 1);
		strncpy(ns->path, path, PATH_MAX - 1);
		ns->path[PATH_MAX - 1] = '\0';
	} while ((namespace = strtok_r(NULL, ",", &saveptr)) != NULL);

	/*
	 * The ordering in which we join namespaces is important. We should
	 * always join the user namespace *first*. This is all guaranteed
	 * from the container_linux.go side of this, so we're just going to
	 * follow the order given to us.
	 */

	for (i = 0; i < num; i++) {
		struct namespace_t *ns = &namespaces[i];
		int flag = nsflag(ns->type);

		write_log(DEBUG, "setns(%#x) into %s namespace (with path %s)", flag, ns->type, ns->path);
		if (setns(ns->fd, flag) < 0)
			bail("failed to setns into %s namespace", ns->type);

		/*
		 * If we change user namespaces, make sure we switch to root in the
		 * namespace (this matches the logic for unshare(CLONE_NEWUSER)), lots
		 * of things can break if we aren't the right user. See
		 * <https://github.com/opencontainers/runc/issues/4466> for one example.
		 */
		if (flag == CLONE_NEWUSER) {
			if (setresuid(0, 0, 0) < 0)
				bail("failed to become root in user namespace");
		}

		close(ns->fd);
	}

	free(namespaces);
}

static inline int sane_kill(pid_t pid, int signum)
{
	if (pid > 0)
		return kill(pid, signum);
	else
		return 0;
}

void try_unshare(int flags, const char *msg)