尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

一篇文章搞懂Linux 文件系统隔离:Mount Namespace 与三个挂载视图 容器安全3/7

一篇文章搞懂Linux 文件系统隔离:Mount Namespace 与三个挂载视图 容器安全3/7
📅 发布时间:2026/8/1 14:44:22

容器安全文章:3
核心概念:Mount Namespace(挂载命名空间)与文件系统视图隔离

Linux 文件系统隔离:Mount Namespace 与三个挂载视图

为什么需要隔离?

一台服务器跑着网站、数据库、缓存三个服务。如果共享同一个文件系统,一个服务被入侵就能读到其他服务的配置文件、数据库密码。文件系统隔离让每个服务只能看到自己的文件,即使运行在同一台机器上。

下面是实验证明:

  • Linux 系统:debian
  • 实验能更好了解和证明

一、核心概念

1.1 目录是门,文件系统是房间

目录本身不存储数据,它只是一扇门。门后面是什么房间,取决于你在这扇门上"挂载"了什么。

文件系统是独立的房间——有自己的文件、目录、权限。但不挂到门上,你就进不去、看不到、用不了。

# 造一扇门(创建一个空目录)mkdir/mnt/door# 门后面是空的ls/mnt/door# => (没有任何输出)# 在门后挂一个房间# mount = 挂载命令# -t tmpfs = 指定房间类型为 tmpfs(内存文件系统,存在内存里,重启消失)# 第一个 tmpfs = 房间类型# 第二个 tmpfs = 房间名字(可以随便取)# /mnt/door = 门的位置mount-ttmpfs tmpfs /mnt/door# 现在门后就是一个独立房间了echo"我在房间里">/mnt/door/msg.txtcat/mnt/door/msg.txt# => 我在房间里# 拆下房间,门又变空了:# umount = 卸载,把房间从门上拆下来umount/mnt/doorcat/mnt/door/msg.txt# => 报错:没有那个文件或目录

📌文件系统必须挂载到目录上才能使用。目录是唯一的入口。


1.2 什么是 Mount Namespace(挂载视图)

Linux 内核有一个机制叫Mount Namespace(挂载命名空间),本文简称"挂载视图"。

它的作用:

让每个进程拥有自己的"房间清单"(挂载表),进程之间互相独立。

同一个门/mnt/data,进程 A 的清单上写着通向房间 X,进程 B 的清单上可能写着通向房间 Y,或者什么都没写。

不是房间变了,是进程手里的清单不同。


1.3 什么是"复制一份"

创建新挂载视图时,内核会复制一份当前的房间清单给新视图。之后两边的清单各自更新,互不影响。

就像你复印一份文件清单,你在这份复印件上新增一条记录,原件不会自动更新

⚠️重要:挂载视图隔离的是"房间清单"(挂载表),不是房间里的文件内容。

如果两个视图都挂载了同一个房间(比如都指向同一个硬盘分区),修改文件会互相看到。只有新挂载的房间才是隔离的。


二、第一视图:宿主机的清单

这是你开机后的正常 Linux。所有进程共享同一份房间清单。

你在第一视图 终端:ls/=>bin boot dev etc home lib...

特点:

  • 所有挂载操作全系统可见
  • 其他视图的新挂载,你看不到
  • 这是"根视图",其他视图都从这里复制出去

三、第二视图:独立的清单

3.1 怎么创建?

sudo=以 root 权限执行 unshare=脱离共享资源,创建自己的副本--mount=只脱离"房间清单"这一项--propagationprivate=确保新视图的挂载操作不影响宿主机 (systemd 默认把根文件系统的挂载传播类型设为 shared,不加这句可能传播回宿主机) /bin/bash=启动一个新的命令行 终端:sudounshare--mount--propagationprivate /bin/bash

执行后,你的 shell 进入了一个新的挂载视图。这一刻,内核复制了一份房间清单给你。从此你的清单和宿主机的清单各自独立。

3.2 验证视图切换

查看当前进程的 Mount Namespace ID 终端: readlink /proc/$$/ns/mount=>mnt:[4026532234](数字与之前不同,说明进了新视图)

