runc rootless模式代码解析---创建dev设备节点文件

containerd-rootless安装 接下来要根据文档3配置一下cni网络,不过上面的错误信息提示要把cni放到/opt/cni/bin下,这个操作的citrix中/opt我没有写权限。上述指定路径到/containerd,然后把cni的配置就可以直接配置到/containerd下,不用再配置到/opt/cni/bin下了。上面下载的cni需要放到/opt/cni/bin下,在citrix中不知道可不可以。然后在root用户下把cni放到/opt/cni/bin下试一下。通过查阅,上述问题可能与主目录的文件系统有关,以下配置可能有效。 阅读详情

runc rootless模式代码解析

本来以为user namespace映射了root权限后可以直接mount /proc /dev, 实现容器隔离。但是实际测试发现,/dev 并不能在userns中的root权限mount udev 到自身的/dev。但实际上, docker上是实现了类似的功能的,所以这里研究了相应的功能。docker 启动采用了containerd 和runc交互的形式,实现容器的创建。而runc可以直接启动利用rootless模式启动普通用户映射root权限的能力,并生成/dev设备文件。这里研究了 /dev目录文件的生成过程。
“libcontainer/rootfs_linux.go”


func mountToRootfs(m *configs.Mount, rootfs, mountLabel string, enableCgroupns bool) error {
	var (
		dest = m.Destination
	)
	if !strings.HasPrefix(dest, rootfs) {
		dest = filepath.Join(rootfs, dest)
	}
	switch m.Device {
	...
		case "tmpfs":
		...
		if err := mountPropagate(m, rootfs, mountLabel);
		if copyUp {
			if err := fileutils.CopyDirectory(dest, tmpDir); 
			if err := unix.Mount(tmpDir, dest, "", unix.MS_MOVE, "")
		}

函数mount_root();挂载ROOT_DEV(真正的根文件系统所在块设备)对应的设备到rootfs的/root目录下。根文件系统挂载后进程的当前目录是/root。sys_mount(".", “/”, NULL, MS_MOVE, NULL);将当前目录的实际根文件系统移到根目录"/“下。sys_chroot((const char __user __force *)”.");将当前目录设为进程的根目录。

func mountPropagate(m *configs.Mount, rootfs string, mountLabel string)
{
//   /dev目录清除
	...
	if err := unix.Mount(m.Source, dest, m.Device, uintptr(flags), data); 

	for _, pflag := range m.PropagationFlags {
		unix.Mount("", dest, "", uintptr(pflag), "")
	}
	...
}
// CopyDirectory copies the files under the source directory
// to dest directory. The dest directory is created if it
// does not exist.
func CopyDirectory(source string, dest string) error {
	fi, err := os.Stat(source)
	// Get owner.
	st, ok := fi.Sys().(*syscall.Stat_t)
	// We have to pick an owner here anyway.
	MkdirAllNewAs(dest, fi.Mode(), int(st.Uid), int(st.Gid));
	return filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
		// Get the relative path
		relPath, err := filepath.Rel(source, path)
		if err != nil {

		if info.IsDir() {
			// Skip the source directory.
			if path != source {
				// Get the owner.
				st, ok := info.Sys().(*syscall.Stat_t)
				uid := int(st.Uid)
				gid := int(st.Gid)
				os.Mkdir(filepath.Join(dest, relPath), info.Mode());
				os.Lchown(filepath.Join(dest, relPath), uid, gid);
			}
			return nil
		}
		// Copy the file.
		CopyFile(path, filepath.Join(dest, relPath));
		return nil
	})
}

mknod 创建设备节点

这里创建节点后复制了host的设备文件。

// CopyFile copies the file at source to dest
func CopyFile(source string, dest string) error {
	si, err := os.Lstat(source)
	st, ok := si.Sys().(*syscall.Stat_t)

	uid := int(st.Uid)
	gid := int(st.Gid)

	// Handle symlinks
	if si.Mode()&os.ModeSymlink != 0 {
		target, err := os.Readlink(source)
		os.Symlink(target, dest);
	}

	// Handle device files
	if st.Mode&syscall.S_IFMT == syscall.S_IFBLK || st.Mode&syscall.S_IFMT == syscall.S_IFCHR {
		devMajor := int64(major(uint64(st.Rdev)))
		devMinor := int64(minor(uint64(st.Rdev)))
		mode := uint32(si.Mode() & 07777)
		if st.Mode&syscall.S_IFMT == syscall.S_IFBLK {
			mode |= syscall.S_IFBLK
		}
		if st.Mode&syscall.S_IFMT == syscall.S_IFCHR {
			mode |= syscall.S_IFCHR
		}
		syscall.Mknod(dest, mode, int(mkdev(devMajor, devMinor)));
	}

	// Handle regular files 复制文件
	if si.Mode().IsRegular() {
		sf, err := os.Open(source)
		defer sf.Close()
		df, err := os.Create(dest)
		defer df.Close()
		_, err = io.Copy(df, sf)
	}

	// Chown the file
	if err := os.Lchown(dest, uid, gid); 

	// Chmod the file
	if !(si.Mode()&os.ModeSymlink == os.ModeSymlink) {
		os.Chmod(dest, si.Mode());
	}

	return nil
}

