Files
container-from-scratch/src/mount.c
T
XingfenD f21cbe0574 Add comments to all source and header files
- include/container.h: document struct fields and constants
- src/main.c: explain argument parsing, clone flow, parent/child roles
- src/mount.c: describe 6-step mount isolation process
- src/cgroup.c: explain cgroup data structures and resource setup/cleanup
- src/capabilities.c: document capability drop (bounding + inheritable)
- src/seccomp.c: explain each seccomp rule's security purpose
- src/userns.c: describe parent-child sync and uid_map/gid_map format
- src/hostname.c: document tarot card random naming scheme
2026-07-23 15:48:33 +08:00

113 lines
3.6 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* mount.c — 文件系统隔离模块
*
* 负责容器的文件系统隔离:
* 1. MS_PRIVATE 重挂载,防止挂载事件泄漏到宿主机
* 2. bind mount 将 rootfs 挂载到临时目录
* 3. pivot_root 切换根文件系统
* 4. 卸载旧的根文件系统
* 5. 挂载 /proc(进程信息)和 /dev(设备节点)
*/
#include "container.h"
#include "mount.h"
/* pivot_root 系统调用封装(glibc 没有提供封装函数) */
static int pivot_root(const char *new_root, const char *put_old)
{
return syscall(SYS_pivot_root, new_root, put_old);
}
int mounts(struct child_config *config)
{
/* 第一步:将当前所有挂载点标记为 MS_PRIVATE
* 防止 mount namespace 内的挂载事件传播到宿主机 */
fprintf(stderr, "=> remounting everything with MS_PRIVATE...");
if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL)) {
fprintf(stderr, "failed! %m\n");
return -1;
}
fprintf(stderr, "remounted.\n");
/* 第二步:创建临时目录,将 rootfs bind mount 到这里 */
fprintf(stderr, "=> making a temp directory and a bind mount there...");
char mount_dir[] = "/tmp/tmp.XXXXXX";
if (!mkdtemp(mount_dir)) {
fprintf(stderr, "failed making a directory!\n");
return -1;
}
/* bind mount:将 -m 指定的 rootfs 挂载到临时目录 */
if (mount(config->mount_dir, mount_dir, NULL, MS_BIND | MS_PRIVATE, NULL)) {
fprintf(stderr, "bind mount failed!\n");
return -1;
}
/* 在挂载点内创建 oldroot 子目录,用于存放旧根 */
char inner_mount_dir[] = "/tmp/tmp.XXXXXX/oldroot.XXXXXX";
memcpy(inner_mount_dir, mount_dir, sizeof(mount_dir) - 1);
if (!mkdtemp(inner_mount_dir)) {
fprintf(stderr, "failed making the inner directory!\n");
return -1;
}
fprintf(stderr, "done.\n");
/* 第三步:pivot_root,将根文件系统切换到 rootfs */
fprintf(stderr, "=> pivoting root...");
if (pivot_root(mount_dir, inner_mount_dir)) {
fprintf(stderr, "failed!\n");
return -1;
}
fprintf(stderr, "done.\n");
/* 第四步:卸载旧根文件系统,彻底与宿主机文件系统断开 */
char *old_root_dir = basename(inner_mount_dir);
char old_root[sizeof(inner_mount_dir) + 1] = { "/" };
strcpy(&old_root[1], old_root_dir);
fprintf(stderr, "=> unmounting %s...", old_root);
if (chdir("/")) {
fprintf(stderr, "chdir failed! %m\n");
return -1;
}
/* MNT_DETACH:lazy unmount,先断开挂载点,等引用释放后再清理 */
if (umount2(old_root, MNT_DETACH)) {
fprintf(stderr, "umount failed! %m\n");
return -1;
}
if (rmdir(old_root)) {
fprintf(stderr, "rmdir failed! %m\n");
return -1;
}
fprintf(stderr, "done.\n");
/* 第五步:挂载 /proc,让 ps、top 等工具能读取容器内进程信息 */
fprintf(stderr, "=> mounting /proc...");
if (mount("proc", "/proc", "proc", 0, NULL)) {
fprintf(stderr, "failed: %m\n");
return -1;
}
fprintf(stderr, "done.\n");
/* 第六步:挂载 /dev(tmpfs),创建必要的设备节点 */
fprintf(stderr, "=> mounting /dev...");
if (mount("tmpfs", "/dev", "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=755,size=65536k")) {
fprintf(stderr, "failed: %m\n");
return -1;
}
/* 清除 umask,确保设备节点权限正确(0666) */
umask(0);
/* 创建基本设备节点:null、zero、urandom */
if (mknod("/dev/null", S_IFCHR | 0666, makedev(1, 3))) {
fprintf(stderr, "mknod null failed: %m\n");
}
if (mknod("/dev/zero", S_IFCHR | 0666, makedev(1, 5))) {
fprintf(stderr, "mknod zero failed: %m\n");
}
if (mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9))) {
fprintf(stderr, "mknod urandom failed: %m\n");
}
fprintf(stderr, "done.\n");
return 0;
}