3.3 即时验证

# 你在第二视图mkdir/mnt/room2mount-ttmpfs tmpfs /mnt/room2echo"第二视图的文件">/mnt/room2/secret.txtcat/mnt/room2/secret.txt# => 第二视图的文件# 退出第二视图,回到第一视图exit# 第一视图看不到ls/mnt/room2# => (没有任何输出)cat/mnt/room2/secret.txt# => 报错:没有那个文件或目录

第二视图的新挂载只写在自己的清单上,第一视图的清单没有这条记录。


⚠️ 常见错误

错误:以为 exit 后文件还在

exit只是退出视图,但挂载的房间还在内存里。如果同一目录在宿主机会被用到,可能冲突。

解决:退出前卸载

在第二视图里执行 终端:umount/mnt/room2exit

⚠️ 安全警告

第二视图里/仍然是宿主机的根文件系统(只是挂载表不同)。不要执行rm -rf /等危险命令,会删除宿主机文件。

注意:清单隔离 ≠ 文件隔离

如果第二视图修改了已经存在的文件(如/etc/hosts),第一视图能看到变化,因为底层文件数据是同一个。只有新挂载的房间才是隔离的。

验证:

# 在第二视图里echo"test">>/etc/hosts# 退出到第一视图exitcat/etc/hosts# => 能看到 "test" 被追加进去了

四、第三视图:在独立清单里再复制一份

4.1 怎么创建?

在第二视图内部执行(在第二视图的 shell 里继续输入):

# 确保你在第二视图里(提示符可能变了,或者你记得执行过 unshare)sudounshare--mount--propagationprivate /bin/bash# 在第二视图里再复制一份清单,创建第三视图mkdir/mnt/room2/room3mount-ttmpfs tmpfs /mnt/room2/room3echo"第三视图的文件">/mnt/room2/room3/deep.txt

“在内部执行” = 基于第二视图的清单再复制一份,作为第三视图的起点。

4.2 即时验证

# 第三视图能看到所有内容cat/mnt/room2/secret.txt# 第二视图的文件(复制时带过来的)cat/mnt/room2/room3/deep.txt# 第三视图的文件(自己的新挂载)# 退出到第二视图exitcat/mnt/room2/secret.txt# ✅ 能看到cat/mnt/room2/room3/deep.txt# ❌ 报错!第二视图看不到第三视图的新挂载# 退出到第一视图exitcat/mnt/room2/secret.txt# ❌ 报错!第一视图看不到第二视图的新挂载

4.3 三个视图对比

查看内容第一视图第二视图第三视图
/mnt/room2/secret.txt❌ 看不到✅ 能看到✅ 能看到(复制时带过来的)
/mnt/room2/room3/deep.txt❌ 看不到❌ 看不到✅ 能看到
修改/etc/hosts(已存在文件)✅ 能看到变化✅ 能看到变化✅ 能看到变化(底层共享)

规律:每多一个视图,就多一层清单隔离。外层看不到内层的新挂载,除非显式进入内层。


⚠️ 常见错误

错误:在第二视图外创建第三视图

如果你在第一视图里执行sudo unshare --mount,创建的是另一个第二视图,不是第三视图。第三视图必须在第二视图内部创建。


五、从视图到容器:换房间

5.1 问题:前面的视图只隔离了清单,没换房间

第二视图、第三视图的清单虽然独立了,但根目录/里的内容还是和第一视图一样。/bin/bash、/etc/passwd都是宿主机的文件。

容器需要:不仅清单独立,根目录/也要换成新房间。

5.2 容器怎么做?(以文件系统隔离为例)

dockerrun-itubuntu /bin/bash

内部三步:

  1. 创建 Mount Namespace(第二视图,清单隔离)
  2. 挂载容器镜像文件系统(新房间,不是第三视图)
  3. 用pivot_root把根目录/指向新房间(换房间操作)

pivot_root:把进程的根目录切换到指定目录。这是容器运行时的内部机制,实验 1-4 不手动操作,只理解原理。