// CopyDirectory copi

建立dev目录的开始

mountToRootfs在往上即是prepareRootfs,prepareRootfs调用mountToRootfs创建设备节点,并复制设备文件。


// prepareRootfs sets up the devices, mount points, and filesystems for use
// inside a new mount namespace. It doesn't set anything as ro. You must call
// finalizeRootfs after this function to finish setting up the rootfs.
func prepareRootfs(pipe io.ReadWriter, iConfig *initConfig) (err error) {
	config := iConfig.Config
	if err := prepareRoot(config); err != nil {
		return newSystemErrorWithCause(err, "preparing rootfs")
	}

	hasCgroupns := config.Namespaces.Contains(configs.NEWCGROUP)
	setupDev := needsSetupDev(config)
	for _, m := range config.Mounts {
		for _, precmd := range m.PremountCmds {
			if err := mountCmd(precmd); err != nil {
				return newSystemErrorWithCause(err, "running premount command")
			}
		}
		mountToRootfs(m, config.Rootfs, config.MountLabel, hasCgroupns)
		for _, postcmd := range m.PostmountCmds {
			mountCmd(postcmd);
		}
	}

	if setupDev {
		createDevices(config)
		setupPtmx(config)
		setupDevSymlinks(config.Rootfs)
	}

	return nil
}

这里还创建了设备节点。


// Create the device nodes in the container.
func createDevices(config *configs.Config) error {
	useBindMount := system.RunningInUserNS() || config.Namespaces.Contains(configs.NEWUSER)
	oldMask := unix.Umask(0000)
	for _, node := range config.Devices {
		// containers running in a user namespace are not allowed to mknod
		// devices so we can just bind mount it from the host.
		if err := createDeviceNode(config.Rootfs, node, useBindMount); err != nil {
			unix.Umask(oldMask)
			return err
		}
	}
	unix.Umask(oldMask)
	return nil
}


// Creates the device node in the rootfs of the container.
func createDeviceNode(rootfs string, node *configs.Device, bind bool) error {
	dest := filepath.Join(rootfs, node.Path)
	os.MkdirAll(filepath.Dir(dest), 0755);

	if bind {
		return bindMountDeviceNode(dest, node)
	}
	if err := mknodDevice(dest, node); err != nil {
		if os.IsExist(err) {
			return nil
		} else if os.IsPermission(err) {
			return bindMountDeviceNode(dest, node)
		}
		return err
	}
	return nil
}

创建设备节点并绑定设备节点。


func bindMountDeviceNode(dest string, node *configs.Device) error {
	f, err := os.Create(dest)
	if err != nil && !os.IsExist(err) {
		return err
	}
	if f != nil {
		f.Close()
	}
	return unix.Mount(node.Path, dest, "bind", unix.MS_BIND, "")
}
Docker容器安全加固实战:Rootless、Capability与Seccomp三支柱 容器技术通过Linux内核的Namespace和Cgroup机制实现进程级隔离,为应用部署提供了轻量级解决方案。然而,默认配置下的容器安全边界存在局限,例如User Namespace未启用会导致容器内root权限映射到宿主机,一旦发生容器逃逸将带来严重风险。为构建纵深防御体系,需在基础隔离之上实施精细化权限管控。Linux Capability机制将root特权拆分为独立能力,遵循最小权限原则,通过--cap-drop=ALL和--cap-add按需授权可大幅缩减攻击面。Seccomp(安全计算模式)则通 阅读详情

相关推荐

rootlesskit:Linux原生的“假根”,用于实现无根容器

