@
tomychen @
james122333 关键问题是所谓的访问控制本来就不应该是安全特性。
一般意义上任何可预期的访问都涉及访问控制,并且没有特定的规则的限制,默认就是 DAC 。
事实上非安全上下文的访问控制普遍存在各种具有一定抽象能力的可编程上下文中。例如 C++ 和 Java 之类的所谓 OOP 语言中,private 这样的关键字就用来提供基于名称检查的数据访问控制的限制,你能把它当作“安全”么。
这种基于名称检查的访问控制是为了实现信息隐藏来提供封装性。从这个意义上来讲,所谓的就是利用名称访问资源的日常操作的一部分,只要不是检查就不用强调。
并且,不管是不是系统安全的目的,实际上还有更靠谱的:直接不提供可见的名称,连检查都不用。(例如,包括基于求值环境的隐藏,或者弱化一点,ES 的 WeakMap 之类:
https://github.com/tc39/proposal-class-fields/blob/main/PRIVATE_SYNTAX_FAQ.md#how-can-you-model-encapsulation-using-weakmaps 。)
在信息安全上下文的上下文,管理资源的 API 经常退化为 UI (例如 shell 命令),处理的输入限制也弱很多(例如 VFS 路径相对一般 PL 里的引用),这里的相关设计体现出在想象力就弱上许多,也更依赖具体名称限定的少数检查入口,以至于会滥用半吊子解决方案。
对用户来说,尽管 DAC 无处不在,去在乎权限位这种多数情况就是自欺欺人的机制只是浪费精力。
UNIX 的 FS 的这种设计其实就是附加了一些元数据,让 VFS 的系统调用保证可以获取。
这种实现手段是整体容易批判的:比一般编程机制的手段(比如说,类型系统)弱得实在发指而不成提供。
无能性首先体现在因为大部分情况下用户就不会关心这个,却又时常被坑;真要关心的时候,却又经常不顶用,而不得不指望另外的像样的 MAC 和审计措施来补救。
一部分代价跟用户是否容易误操作无关。比如,我凭什么要忍受 FS 多占用一个位来允许 drw- 这样没卵用的组合呢?(我知道扇区存储的磁盘不用纠结空间浪费,但是 tar 一下还是可以有感知的。)
并且,这还可能真的使用户增加看似便宜,实际坑爹的误操作的机会,像 chmod -R 777 这种低成本一键搞砸系统的冗余手段;如果说 rm -rf 姑且算是管理系统资源的必要手段的滥用,这就算是凭空多出来的 side channel 了。
另一方面,这种元数据就算留着,也没什么扩展性。类似的简单水平扩展,如 sticky bit ,也就是另外附加,而不是取代鸡肋设计。结果,整个设计还是同样的馊味。
于是,这样的设计,就日用来说,基本上还不如没有。如果非要实现现有 UNIX 权限位类似的功能,大可以让像样的实现(如系统级 MAC )来作为基础,重新建立适当的 UI 。
遗憾的是,不管是 SELinux 还是 NT 安全性模型,这些系统级设计都过于依赖系统机制自身,也没有充分的 UI 来让用户便于使用。但我不认为这是个安全性原则问题;易用性上的尴尬是产品力缺失的表现。
那么,为什么 UNIX 的 VFS 会特别明显地暴露这类缺陷?这恐怕根本就不是安全设计或者“用户”应该代表什么的个别问题,而是更一般意义上的“哲学”出了岔子,导致各种抽象都和开始的原意若即若离地背离,却又无法甩脱兼容性而一直被滥用。这种鸡肋抽象,最典型的就是“文件”:
cf.
https://github.com/FrankHB/pl-docs/blob/master/zh-CN/about-operating-systems.md#%E4%B8%80%E5%88%87%E7%9A%86%E6%96%87%E4%BB%B6everything-is-a-file在用户空间滥用“文件”作为首要的操作实体,与其说这是简化用户的手续(不用去学 PL 而只用学 shell ;不用认真了解怎么折腾 API 去避免非预期行为而只要等待 CLI 的反馈),倒不如说是系统设计者没能力把两种面向不同用户的可编程手段统一起来。
更一般地,这表现在对“无名师和万行码”的吹捧上——表面上看,是让 shell 干 shell 该干的活,让 C 不要掺和,属于使用合适的工具完成任务的典范;而事实上,这只是掩盖了 UNIX 祖师没能力发明出涵盖 shell 编程和更严肃的“系统”编程的统一接口而已。
比如,要是当年有像 scsh 类似的实现,现在可能就不会坚持 pid_t 乱飞导致僵尸进程这种层次的设计问题暴露给系统管理员添堵了。