LEC17 Singularity

预先阅读

  1. Singularity
  2. Language Support for Fast and Reliable Message-based Communication in Singularity OS

概览

Singularity是微软的研究型实验OS

  1. 该OS发表了很多相关论文,相当高调.
  2. 受到了微软OS的经验的影响,比如Windows
  3. 我们可以推测Singularity对于微软产品的影响

目标

  1. 健壮性和安全性增强,尤其针对插件
  2. 减少不必要的交互
  3. 利用最新的技术

总体架构

  1. 微内核: 内核,进程和IPC
  2. page 5声称已经将服务分解到用户流程中 2.1 NIC, TCP/IP, FS, disk driver 2.2 内核: 进程, 内存, 部分IPC, nameserver 2.3 不再追求和UNIX的兼容,因此避免了部分陷阱
  3. 最终,singularity有192个系统调用

最根本的设计理念

  1. 只有一个地址空间(不需要分段和分页功能),内核和所有进程均处于同一地址空间
  2. 用户进程均运行在特权级,即CPL=0

新设计的优势

  1. 性能提升
  2. 更快的进程切换: 不需要切换页表
  3. 更快的系统调用: 不需要INT就可以执行系统调用
  4. 更快的进程间通信: 不需要拷贝数据
  5. 用户进程可以直接访问硬件资源,比如设备驱动
  6. paper Table 1展示了性能对比的结果

新设计的核心目标

  1. 健壮性
  2. 安全性
  3. 交互

健壮性不依赖页表保护机制

  1. 不可靠的问题主要来自浏览器插件以及动态加载的内核模块
  2. 出于性能和便利性的考量,需要加载到主进程的地址空间来执行.
  3. 我们是否可以不依赖硬件,来完成健壮性保护

插件在Singularity中如何运行?

  1. 插件包含: 设备驱动,新的网络协议,浏览器插件
  2. 分隔的进程,和主进程间通过IPC通信

单地址空间遇到的挑战

  1. 阻止恶意程序访问其他进程或者内核空间
  2. 支持杀死进程和进程退出

SIP: software-isolated program

SIP总体理念

  1. 密封的
  2. 进程外部无法修改程序 2.1 除了启动和停止进程外,没有以进程号为参数的系统调用 2.2 可能没有debugger,只有IPC.
  3. 进程内部无法修改程序 3.1 没有JIT 3.2 没有class loader 3.3 没有动态库加载

SIP规则

  1. 指针只能指向本进程的数据 1.1 指针不允许指向其他SIP数据或者内核 1.2 尽管共享地址空间,但没有共享内存. 1.3 在exchange heap中传递的IPC消息,只支持有限的exception
  2. SIP可以从内核中分配物理内存 2.1 不同的分配内存是不连续的.

为什么要限制SIP的修改?即使是修改本进程?

  1. 限制的好处是什么? 1.1 没有代码注入攻击 1.2 更容易完成正确性推理 1.3 更容易做代码优化,比如删除未使用的函数 1.4 TODO: SIP可以作为一个安全原则,拥有文件
  2. 以上收益和损失相比,是否值得?

为什么不类似Java虚拟机,共享所有数据呢?

  1. SIPs排除了所有的进程间交互,除了显式的通过IPC通信
  2. SIPs更加健壮
  3. SIPs使得每个进程都有自己的语言runtime,GC等 3.1 尽管质量有一定保障,但这部分代码未必没有bug 3.2 内核代码也是同样敏感 3.3 所以开发者比较难自己准备runtime和GC
  4. SIPs使得内核杀死和退出进程比较容易

如何防止SIPs读写其他SIP的内存

  1. SIP只能读写内核分配的内存
  2. 编译器在编译时,会检查内存访问地址是否合法? 2.1 内存指针是否合法? 2.2 是否会导致代码执行速度下降 2.3 编译器是否完全可信

PL-based保护(Program-Language)

总体架构

  1. 编译为字节码.
  2. 在安装时,验证字节码
  3. 在安装事,将字节码编译为机器码
  4. 在可信的runtime,运行经过验证的机器码

问题

  1. 为什么不直接编译为机器码?
  2. 为什么不在运行时,编译运行(JIT, Just in time)?
  3. 为什么不在编译期验证字节码?
  4. 为什么不在运行期验证字节码?

对Singularity而言,字节码验证有什么好处?

字节码验证是否检查: 字节码中是否仅访问了内核分配的内存?