RootlessKit:使用用户名称空间Linux本地fakeroot RootlessKit是使用在Linux上实现的“假根”。 的目的是运行 ,以保护主机上的真实根免受潜在的容器突破攻击。 RootlessKit实际做什么 RootlessKit创建和 ,并执行 / 以及和 。 RootlessKit还支持使用与用户空间NAT隔离 。 实验上也支持使用启用了SUID的内核模式NAT。 类似项目 基于LD_PRELOAD工具(不足以运行无根容器,但缺乏对静态二进制文件的支持): 基于ptrace(2)工具(不足以运行无根容器,但速度较慢): 基于user_namespaces(7)工具(如--copy-up一样,但不支持--copy-up ,-- --net ,...): 使用RootlessKit的项目 集装箱发动机: (自Podman v1.8.0起) 容器图片制作工具:

Linux0.11内核源码分析1-main函数运行之前的准备

主题列表:juejin, github, smartblue, cyanosis, channing-cyan, fancy, hydrogen, condensed-night-purple, greenwillow, v-green, vue-pro, healer-readable, mk-cute, jzman, geek-black 贡献主题:https://github.com/xitu/juejin-markdown-themes theme: juejin highlight: 在阅读该文.

L25000的专栏 1586

ADS1293心电图模块实战:从电极贴片到信号采集的全流程指南

本文提供了一份基于TI ADS1293芯片的心电图采集系统全流程实战指南。文章深入探讨了从电极贴片选择与皮肤预处理、ADS1293前端配置(包括PGA、RLD和威尔逊网络),到PCB布局、电源去耦以及固件滤波与运动伪影处理等关键环节,旨在帮助硬件工程师和嵌入式开发者构建稳定可靠的可穿戴心电监测设备。

weixin_29201313的博客 384

容器技术之Chroot&Docker

chroot 容器技术从1979年chroot的首次问世便已崭露头角。 维基百科对chroot的定义如下: 是在 Unix 和 Linux 系统的一个操作,针对正在运行的软件进程和它的子进程,改变它外显的根目录。一个运行在这个环境下,经由 chroot 设置根目录的程序,它不能够对这个指定根目录之外的文件进行访问动作,不能读取,也不能更改它的内容。 通俗地说 ,chroot 就是可以改变某进程的根目录,使这个程序不能访问目录之外的其他目录,这个跟我们在一个容器中是很相似的。下面我们通过一个实例来演示

Python+大数据+数据分析+自动化+Vue组件开发 4017

BEVFusion(mit)最强环境安装,部署复现

BEVFusion作为一项经典的工作,值得深入探索。然而由于配置环境比较麻烦,耽误了一些时间。经过几次成功配置之后,有了一些总结,在这里记录下来,供大家参考避坑,也方便自己下次查阅。

qq_45783225的博客 1万+

结构力学程序算法理论基础(一)————虚功原理

1.约束 定义约束:限制质点或者质点系运动的条件称为约束,表示这些限制条件的数学方程称为约束方程。 (1)几何约束 限制质点或者质点系在空间的几何位置的条件称为几何约束.如单摆,其中质点M可绕固定点O在平面Oxy内摆动,摆长为l.这时摆杆对质点的限制条件是:质点M必须在以点O为圆心,以l为半径的圆周上运动.其约束方程为: 又质点M在固定的曲面上运动,那么曲面方程就是质点M的约束方程,即 上...

l93919861的博客 4511

linux0.11 root_dev,linux0.11/bootsect.s at master · loveveryday/linux0.11 · GitHub

.model tiny.386p;// SYSSIZE是要加载的节数(16字节为1节)。3000h共为30000h字节=192kB;// 对当前的版本空间已足够了。SYSSIZE =3000h;// 指编译连接后system模块的大小。;// 这里给出了一个最大默认值。SETUPLEN =4;// setup程序的扇区数(setup-sectors)值BOOTSEG =07c0h;// boot...

weixin_29047919的博客 350

AF3​​​​​​​ Msa、TemplateHit、HitMetadata类解读

Msa:处理 多序列比对 (MSA) 结果,为 AlphaFold3 提供 序列进化信息。 TemplateHit:存储 查询序列与模板结构的比对信息,用于 筛选模板。 HitMetadata:提供 比对模板的 PDB 结构信息,帮助 解析和使用模板数据。

qq_27390023的博客 818

linux的start函数,linux start_kernel()函数全解析

一位大师级的人物写的,不看要后悔的哟!!如果以为到了c代码可以松一口气的话,就大错特措了,linux的c也不比汇编好懂多少,相反到掩盖了汇编的一些和机器相关的部分,有时候更难懂。其实作为编写操作系统的c代码,只不过是汇编的另一种写法,和机器代码的联系是很紧密的。start_kernel在 /linux/init/main.c中定义:asmlinkage void __init start_kern...

