secomp的strict模式的优点是简单,限制得也很彻底。它的缺点是:
(1)允许的系统调用太少。
(2)不能对系统调用的参数进行限制,比如只允许write标准输出而不允许write其他文件。
在seccomp的后续开发中,出现了几个扩展方案。在多个扩展方案中,BPF方案胜出。BPF是Berkeley Packet Filter的缩写。此方案增加了一个模式:SECCOMP_MODE_FILTER,并在结构体seccomp中增加了一个类型为seccomp_filter的成员filter。
下面看一下seccomp_filter:
usage是一个引用计数。prev用于将filter串成链表。len表示后边数组insns的长度。数组insns存储的是filter指令。因为seccomp规定filter一旦建立就不允许修改,包括添加新的filter指令,所以后续要增加新的filter指令时,就要建立一个新的类型为seccomp_filter的filter实例,用其成员prev将旧的filter串起来。
关键的数据结构是sock_filter,用于网络系统的过滤。在引入seccomp的filter模式之前,内核中已经有用于网络包过滤的sock_filter,seccomp的filter模式利用了现成的机制:
sock_filter规定了一种指令结构,有代码、跳转和立即数。这种指令运行在一个虚拟的计算机上,称为BPF虚拟机。这个BPF虚拟机有一个累加器(accumulator),一个索引寄存器(index register),大小为16×32bit的内存(Scratch Memory Store)和一个不可见的程序计数器(program counter)。说它是虚拟机,不如说它是伪机(Pseudo Machine),因为它的某些指令要取网络包头或者系统调用号之类的数据,这些东西不在它那可怜的16×32bit内存中。不管怎么说,这种指令系统十分简单,通过它可以比较容易地定义过滤条件。下面介绍一下指令系统。
(1)加载指令
将数据加载到累加器或索引寄存器。数据来源可以是立即数(sock_filter结构体中的k)、网络包、网络包长度、内存(Scratch Memory Store)、系统调用号、系统调用的参数等。
(2)存储指令
将累加器或索引寄存器中的数据存入内存(Scratch Memory Store)。(www.xing528.com)
(3)算术和逻辑指令
对累加器中的数据执行算术或逻辑运算,运算结果存回累加器,运算参数来自索引寄存器或立即数。
(4)跳转指令
基于累加器中数值和索引寄存器中数值的比较结果,或者基于累加器中数值和立即数的比较结果,改变指令控制流。
(5)返回指令
结束处理,返回状态。
(6)其他指令
目前包含两条指令,一条用于将索引寄存器的值存入累加器,另一条用于将累加器的值存入索引寄存器。
内核执行BPF指令的代码在net/core/filter.c的sk_run_filter函数中。它是解释执行的,读一条指令,根据语义执行相应的操作。有趣的是,内核开发者引入了JIT(Just In Time)编译器,将BPF指令编译为本机指令,提高运行速度。网络包过滤的相关代码提供了使用JIT编译后指令的逻辑,在本书参考的内核版本3.14-rc4中,seccomp没有这样,还是老老实实地调用解释执行的sk_run_filter函数。
另外,为了生成BPF指令,也有些用户态工具提供编译和汇编功能,例如netsniff-ng [5] 软件包中的bpfc。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。