
gVisor 安全模型深度解析应用内核如何通过纵深防御遏制容器逃逸【免费下载链接】gvisorApplication Kernel for Containers项目地址: https://gitcode.com/GitHub_Trending/gv/gvisorgVisor 是面向容器的应用内核Application Kernel for Containers其安全模型的核心目标是为运行不可信用户态代码的场景提供额外防线降低内核漏洞被利用的风险。本文以 g3doc/architecture_guide/security.md 为主线结合仓库内 Sentry 源码如 runsc/boot/filter/config/config.go、pkg/sentry/platform/systrap/README.md展开帮助你理解 gVisor 的威胁模型、攻击面缩减策略与纵深防御工程原则并掌握其在代码层面的落地方式。威胁模型一次漏洞利用的解剖要理解 gVisor 为什么这样设计首先要理解它防御的是什么。一次漏洞利用exploit通过软件或硬件缺陷来提升权限、获取特权数据或破坏服务。恶意应用与系统其余部分之间所有可能的交互途径攻击向量共同构成了攻击面attack surface。gVisor 将攻击向量归纳为以下几个常见类别。系统 APISystem API操作系统或虚拟机监控器hypervisor以系统调用system calls和陷阱traps的形式暴露一个抽象的系统 API。它可以是像 Linux 那样有文档、稳定的接口也可以像 Windows 那样被封装在库如 win32.dll、ntdll.dll之后。系统 API 包含应用程序与系统交互的全部标准接口包括由底层系统调用衍生出的高层抽象系统文件、socket 和命名空间等。虽然系统 API 是设计上就要暴露给应用的但内核或 hypervisor 内部的 bug 与竞态条件仍可能经由该 API 被利用。这很大程度上是因为大多数内核与 hypervisor 使用 C 语言编写——C 适合与硬件打交道却往往容易引入安全问题。一个典型的攻击往往组合了以下手法打开或创建若干文件、socket 或其他描述符传入精心构造的恶意参数、结构体或数据包使用多线程竞争命中特定的竞态代码路径。文档中以Dirty COW提权漏洞为例应用打开/proc下的某个特定文件或使用特定的ptrace系统调用然后借助多线程在触碰一页新内存时触发竞态条件最终获得对系统某页内存的控制权。一旦攻击者在内核中取得额外权限或接触到特权数据往往还能运用更多技巧获得对系统其余部分的完全控制。系统 API 实现中的 bug 虽然容易被修复却也是最常见的漏洞利用形式。这一攻击类别带来的暴露面正是 gVisor 旨在最小化与控制的目标。系统 ABISystem ABI有些硬件和软件漏洞存在于不属于预期系统 API 的执行路径中例如硬件或特权系统代码对陷阱、中断等事件做出响应时的隐式动作。文档引用的POPSS缺陷即属此类只需原生代码执行无需特定系统调用或文件访问即可触发且 Xen hypervisor 同样受影响——说明 hypervisor 对此类向量并非免疫。侧信道Side Channels硬件侧信道可能被系统上运行的任何代码利用无论是原生代码、沙箱内代码还是虚拟化代码。不过许多宿主级缓解措施在沙箱场景下依然有效例如基于 retpoline 构建的内核可防御部分投机执行攻击Spectre帧中毒frame poisoning可防御 L1 终端故障L1TF攻击。而 hypervisor 在此可能引入额外的复杂性在一个功能正常的虚拟机VM中没有任何缓解措施能阻止应用利用 L1TF 攻击兄弟超线程上的另一个 VM。其他向量Other Vectors上述类别远非穷尽列表——gVisor 只聚焦于在操作系统或 hypervisor 内部运行不可信代码这一场景并不考虑更泛化的对抗者交互方式例如插入带有恶意文件系统镜像的便携存储设备、构造键盘/触摸输入组合或用畸形数据包饱和网络设备等。此外高层系统本身也可能包含可利用组件。如果宿主机上存在可利用的网络可达服务或其他 API 路径攻击者甚至无需在容器内提权。沙箱不是安全架构的替代品A sandbox is not a substitute for a secure architecture。设计目标限制暴露面gVisor 的首要设计目标是通过多层防御最小化系统 API 攻击向量同时仍然提供一个进程模型。这一设计由两条主要安全原则驱动应用与宿主系统 API 的直接交互被 Sentry 拦截——由 Sentry 自己实现系统 APISentry 自身可访问的系统 API 被缩减为更小、更受限的集合。第一条原则最小化了应用直接利用宿主系统 API 的可能性第二条原则最小化了间接可利用性——即已被利用或有 bug 的 Sentry 被攻击者链式利用chaining an exploit继续攻击宿主内核的可能。与虚拟机VM的类比与差异第一条原则与虚拟机的安全基础相似。在 VM 场景中应用与宿主的交互被替换为与客户操作系统及一组虚拟化硬件设备的交互这些硬件设备再由虚拟机监控器VMM通过宿主系统 API 实现。Sentry 同样通过提供应用必须与之交互的、自己实现的系统 API 来阻止直接交互——应用无法直接为宿主系统 API 构造特定参数或标志也无法直接操作宿主原语。值得强调的是对 Sentry 和 VMM 而言直接交互虽不可能间接交互仍然存在。例如Sentry 中对宿主后备文件host-backed file的一次read最终可能触发一次宿主read系统调用由 Sentry 自己发起而非透传应用参数——这与 VM 中读取块设备可能导致 VMM 对后备文件发起相应宿主read类似。与 VM 的关键区别在于Sentry 直接基于宿主系统 API 原语实现系统 API而不是依赖虚拟化硬件和客户操作系统。这带来一组不同的权衡主要集中在性能、效率与兼容性领域由于进出沙箱的切换相对昂贵客户操作系统通常会占有资源。例如在上述例子中客户 OS 可能把块设备数据读入本地页缓存以避免后续读取从而获得更好的性能但可能浪费或复制内存导致效率较低Sentry 则选择在运行期间将许多操作延迟委派给宿主换取更高的效率但在某些使用场景下性能较低。沙箱能做什么gVisor 沙箱中的应用被允许执行标准容器能做的大多数事情读写映射进容器的文件、发起网络连接等。即便如此gVisor 仍会限制某些标准容器可能允许的操作。即使具备相应的 capabilitygVisor 沙箱中的用户也只能操纵虚拟化的系统资源如系统时间、内核设置或文件系统属性而无法操纵底层宿主系统资源。沙箱虽为应用虚拟化了大量操作但其自身与宿主的高层交互被限制在以下集合内使用已连接的 socket 与 Gofer 进程建立通信。Gofer 进程管理容器的文件系统并在请求时向沙箱提供文件描述符沙箱可直接读写这些文件描述符。沙箱自身运行在空挂载命名空间中。沙箱还可以进一步调优为拒绝所有对文件系统的访问此时所有操作都由 Gofer 代表沙箱执行发起一组最小化的宿主系统调用。这些调用不包含创建新 socket除非启用宿主网络模式或打开文件除非启用 directfs包含的是文件描述符的复制与关闭、同步、定时器与信号管理读写虚拟以太网设备的数据包。若启用了宿主网络或网络被禁用则此项非必需。系统 ABI、侧信道与其他向量的防御边界对于基于硬件的攻击系统 ABI 与侧信道类别gVisor依赖宿主操作系统与平台层进行防御。鉴于这类漏洞的性质gVisor 本身几乎无法提供额外防御——即使采用硬件虚拟化加速也是如此因为最终仍由宿主内核或 hypervisor 负责防御来自恶意客户机的攻击无法保证虚拟化、内存加密等额外硬件措施真能减小攻击面。对于资源耗尽与拒绝服务攻击gVisor 同样依赖宿主资源机制cgroups进行防御。网络策略控制应在容器层面应用以确保正确的网络策略执行。注意沙箱自身无法修改或配置这些机制而沙箱本身应使攻击者更难以通过其他手段利用或绕过这些控制。原则纵深防御Defense-in-Depth为确保系统达成设计目标gVisor 开发中采用了几条工程原则没有任何系统调用被直接透传给宿主。每个受支持的调用在 Sentry 中都有独立实现因此不太可能遭受与宿主相同的漏洞影响。其推论是应用使用的所有内核特性都需要在 Sentry 内有一份实现只实现通用的、普遍的功能。某些文件系统、网络设备或模块可能通过扩展属性、raw socket 或 ioctl 向用户态应用暴露专用功能。由于 Sentry 负责实现完整的系统调用面这类专用 API 不会被实现或透传暴露给 Sentry 的宿主面被最小化。虽然系统调用面并不小但它被显式枚举并受控。Sentry 不允许在宿主上打开新文件、创建新 socket 或做其他许多有趣的事情。此外项目还施加了若干实践性限制以最小化 Sentry 被利用的风险不安全代码被严格管控。所有 unsafe 代码被隔离在文件名以unsafe.go结尾的文件中便于验证与审计没有 unsafe 后缀的文件不得导入 unsafe 包禁止 CGo。Sentry 必须是纯 Go 二进制核心包内通常不允许外部导入。仅设置代码中允许少量外部导入。Sentry 内可用的代码被仔细管控以确保上述规则有效。最后gVisor 承认安全是一个过程保持警觉至关重要。除了安全披露流程外Sentry 被持续模糊测试fuzzed以主动发现潜在的 bug 与竞态生产崩溃会被记录与分诊以同样识别出实质性问题。源码佐证Sentry 的宿主系统调用面如何被强制执行上述最小化 Sentry 宿主面的承诺在代码中有直接体现。Sentry 进程通过seccomp-bpf 过滤器约束自己对宿主内核的系统调用相关实现在 runsc/boot/filter 目录config.go 的包注释明确写道Package config defines all syscalls the sandbox is allowed to make to the host定义沙箱允许向宿主发起的全部系统调用这正是显式枚举并受控的落地Options结构体config.go#L37-L50记录了影响过滤规则组合的开关HostNetwork宿主网络、HostNetworkRawSockets宿主 raw socket、HostFilesystem宿主文件系统/directfs、ProfileEnable、NVProxy/TPUProxy/RDMAProxyGPU/TPU/RDMA 设备代理、CgoEnabled、PluginNetwork等rules()函数config.go#L140-L176以allowedSyscalls基础白名单为起点按需合并hostInetFilters宿主网络、hostFilesystemFiltersdirectfs、平台自身的SyscallFilters等最终生成允许规则与DenyNewExecMappings拒绝规则。也就是说默认配置下 Sentry 在宿主上不能新建 socket、不能打开文件只有开启对应模式才会放行与文档描述完全一致注意Warnings()config.go#L84-L118会为每一项放宽过滤器的选项输出syscall filters less restrictive!警告提醒运维人员安全边界正在变宽filter.go#L41 的Install()负责实际安装过滤器并在debugFilter打开时把违规动作改为Trap以便输出 panic 堆栈filter.go#L28-L32 的 DEBUG TIP 注释提示怀疑 Sentry 因 seccomp 违规被杀时可将其改为true获取崩溃现场。系统调用拦截而非过滤则由平台层负责。以默认平台 Systrap 为例pkg/sentry/platform/systrap/README.md 说明Linux 允许设置SECCOMP_RET_TRAP的 seccomp 过滤器使线程一旦调用被过滤器捕获的系统调用就收到SIGSYS信号Systrap 平台利用这一特性让所有需由 Sentry 处理的线程事件系统调用、缺页、异常都以信号形式触发。新 stub 线程的初始化包括安装捕获所有用户系统调用的 seccomp 过滤器、建立与 Sentry 共享的备用信号栈、为SIGSYS/SIGSEGV/SIGBUS/SIGFPE/SIGTRAP/SIGILL安装 sysmsg 信号处理器。用户代码运行在 stub 线程上下文中一旦发起系统调用或触发缺页stub 信号处理器通知 SentrySentry 处理后回调系统线程继续执行——信号帧保存在共享内存区域使 Sentry 能读写线程状态。注意这与 ptrace 沙箱的审核并放行完全不同被捕获的调用永远不会继续进入宿主内核完成而是由 Sentry 解释并处理。FAQ这比虚拟机更安全还是更不安全VM 的安全性很大程度上取决于宿主内核与用户态支撑代码暴露了什么。例如宿主内核中的设备模拟代码如 APIC或优化如 vhost可能比一次简单系统调用更复杂利用它们同样带来风险而用户态支撑代码往往未被沙箱化一旦被利用虽然罕见可能获得对系统的无限制访问。gVisor 的部分平台复用了与 VM 相同的虚拟化硬件以获得更好的系统调用拦截性能但 gVisor不实现任何设备模拟而是选择直接使用被沙箱化的宿主系统 API。两种方案都显著缩减了原始攻击面。归根结底既然 gVisor 也能使用相同的硬件机制就不应假设仅仅使用了虚拟化硬件就让系统更安全或更不安全——就像不能因为某辆车用了整体式车身就断言它安全一样。这能阻止硬件侧信道吗一般来说gVisor 不提供针对硬件侧信道的保护尽管它可能使依赖直接访问宿主系统 API 的利用手段更难奏效。要最小化暴露面应遵循厂商的相关指引并保持宿主内核与固件及时更新。这只是个 ptrace 沙箱吗不是。ptrace 沙箱通常指使用 Linux ptrace 机制检查并授权应用发起的系统调用、强制执行特定策略的软件。这类方案常见两个问题其一易受攻击的系统调用可能被沙箱授权——因为应用仍然直接接触部分系统 API其二在不禁用多线程的前提下无法避免 TOCTOU检查时间/使用时间竞态。在 gVisor 中使用 ptrace 的平台运作方式不同被跟踪的 stub 永远不会被允许继续执行进入宿主内核并直接完成一次调用。所有系统调用都由 Sentry 解释并处理Sentry 将结果寄存器状态回写进被跟踪进程tracee然后继续在用户态执行。这与 User-Mode LinuxUML使用的机制非常相似。延伸阅读gVisor 安全入门面向安全研究者的高层介绍对比 Linux 内核安全原语、虚拟化与 gVisor 三种隔离方案并给出runsc do的快速验证示例平台架构指南深入了解 Systrap 与 KVM 两种系统调用/缺页拦截机制文件系统指南directfs 章节了解如何进一步收紧沙箱对文件系统的访问若需在本地复现文中所述行为可参考 Docker 快速开始 将 runsc 注册为容器运行时后自行验证。【免费下载链接】gvisorApplication Kernel for Containers项目地址: https://gitcode.com/GitHub_Trending/gv/gvisor创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考