OCI/runc 系统路径约束如何工作以防止重新安装此类路径?

如何解决OCI/runc 系统路径约束如何工作以防止重新安装此类路径?

我的问题的背景是我的 Linux-kernel Namespaces discovery Go package lxkns 的一组测试用例,我在其中创建了一个新的子用户命名空间以及一个测试容器内的新子 PID 命名空间。然后我需要重新挂载/proc,否则我会看到错误的进程信息并且无法查找正确的进程相关信息,例如新子用户+PID命名空间内的测试进程的命名空间(不采取游击策略)。

测试工具/测试设置本质上是这样,如果没有 --privileged 就会失败(我正在简化为所有大写并关闭 seccomp 和 apparmor,以便切入真正的肉):

docker run -it --rm --name closedboxx --cap-add ALL --security-opt seccomp=unconfined --security-opt apparmor=unconfined busybox unshare -Umpfr mount -t proc /proc proc
mount: permission denied (are you root?)

当然,阻力最小和美感最少的路径是使用--privileged,这将完成工作,因为这是一个扔掉的测试容器(也许有美在完全缺乏)。

最近,我意识到 Docker 的 --security-opt systempaths=unconfined,它 (afaik) 在生成的 OCI/runc 容器规范中转换为空的 readonlyPaths。以下 Docker 运行命令根据需要成功,在示例中它只是静默返回,因此执行正确:

docker run -it --rm --name closedboxx --cap-add ALL --security-opt seccomp=unconfined --security-opt apparmor=unconfined --security-opt systempaths=unconfined busybox unshare -Umpfr mount -t proc /proc proc

如果设置失败,在没有 --privilege--security-opt systempaths=unconfined 的情况下运行时,子用户内的挂载和容器内的 PID 命名空间如下所示:

docker run -it --rm --name closedboxx --cap-add ALL --security-opt seccomp=unconfined --security-opt apparmor=unconfined busybox unshare -Umpfr cat /proc/1/mountinfo
693 678 0:46 / / rw,relatime - overlay overlay rw,lowerdir=/var/lib/docker/overlay2/l/AOY3ZSL2FQEO77CCDBKDOPEK7M:/var/lib/docker/overlay2/l/VNX7PING7ZLTIPXRDFSBMIOKKU,upperdir=/var/lib/docker/overlay2/60e8ad10362e49b621d2f3d603845ee24bda62d6d77de96a37ea0001c8454546/diff,workdir=/var/lib/docker/overlay2/60e8ad10362e49b621d2f3d603845ee24bda62d6d77de96a37ea0001c8454546/work,xino=off
694 693 0:50 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw
695 694 0:50 /bus /proc/bus ro,relatime - proc proc rw
696 694 0:50 /fs /proc/fs ro,relatime - proc proc rw
697 694 0:50 /irq /proc/irq ro,relatime - proc proc rw
698 694 0:50 /sys /proc/sys ro,relatime - proc proc rw
699 694 0:50 /sysrq-trigger /proc/sysrq-trigger ro,relatime - proc proc rw
700 694 0:51 /null /proc/kcore rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755
701 694 0:51 /null /proc/keys rw,mode=755
702 694 0:51 /null /proc/latency_stats rw,mode=755
703 694 0:51 /null /proc/timer_list rw,mode=755
704 694 0:51 /null /proc/sched_debug rw,mode=755
705 694 0:56 / /proc/scsi ro,relatime - tmpfs tmpfs ro
706 693 0:51 / /dev rw,mode=755
707 706 0:52 / /dev/pts rw,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=666
708 706 0:49 / /dev/mqueue rw,relatime - mqueue mqueue rw
709 706 0:55 / /dev/shm rw,relatime - tmpfs shm rw,size=65536k
710 706 0:52 /0 /dev/console rw,ptmxmode=666
711 693 0:53 / /sys ro,relatime - sysfs sysfs ro
712 711 0:54 / /sys/fs/cgroup rw,relatime - tmpfs tmpfs rw,mode=755
713 712 0:28 /docker/eebfacfdc6e0e34c4e62d9f162bdd7c04b232ba2d1f5327eaf7e00011d0235c0 /sys/fs/cgroup/systemd ro,relatime - cgroup cgroup rw,xattr,name=systemd
714 712 0:31 /docker/eebfacfdc6e0e34c4e62d9f162bdd7c04b232ba2d1f5327eaf7e00011d0235c0 /sys/fs/cgroup/cpuset ro,cpuset
715 712 0:32 /docker/eebfacfdc6e0e34c4e62d9f162bdd7c04b232ba2d1f5327eaf7e00011d0235c0 /sys/fs/cgroup/net_cls,net_prio ro,net_cls,net_prio
716 712 0:33 /docker/eebfacfdc6e0e34c4e62d9f162bdd7c04b232ba2d1f5327eaf7e00011d0235c0 /sys/fs/cgroup/memory ro,memory
717 712 0:34 /docker/eebfacfdc6e0e34c4e62d9f162bdd7c04b232ba2d1f5327eaf7e00011d0235c0 /sys/fs/cgroup/perf_event ro,perf_event
718 712 0:35 /docker/eebfacfdc6e0e34c4e62d9f162bdd7c04b232ba2d1f5327eaf7e00011d0235c0 /sys/fs/cgroup/devices ro,devices
719 712 0:36 /docker/eebfacfdc6e0e34c4e62d9f162bdd7c04b232ba2d1f5327eaf7e00011d0235c0 /sys/fs/cgroup/blkio ro,blkio
720 712 0:37 /docker/eebfacfdc6e0e34c4e62d9f162bdd7c04b232ba2d1f5327eaf7e00011d0235c0 /sys/fs/cgroup/pids ro,pids
721 712 0:38 / /sys/fs/cgroup/rdma ro,rdma
722 712 0:39 /docker/eebfacfdc6e0e34c4e62d9f162bdd7c04b232ba2d1f5327eaf7e00011d0235c0 /sys/fs/cgroup/freezer ro,freezer
723 712 0:40 /docker/eebfacfdc6e0e34c4e62d9f162bdd7c04b232ba2d1f5327eaf7e00011d0235c0 /sys/fs/cgroup/cpu,cpuacct ro,cpu,cpuacct
724 711 0:57 / /sys/firmware ro,relatime - tmpfs tmpfs ro
725 693 8:2 /var/lib/docker/containers/eebfacfdc6e0e34c4e62d9f162bdd7c04b232ba2d1f5327eaf7e00011d0235c0/resolv.conf /etc/resolv.conf rw,relatime - ext4 /dev/sda2 rw,stripe=256
944 693 8:2 /var/lib/docker/containers/eebfacfdc6e0e34c4e62d9f162bdd7c04b232ba2d1f5327eaf7e00011d0235c0/hostname /etc/hostname rw,stripe=256
1352 693 8:2 /var/lib/docker/containers/eebfacfdc6e0e34c4e62d9f162bdd7c04b232ba2d1f5327eaf7e00011d0235c0/hosts /etc/hosts rw,stripe=256
  1. 究竟是什么机制阻止了 procfs/proc 的新安装?
  2. 是什么阻止我卸载 /proc/kcore 等?