不完全是,但相关

  1. 仅使用可达的指针
  2. 不能创建新的指针,只有可信runtime可以创建指针
  3. 所以如果内核/运行时不提供超出SIP范围的指针,那么经验证的SIP只能访问其自身的内存.

    要达到以上目标,检查器必须检查哪些?

  4. 不要创建指针,只能使用传递的指针.
  5. 不允许类型转换,比如将int类型转换为指针.
  6. 不允许use-after-free.指针重用可以指针类型已经发生了变化.
  7. 不允许使用未初始化的变量.
  8. 总体而言,不要欺骗检查器

栗子

      R0 <- new SomeClass;
      jmp L1
      ...
      R0 <- 1000
      jmp L1
      ...
    L1:
      mov (R0) -> R1

潜在的问题

  1. 第一次jmp是没问题的,相当于读取类的第一个成员.
  2. 第二次jmp是有风险的,0x1000中的内容很有可能是指向内核.

检查器尝试解析每个寄存器的类型

  1. 尝试运行每个代码路径
  2. 要求所有路径对同一寄存器的使用结果是一致的.
  3. 所有寄存器的使用是类型安全的
  4. 这里需要判断R0是int类型还是SomeClass*类型.如果是前者,检查器会报错

字节码验证可以比Singularity需要的做的更多

  1. 创建新的指针或许也可以,只要新指针在SIP的内存范围内.
  2. 检查器可能会禁止一些在Singularity上可以运行的程序

全面检查的收益

  1. 更快的执行速度,通常不需要再进行运行时检查.个别情况除外,比如数组越界,对象转换,栈溢出等.
  2. IPC消息类型检查
  3. 需要允许交换堆读写,但这不是SIP的内存
  4. 栈内存分配
  5. 系统调用是否运行在SIP内存栈上? 5.1 防止线程X破坏线程Y的内核系统调用栈

可以在SIP中放一个解释器来规避对自修改代码的禁令

  1. 这会带来麻烦吗?

哪些部分是可信的还是不可信的?

  1. 所有软件都有bug
  2. 可信的软件: 如果有bug,可以导致Singularity crash,也可能导致其他SIP crash.
  3. 不可信的软件: 如果有bug,只能导致其自身crash.
  4. 让我们考虑一些普通的应用程序,而不是服务器. 4.1 编译器.编译器输出.验证者.验证器输出.GC.

交换堆(Exchange heap)

IPC

  1. SIPs之间如何通信?
  2. 端点(endpoints),隧道(channels)
  3. 接收端点是个消息队列
  4. 消息主体在交换堆中
  5. 特性: 无需拷贝

交换堆是共享内存

  1. 风险是什么?
  2. 发送了错误的消息类型
  3. 使用时,修改了消息
  4. 将消息修改为完全不相关的消息
  5. 耗尽了交换堆内存,并且不释放.

如何防止交换堆滥用

  1. 验证器确保SIP字节码只对交换堆中的任何内容保留一个ptr,从不保留两个及以上ptr.
  2. SIP在调用send()后,不会保留ptr.单一的指针帮助如下: 2.1 验证器知道何时ptr失效 2.2 通过send() 2.3 通过另外一个交换堆指针指向它 2.4 通过删除
  3. 单一指针防止了发送后修改的错误,也保证了完成后正确的删除.
  4. 删除必须是显式手动的,没有GC.验证器确保了每个block仅有一个指针
  5. 运行时在各个交换堆block中,维护自身的SIP入口. 5.1 通过send()更新 5.2 通过exit()来清除

接收消息如何工作?

  1. 检查共享内存中的端点,如果没有消息,则阻塞条件变量,所以发送方必须调用唤醒系统调用.

系统调用如何陷入内核?

  1. INT? CALL?
  2. 栈分布如何?
  3. 因为共用一个栈,GC如何工作?
  4. SIP可以传递一个指针给内核么?

Endpoints function as capabilities

  1. 不能传递它们
  2. 不通过channel无法和其他SIPs通信
  3. 通过使用channel来限制访问资源,比如文件

目前评估情况如何?

  1. 健壮性?
  2. 有利于扩展的模型?
  3. 性能? 3.1 在单一地址空间, 快速的系统调用, 进程切换和IPC. 3.2 论文表1, benchmarks 3.3 图5: 不安全代码的执行代价 3.3.1 物理内存 -- 不支持分页 -- 这是Singularity么? 3.3.2 支持4K分页 -- 打开分页,但是使用单一页表,且特权级均为0. 3.3.3 区域隔离 -- 为SIPs中每个SIP提供独立页表,此时进程切换会增加损耗 3.3.4 特权级3 -- CPL=3 因此INT会损耗 3.3.5 全部微内核 -- 对所有SIPs, 页表+INT

results matching ""

    No results matching ""