struct user_namespace
struct user_namespace是 Linux 内核中用于实现用户命名空间User Namespace的核心数据结构定义于include/linux/user_namespace.h。它是内核权限隔离的基石负责管理UID/GID 映射、权限能力Capabilities与命名空间层级关系。核心结构体定义内核 5.xstruct user_namespace { struct ns_common ns; /* 命名空间通用属性 */ struct uid_gid_map uid_map; /* UID映射表 */ struct uid_gid_map gid_map; /* GID映射表 */ struct user_namespace *parent; /* 父命名空间指针 */ kuid_t root_uid; /* 本空间root(UID 0)映射的宿主kuid_t */ kgid_t root_gid; /* 本空间root(GID 0)映射的宿主kgid_t */ kuid_t overflowuid; /* 未映射UID默认值 (通常65534/nobody) */ kgid_t overflowgid; /* 未映射GID默认值 */ unsigned int level; /* 命名空间层级 (init_user_ns为0) */ struct ns_common *ns[COUNT_NS]; /* 关联其他类型命名空间 */ unsigned int flags; /* 标志位 (如USERNS_FLAG_FULL) */ /* 权限、引用计数、锁、proc接口等其他字段 */ };核心字段解析struct ns_common ns所有命名空间PID/MNT/UTS 等的通用头部包含引用计数、唯一 ID、父节点、proc入口等。uid_map/gid_map核心隔离机制存储内部虚拟 ID ↔ 宿主真实 ID 的映射规则。格式内部起始ID 宿主起始ID 映射长度示例0 1000 1→ 容器内 root (0) ↔ 宿主普通用户 (1000)parent与level命名空间呈树形层级结构init_user_ns初始根空间level0子空间只能看到 / 管理自身及后代无法影响父 / 兄弟空间root_uid/root_gid本空间内UID0进程在宿主系统的真实身份。overflowuid/overflowgid未映射 ID 的默认值通常65534/nobody。关键原理与机制UID/GID 虚拟化映射不是简单转换而是两套完全独立的 ID 空间内核内部kuid_t / kgid_t全局唯一、真实 ID用户空间uid_t / gid_t虚拟 ID仅本 ns 有效映射规则内部 uid ↔ 宿主 kuid子 ns 看不到父 ns 的 ID 范围未映射 ID → 自动变成overflowuid(65534)同一数字 UID在不同 user_ns 代表完全不同身份这是资源所有权隔离的基础文件、信号、进程权限、socket 都靠 kuid/kgid 判定不是用户态 UID。Capabilities 按命名空间截断权限隔离真正安全的关键capability 不是全局的是绑定 user_ns 的。规则进程的 capability只在自己 user_ns 及子 ns 有效无法提升到父 ns根 nsinit_user_ns才是真正的全局 root函数bool ns_capable(const struct user_namespace *ns, int cap)意义容器内UID0 CAP_SYS_ADMIN→只是容器内的 root不是真实机器 root无法影响宿主、其他容器、内核全局资源这就是容器安全的本质权限被命名空间截断。权限虚拟化Capabilities进程在本空间内可拥有完整root权限如CAP_SYS_ADMIN权限仅在当前空间及子空间有效无法逃逸至父空间内核权限检查ns_capable(current_user_ns(), CAP_SYS_ADMIN)ID 映射生命周期用clone(CLONE_NEWUSER)/unshare(CLONE_NEWUSER)创建空用户空间父空间进程写入/proc/$child/uid_map/gid_map建立映射映射完成后子空间内UID0获得本地root权限与其他命名空间的关系所有命名空间PID/MNT/NET 等必须归属一个用户空间struct pid_namespace { // ... struct user_namespace *user_ns; /* 所属用户空间 */ };创建其他命名空间时需在所属用户空间内拥有CAP_SYS_ADMIN。树形层级结构只能向下不能向上init_user_ns (level 0) ├─ user_ns1 (level 1) │ └─ user_ns11 (level 2) └─ user_ns2 (level 1)严格规则子 ns永远不能访问 / 控制父 ns父 ns 可以管理子 ns写 map、kill 进程等同级 ns 互相不可见、不可干扰这保证了隔离不可逃逸。内核最关键一句代码current_uid() kuid_to_uid(current_user_ns(), current_kuid)所有用户态看到的 UID都是根据当前 user_ns 映射出来的虚拟值。内核真正信任的永远是kuid/kgid全局真实 ID。user_namespace 核心隔离原理图【内核全局层】 ┌───────────────────────────┐ │ init_user_ns │ ← 真正 root全局权限 │ level0 真实 kuid/kgid │ └───────────────────────────┘ │ ▲ 父→子 权限可下放 │ │ 子→父 权限永远无法穿透 可管理 │ │ 不可越权、不可逃逸 ▼ │ ┌───────────────────────────┐ │ user_ns (容器) │ │ level1 │ │ uid_map ↔ kuid │ ← 核心ID 映射隔离 │ gid_map ↔ kgid │ │ cap只在本ns有效 │ ← 权限截断隔离 └───────────────────────────┘ │ ▲ ▼ │ ┌───────────────────────────┐ │ user_ns (孙ns/嵌套) │ │ level2 │ └───────────────────────────┘三条铁律ID 隔离用户态 uid →映射→ 内核全局 kuid同一数字 uid不同 ns 完全不同身份权限隔离CAP_SYS_ADMIN等能力只在本 user_ns 生效→ 容器 root ≠ 宿主机 root结构隔离树形单向父可控子子不可控父同级互不可见→ 天然防止逃逸内核全局实例init_user_ns系统启动时创建的根用户命名空间对应宿主机真实 UID/GID所有内核线程与初始进程 (pid1) 均属于此空间应用场景容器安全Docker/Podman 用其实现 “容器内 root、宿主机普通用户”沙箱 / 测试无特权用户获取本地 root不影响宿主多租户隔离不同租户 UID 空间完全独立总结struct user_namespace是 Linux轻量级权限隔离的核心通过ID 映射 树形层级 能力限制在单一内核内实现安全的 “虚拟 root”是容器、沙箱技术的安全基石。user_namespace ID 虚拟化 权限按空间截断 树形不可逃逸实现同一个内核里同时存在多套独立 “用户权限体系”彼此不可穿透。这就是 Linux 之所以能安全运行容器的根本技术基础。