weixin_31750655的博客 644

Boost电路双闭环控制MATLAB仿真

通过电流内环控制,我们可以改变目标平均电流基准值的大小来闭环改变占空比,再改变输出电压与电路电流,直到电路电流达到基准电流才达到稳态。但是我们的基准电流依旧是外部提供的,下边的电压外环控制就是电路自己计算基准电流。

Fourglsl的博客 5846

YOLOv5改进——添加SimAM注意力机制

这样可以使注意力机制看到整个backbone部分的特征图,将具有全局视野,类似于一个小的transformer结构。注意:很多改进教程都是将代码直接复制到common.py文件,如果改进机制多了容易造成混乱。在models文件夹下新建modules文件夹,在modules文件夹下新建一个py文件。这里为simam.py。在models文件夹下,复制yolov5s.yaml文件,粘贴并重命名为yolov5s-simam.yaml。运行yolo.py,出现刚刚加入的SimAM注意力机制,说明加入成功。

2302_80099075的博客 1653

linux 根文件系统,根设备,sys_open, sys_read, sys_write, sys_mount, sys_mknod

笔者语: 1. 内容涉及比较多,自己也没有分章节,因为觉得这些内容关联性很强,自己也懒的去弄了。 2. 本文涉及一下内容: 2.1 内核启动过程中,第一个文件系统为rootfs, 描述内核如何从rootfs切换到真正的根文件系统, 这其中包括了根设备的查找,还包括ramdisk, cpiok-initrd, image-initrd的描述。 2.2 内...

shaohui973的专栏 4145

公文流转系统

公文录入区 | QLineEdit(文号/标题)、QComboBox(公文类型/紧急程度)、QTextEdit(正文)、QListWidget(附件列表)、QPushButton(上传附件/保存草稿/提交审批) |// 按时间范围获取。QStringList userNames = {"张三", "李四", "王五", "赵六", "钱七", "孙八", "周九", "吴十", "郑十一", "王十二"};

寒寒豆豆软件公司的博客 550

runc spec 命令完全指南:从零生成 OCI 容器配置文件的实战详解