解决方法

更多的挖掘发现这个 answer to "About mounting and unmounting inherited mounts inside a newly-created mount namespace" 指向正确的方向,但需要额外的解释(尤其是因为基于迈克尔·凯里斯(Michael Kerrisk)修复了一段时间的手册页中关于挂载命名空间分层的误导性段落之前)。

我们的出发点是当 runc 设置(测试)容器时,为了屏蔽系统路径,尤其是在容器未来的 /proc 树中,它会创建一组新的挂载来屏蔽单个文件使用 /dev/null 或使用 tmpfs 的子目录。这导致 procfs 安装在 /proc 上,以及进一步的子安装。

现在测试容器启动,并且在某个时刻一个进程取消共享到一个新的用户命名空间。请记住,这个新用户命名空间(再次)属于 UID 为 0 的(真实)root 用户,因为默认的 Docker 安装不会在新用户命名空间中启用运行容器。

接下来,测试过程也unshare到一个新的mount命名空间,所以这个新的mount命名空间属于新创建的用户命名空间,而不是初始用户命名空间。根据 mount_namespaces(7) 中的“挂载命名空间的限制”部分:

如果新的命名空间和从中复制挂载点列表的命名空间由不同的用户命名空间拥有,那么新的挂载命名空间被视为权限较低

请注意,这里的标准是:“donor”挂载命名空间和新挂载命名空间具有不同的用户命名空间;它们是否具有相同的所有者用户 (UID) 并不重要。

现在的重要线索是:

作为单个单元来自更高特权的挂载命名空间的挂载被锁定在一起,并且不能在低特权的挂载命名空间中分开。 (unshare(2) CLONE_NEWNS 操作将原始挂载命名空间中的所有挂载作为一个单元,并将在挂载命名空间之间传播的递归挂载作为一个单元传播。)

由于现在无法再将 /proc 挂载点与掩蔽子挂载分开,因此无法(重新)挂载 /proc(问题 1)。同样,也无法卸载 /proc/kcore,因为这将允许取消屏蔽(问题 2)。

现在,当使用 --security-opt systempaths=unconfined 部署测试容器时,这只会导致 单一 /proc 安装,没有任何掩蔽子安装。因此,根据上面引用的手册页规则,我们只允许(重新)挂载一个挂载,受制于 CAP_SYS_ADMIN 能力,还包括挂载(除了大量其他有趣的功能)。

请注意,可以在容器内卸载屏蔽的 /proc/ 路径,同时仍处于原始(=初始)用户命名空间并且拥有(并不奇怪){{1} }. (b)lock 只在一个单独的用户命名空间中启动,因此一些项目努力在他们自己的新用户命名空间中部署容器(不幸的是,这不仅对容器网络有影响)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 <select id="xxx"> SELECT di.id, di.name, di.work_type, di.updated... <where> <if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 <property name="dynamic.classpath" value="tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-