容器里:

ls/# => bin boot dev etc home lib ...(这是 Ubuntu 镜像的内容,不是宿主机的)cat/etc/os-release# => PRETTY_NAME="Ubuntu 22.04 LTS"

宿主机上:

终端:cat/etc/os-release=>显示宿主机自己的系统(如 CentOS)

5.3 容器的文件系统隔离

容器的文件系统隔离 = 第二视图(清单隔离)+ 新房间 + 换根

容器比纯 Namespace 多了一层:不仅"换清单"(视图隔离),还"换房间"(根目录替换)。

注意:容器没有创建"第三视图",它复用了第二视图的 Mount Namespace,在里面直接挂载新房间并换根。

完整的容器还需要 PID Namespace(进程隔离)、Network Namespace(网络隔离)、User Namespace(用户权限隔离)等。这里只讨论文件系统隔离。

5.4 安全 implications(文件系统隔离机制)

攻击场景文件系统隔离机制(标准容器)
容器内读取宿主机/etc/shadow✅ 换根后看不到
容器内修改宿主机文件✅ 清单隔离保护

注意:通过 volume 显式挂载宿主机目录,容器可以访问。这是配置行为,不是隔离机制的绕过。

实验 1-4 的理解适用于标准容器。特权容器(--privileged)或内核漏洞逃逸需要额外防护,不在本文范围。


六、核心结论

第一视图(宿主机) │ ├── 房间清单:/bin, /etc, /home, /mnt...(所有系统挂载) │ ▼ unshare --mount(复制清单) 第二视图(容器边界) │ ├── 复制了第一视图的清单作为起点 ├── 之后独立添加新房间 ├── 第一视图看不到第二视图的新房间 │ ▼ 内部再 unshare + mount(再复制清单) 第三视图(嵌套隔离) │ ├── 在第二视图内部再创建的 Mount Namespace ├── 第二视图看不到第三视图的新房间 ├── 底层还是同一个内核 │ └── 宿主机不进入第二视图,永远看不到这里 容器(第二视图的应用) │ ├── 用第二视图的 Mount Namespace 做边界 ├── 在内部挂载新房间(容器镜像) ├── 用 pivot_root 把根目录指向新房间 │ └── 不是第三视图,是"第二视图 + 换房间"
  • 同一内核,不同房间清单。
  • 跨视图不可见,必须显式进入。
  • 容器多一步,不仅换清单,还换房间。

七、完整实验(带清理)

# === 步骤1:创建第二视图,记录 PID ===sudounshare--mount--propagationprivate /bin/bashecho$$# 记下这个 PID,如 1234readlink /proc/$$/ns/mount# => mnt:[...](记下这个数字)# === 步骤2:第二视图挂载 ===mkdir/mnt/room2mount-ttmpfs tmpfs /mnt/room2echo"第二视图">/mnt/room2/a.txt# === 步骤3:在第二视图里创建第三视图 ===sudounshare--mount--propagationprivate /bin/bash readlink /proc/$$/ns/mount# => mnt:[...](数字与步骤1不同)# === 步骤4:第三视图挂载(嵌套在room2内部) ===mkdir/mnt/room2/room3mount-ttmpfs tmpfs /mnt/room2/room3echo"第三视图">/mnt/room2/room3/b.txt# === 步骤5:第三视图验证(能看到所有) ===cat/mnt/room2/a.txt# 第二视图的文件cat/mnt/room2/room3/b.txt# 第三视图的文件# === 步骤5.5:在第三视图内先卸载内层(必须在exit之前!)===umount/mnt/room2/room3# === 步骤6:回退到第二视图 ===exitcat/mnt/room2/a.txt# ✅ 能看到cat/mnt/room2/room3/b.txt# ❌ 报错(目录存在但为空,因为room3已卸载)# === 步骤6.5:用 nsenter 进入第二视图验证 ===# 需要另开终端窗口执行,保持原终端不退出:# 1. 保持原终端窗口不关闭(第二视图的bash还在运行)# 2. 新开一个终端窗口(或新标签页)# 3. 在新终端里执行以下命令# 4. 验证完成后在新终端里输入 exit 退出# 5. 回到原终端继续步骤7sudonsenter-t1234-m/bin/bashcat/mnt/room2/a.txt# ✅ 能看到cat/mnt/room2/room3/b.txt# ❌ 报错(确认第二视图看不到第三视图)exit# 回到原终端# === 步骤7:在第二视图内卸载外层 ===umount/mnt/room2# 在第二视图内卸载exit# 回退到第一视图# === 步骤8:第一视图验证(看不到第二视图) ===cat/mnt/room2/a.txt# ❌ 报错# === 步骤9:确认回到第一视图 ===readlink /proc/$$/ns/mount# 与步骤1的数字对比,确认一致