`runc spec` 是 runc(OCI 规范的参考容器运行时实现)中用于生成容器 bundle 配置文件的命令,它会在 bundle 目录下创建一份名为 `config.json` 的 OCI 运行时规范起始文件。本文以 runc 官方手册 [man/runc-spec.8.md](https://link.gitcode.com/i/23c3eceaf9542f00eaa1fd3905a6

gitblog_00680的博客 607

把 LangGraph 当“工作流引擎”用:与传统 BPM 的差异与融合策略

首先,我们来回顾一下有限状态机(FSM)的基本定义——一个 FSM 可以用一个五元组MQΣδq0FMQΣδq0​FQQQ有限状态集合,包含 FSM 所有可能的状态;Σ\SigmaΣ有限输入字母表,包含 FSM 所有可能的输入;δ\deltaδ状态转移函数,定义了 FSM 从当前状态q∈Qq \in Qq∈Q接收输入σ∈Σσ∈Σ后,转移到的下一个状态q′∈Qq' \in Qq′∈Q,即δQ×Σ→QδQ×Σ→Q。

AI 原生应用开发的博客 227

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

RunC 轻量级 容器运行工具 简介

RunC 是什么? RunC 是一个轻量级的工具,它是用来运行容器的,只用来做这一件事,并且这一件事要做好。我们可以认为它就是个命令行小工具,可以不用通过 docker 引擎,直接运行容器。事实上,runC 是标准化的产物,它根据 OCI 标准来创建和运行容器。而OCI(Open Container Initiative)组织,旨在围绕容器格式和运行时制定一个开放的工业化标准。 安装 runC RunC 是用 golang 创建的项目,因此编译它之前需要在本地安装 golang 的开发环境。Gola.

whatday的专栏 1682

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

runc 实验特性演进指南:从 cgroup v2、`runc features` 到 runc-dmz 的毕业与淘汰

> 实验特性(Experimental features)是 runc 在重大能力落地过程中的过渡机制:新功能先以实验形式发布,经过验证后再"毕业"(Graduation)为稳定能力,或被评估后直接移除。本文以 [docs/experimental.md](https://link.gitcode.com/i/77f95ab517e72cee33629346ca13f53b) 为主线,逐一梳理 r

gitblog_00311的博客 820

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

runc 集成测试指南:基于 bats 的端到端测试架构与实践

runc 的集成测试位于 [tests/integration/README.md](https://link.gitcode.com/i/6528b7f3eaa084f9cc7d78957d18ec63),它提供了对 runc 的端到端(end-to-end)验证手段,覆盖从 OCI bundle 构建、容器启动到 cgroup 资源限制生效、checkpoint/restore 等完整生命周期

gitblog_00651的博客 1034

【容器运行时-转载】RunC 是什么?

RunC 作为标准化容器运行时的一个实现目前已经被 docker 内置为默认的容器运行时。相信随着 runC 自身的成熟和完善会有越来越多的大厂把 runC 作为默认的容器运行时。OCI和runc容器标准化和dockerOCI标准和runC原理解读。

叮当猫的喵i 1717

runc 弃用时间线解析:cgroup v1 的淘汰计划与 cgroup v2 迁移实战

本篇文章以 runc 官方文档 [docs/deprecated.md](https://link.gitcode.com/i/ed2dc66a628f6e2297cb88e5a301e166) 为核心,系统梳理 runc 对 cgroup v1 的正式弃用时间线与淘汰计划,并结合 [docs/cgroup-v2.md](https://link.gitcode.com/i/1dbeecc80e1

gitblog_00544的博客 216

runc:基于 OCI 规范的 Linux 容器运行时——从源码构建到容器生命周期管理完全指南

runc 是 Open Container Initiative(OCI)规范的官方参考实现之一,一个用于在 Linux 上按 OCI 规范生成与运行容器的 CLI 工具。本文以仓库根目录 [README.md](https://link.gitcode.com/i/d07bb8a2141acdd7b240932ce851ecbc) 为主线,结合 [Makefile](https://link.g

gitblog_00825的博客 156

go-runc 使用指南:在 Go 应用中封装 runc CLI 的容器运行时客户端库(docker-ce 场景解析)

本文围绕 docker-ce 仓库内嵌的 [containerd/go-runc](https://link.gitcode.com/i/dbf13afd3b8628b59afc0d7c603c0694) 开源组件展开,讲解如何以纯 Go 的方式驱动 runc 二进制,覆盖其 Runc 客户端结构、完整命令面(生命周期、查询、事件、检查点恢复)、IO 抽象与进程监视机制,并结合 docker-ce

gitblog_00981的博客 713

runc 手册全解:OCI 运行时命令行工具的架构、命令与实战用法

runc 是一个依据 Open Container Initiative(OCI)规范实现的开源容器运行时命令行工具,用于在 Linux 上启动和运行容器。本指南以 `man/runc.8.md` 主手册为核心骨架,结合仓库内的源码实现(如 [main.go](https://link.gitcode.com/i/0d919a8f4aae0bba48cd81aa7a96db15)、[run.go]

gitblog_00533的博客 289

BuildKit Rootless 模式完全指南:以非 root 用户运行 buildkitd 的部署、容器化与排障实践

BuildKit 的 rootless 模式允许构建守护进程 `buildkitd` 以非 root 用户身份运行,从根上消除构建守护进程的 root 权限面,是共享构建机、多租户 CI 与无特权 Kubernetes 集群中的关键部署形态。本文以 [docs/rootless.md](https://link.gitcode.com/i/92d59dd66e2d47902b60c928b4d78

gitblog_01069的博客 316

runc update 命令详解:动态调整运行中容器资源限制的完整指南

runc 是依据 OCI(Open Container Initiative)规范实现容器创建与运行的命令行工具。**`runc update`** 是其核心命令之一,用于在不停止、不重建容器的情况下,动态调整**运行中容器**的 cgroup 资源约束(CPU、内存、IO 权重、PID 数量、cpuset 乃至 Intel RDT 缓存/带宽分配)。本文以 [man/runc-update.8.

gitblog_00819的博客 516

cloudpods 中的 libcontainer 深度解析:基于 runc 的 Go 容器运行时构建与生命周期管理

本篇技术文章以 cloudpods 仓库中内置(vendor)的 `github.com/opencontainers/runc` v1.1.5 版本的 libcontainer 官方文档 [libcontainer/README.md](https://link.gitcode.com/i/84ccd841a57c69f2f2c56e5fbd675758) 为核心,完整讲解 libcontain

gitblog_00777的博客 396
上一篇: AFL模糊测试
下一篇: selinux概括总结
inquisiter
博客等级 码龄10年 374粉丝 228原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值