八、清理检查(实验后必做)

# 检查是否还有残留挂载mount|grep/mnt/room# => 应该没有任何输出# 检查 room2 目录是否为空(umount 后)ls/mnt/room2# => (没有任何输出,目录存在但为空)# 检查 room3 目录是否消失(随 room2 的 tmpfs 一起释放)ls/mnt/room2/room3# => 报错:没有那个文件或目录# 如果有残留,手动卸载sudoumount/mnt/room2/room3sudoumount/mnt/room2# 删除空目录sudormdir/mnt/room2/room3sudormdir/mnt/room2

附录 A:故障排查

现象原因解决
umount: not mounted在当前视图里没有这条挂载记录确认你在正确的视图里,或检查 `mount
nsenter: cannot open /proc/1234/ns/mountPID 对应的进程已退出重新执行步骤 1-2,确保第二视图的 bash 没退出
ls /mnt/room2显示文件可能没执行 umount,或 mount 传播到宿主机检查 `mount
修改/etc/hosts后宿主机也变了这是正常的,清单隔离 ≠ 文件隔离理解"已存在文件是共享的"

附录 B:后续学习

实验 1-4 理解了 Mount Namespace(文件系统视图隔离)。后续内容:

  • User Namespace:用户权限隔离(容器内的 root 映射到宿主机普通用户)

附录 C:延伸阅读

  • man 2 unshare:创建新 Namespace 的系统调用
  • man 1 nsenter:进入指定 Namespace 的命令
  • man 2 pivot_root:切换根目录的系统调用
  • Linux 内核源码fs/namespace.c:Mount Namespace 实现

相关新闻

  • 2026手把手教你用录音实时转文字软件,电脑手机免费工具全攻略 - 工具软件使用方法推荐
  • ESP32-P4开发板实战:DMA2D图形加速与工业物联网终端设计
  • 如何在5分钟内配置Plex直播插件:实现媒体中心直播电视融合方案

最新新闻

  • 私有化在线办公平台搭建指南:5步实现团队高效协作
  • NAS机箱六大行业应用场景的常见挑战与平台化应对
  • 武校武术段位证书有用吗?陈家沟王战军太极武术学校考级认证体系 - 圣龙武术朱老师
  • Joplin开源笔记项目深度构建与开发环境配置实战指南
  • 2026年助听算法定制开发哪家好 - 滚动商讯
  • Gemma 4开源模型本地部署与性能优化指南

日新闻

  • ClickHouse版本管理深度实战:4步构建零风险升级与回滚体系
  • Java 23 种设计模式:从踩坑到精通 | 番外:责任链模式 —— 物流审批流程实战
  • 华硕笔记本性能解放指南:G-Helper轻量级控制工具全面解析

周新闻

  • 大连理工大学与东京大学联手打造的“主动型AI助手“
  • 170.2026年国家级科研瓶颈:超精密单点金刚石切削(SPDT)光学表面生成
  • SongBloom:革命性歌曲生成框架深度解析——如何通过交织自回归与扩散模型创作完整音乐

月新闻

  • ClickHouse版本管理深度实战:4步构建零风险升级与回滚体系
  • Java 23 种设计模式:从踩坑到精通 | 番外:责任链模式 —— 物流审批流程实战
  • 华硕笔记本性能解放指南:G-Helper轻量级控制工具全面解析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号