Archive for 2011年2月

整洁之下的隐患

2011/02/23

上个月写了篇《技术的洁癖》比较了一下 Mac OS X 的单文件应用和 installer 两种发布手段,基本上只针对安装和卸载的完全度。不久之后看到某国企发布的一款应用的 installer 居然把 /etc 之下的所有文件权限改成『 777 』,想到单文件应用绝不会有这样的行为,所以写了这篇谈论一下安全问题。

安全是一个复杂的多层面的话题,在讨论普通 Unix 和 Windows 这样的基于 access control list 的 DAC 安全模型时,往往仅仅限于满足一个基本的要求 —— 恶意代码不能修改或者毁坏当前用户之外其他用户的和系统的数据,但是并不要求恶意代码无法修改或者毁坏当前用户自己的数据。在某些高标准的环境中,这个基本要求是远远不够的。但是对于大多数个人应用来说,只要满足这个基本要求,就可以通过系统本身的合理配置建立『沙箱』隔离恶意代码。

这个标准同样可以用来要求应用程序的发布方案:安装和卸载应用程序的过程不能修改或者毁坏当前用户之外其他用户的和系统的数据,但是并不要求恶意代码不修改或者毁坏当前用户本身的数据。

要分析这个要求是否能得到满足,先分解一下安装过程。一般来说,安装应用包括两个动作:

  1. 把应用程序的可执行文件拷贝到目标机器的硬盘(或其它存储设备)。这个过程可能包括文件的解压缩等操作 [1]。
  2. 执行一个或者多个『脚本』[2] 来创建或者修改一些配置文件。

简单考虑,如果保证每个用户拥有各自独立的可执行文件拷贝和配置文件,那么只要让安装的整个过程都只在普通用户权限下执行,前面所说的对安全的基本要求即可得到满足。

对今天的系统和大多数应用来说,保证每个用户有各自独立的配置文件不成问题,但是大多数系统都要求应用的可执行文件由所有用户共享。一般情况下,应用的可执行文件都要拷贝到系统文件夹之下。这意味着如果使用 installer ,就必须用系统管理员权限来执行。这就给了 installer 绕过『不能修改或者毁坏当前用户之外的其他用户和系统的数据』这个要求的机会。

有人会考虑把 installer 分解成两部分,分别执行上面的第一步和第二步,而只给第一部分系统管理员权限。可是,对于一个可执行的 installer ,即使名义上分成了两部分,用户也很难限制第一部分做什么,它完全可能毁坏系统数据,或者更糟,把安装的可执行文件的 ACL 设置成可提升权限 [3] ,又或者把所有系统文件的权限改写成『 777 』。这是一个看似可行但是错误的方案,因为最小权限分离仅仅适用于防止可信程序由于 bug 被恶意代码劫持权限,而 installer 在这个情景中是『可疑』的,其行为是用户不能确定的。

真正可行的办法是让用户调用操作系统的命令而非 installer 来执行第一步 [4],因为系统命令本身是可信的(trusted),即使用管理员权限运行系统命令,只要正确输入参数,其行为是用户可以确定的,不会造成危害。

上面这个过程其实就是设计应用发布方案过程中的一个需求迭代,当安全因素纳入考虑之后,迭代的结果把最初的基于 installer 的方案变成了一个类似 Mac OS X 单文件应用的方案:

  1. 单文件应用的第一步完全依靠 OS X 本身的 Finder 完成。虽然需要管理员权限,但是应用本身,即便是恶意的,也没有机会在这个过程中采取恶意行动。
  2. 单文件应用的配置文件在应用的第一次运行时生成,只要始终用普通用户运行,恶意程序没有机会毁坏其它用户和系统数据。

从这个对比可以看到,installer 确实给了有技术洁癖的人一个整洁的装饰板,可是饰板之下未必就是优雅。以高度互信作为前提的『整洁』的方案,到了『可疑』环境中可能悄悄的毁坏数据。如果非要坚持其表面的整洁,整个方案也很难通过简单的改动弥补安全方面的问题。

当然,在满足本文涉及的安全需求方面,只有单文件应用拥有优势。而 OS X 本身就存在其它安装方式,而且也在不断引入新的安装方式,比如 Photoshop 的定制 installer 和 Mac App Store。不过本文主要针对的是在不考虑 kernel 的严重 bug 的情况下,限制『可疑』应用危害的方法。而 Photoshop 和 Mac App Store 之类的方案则从其它方面提高了应用的『可信度』。那是另外一个话题了。

注释:

  1. Mac OS X 的单文件应用不包括这种操作。
  2. 这里的脚本并非狭义的纯文本解释执行的脚本文件,而是值这种配置操作实质只是一种脚本类的操作。
  3. 比如 Unix 文件系统的 s 属性,可以让一个可执行文件即使被非管理员用户执行也拥有管理员权限。
  4. 对于采用特殊的私有格式进行打包或者压缩的应用,这种操作很困难。

OpenGL 随想(四):计算机如何解决问题

2011/02/05

之前《OpenGL 随想》已经写了三篇()。题目中虽有 OpenGL,但内容并非介绍 OpenGL 或者讨论其技术细节,而是讨论学习过程中联想到的一些计算、软件方面的问题。OpenGL 主要作为引发思考的灵感和一些例子的来源。

这些联系很松散的文章被归于一个系列为的是体现研究 OpenGL 这样一个复杂系统的过程中能引发各种思考。在计算软件领域之外也有类似情况:研究第二次世界大战的历史可以引发人际关系、项目管理、市场走向等等方面的思考。这个系列算是对这些辉煌的灵感源泉一个微不足道的致敬。

聪明和笨

前几个月,有人总结:计算机系统的性能提升中,算法改进导致的部分超过了遵循摩尔定律的硬件发展所带来的部分,前者达到后者的四十多倍。考虑到数学等基础领域出现突破进展是多么困难,而另一方面硬件一直沿着摩尔定律设定的路线坚定不移地提升(指数发展,每 18 个月每单位晶体管数量增加一倍),这个数字有点让人惊讶。

换个角度想,也就是说计算性能的提高的很大一部分不是归功于电子学和材料学的进展,而是归功于人们原本采用了比较『笨』的数学方法。而且提高的幅度之大说明一开始的方法『笨』的不轻。从纯数字看似乎的确如此,但从另一个角度看这是个错觉。

OpenGL 的策略

OpenGL 和计算机三维图形领域的一些方法所体现的『聪明』可以很好的解释『笨』的含义。比如考虑一个基本的问题,在计算机图形中如何表示一个三维平滑曲面,比如一个球体?最直接的方法是把曲面的表面离散化,通过数学方法(比如球的解析式或者 NURBS 表示)求出各个离散点的坐标,然后用离散点构成平面。离散点分布越密集(术语叫采样频率高),每个平面越小,平面越多,结果就和真实的曲面越吻合。当采样频率在 viewport [1] 上的投影超过屏幕的分辨率的时候,就会和平滑曲面无异 [2]。遗憾的是,估计当今主流台式机硬件用这个方法连五年前的高端游戏效果都得不到。OpenGL 采用另一种方法:smooth-shading 。这种方法采用的采样频率不是很高,只计算每个离散点当前视角和光照条件下在 viewport 上的位置和色彩。然后在二维的 viewport 上对各个离散点的投影之间的区域进行二维色彩线性插值。也就是说,OpenGL 的曲面是在 viewport 上用二维位图处理,或者可以叫『伪 3D 』方法实现的。

正是这种『伪 3D 』方法,让个人计算机在七八年以前就实现了高度仿真的实时三维图形效果。那么是不是可以说这是一个『聪明』的方法而提高采样频率是个『笨』办法呢?并非如此。如果希望计算机图形系统能自动完成任何光照条件下对各种材质、包括反射等等效果的自动处理,特别是当仅仅知道光照条件和材料特征的情况下希望通过计算的方式得出场景呈现的效果,这是唯一的方法。OpenGL 采用的『伪 3D 』方法不能直接推演真实的效果,它所做的只是用一些近似方法得到任意的效果,而后必须由人来主观判断这些效果是否足够和真实场景接近。除平滑曲面之外,OpenGL 中通过 viewport『伪 3D 』方法来完成的效果还包括物体遮盖、半透明、反射等等。

另一个例子是阴影。如果要自动生成阴影,图形系统必需跟踪场景中物体对光源遮挡的效果。由于性能的原因,OpenGL 完全不做这种光线追踪处理,阴影效果要求程序员通过投射变换计算出位置和形状之后手工绘制的黑色或者灰色形状(只有透射变换计算本身可以通过 OpenGL 提供的函数完成)。而且,简单的投影计算只能呈现理想点光源的全影,无法实现太阳这样的面积光源形成的半影。如果要形成半影,程序员还必须自己写代码通过二维位图处理(也可以看作『伪 3D 』)算法生成阴影然后画在投影面上。同样通过手工计算完成的效果还有镜面反射等等。

OpenGL 并不是能直接从物体描述自动生成场景的虚拟照相机,大量二维位图处理的应用使它更像画具,只不过增加了一些稍稍方便和精确的三维旋转和透视的处理。用 OpenGL 直接构建应用程序的过程更接近绘画而非场景布置或者摄影。[3] 虽然从历史角度说 OpenGL 的设计不见得就真的经历了从『面向场景和摄制』到『面向绘制』的转变,但是很多惊叹 OpenGL 效果而不明就里的人头脑中确实把 OpenGL 的功能想像成前者。所以从认识的角度以及类比到更广阔的领域,OpenGL 做出的主要『优化』本质上是改变了需求或者说问题域。

这是计算机提高解决问题效率的一个主要方式:回避问题,改变问题!虽然目标仍然是为用户呈现高度真实感的虚拟场景,但是 OpenGL 几乎完全剔除了一切『虚拟现实』的能力。它采用与真实场景和摄影相比高度简化的近似方法,要求系统的构建者通过实际经历、想象力、或者其它 OpenGL 之外 [4] 的方法另行得出,甚至是事先得出真实场景应该呈现的效果,通过主观比较判断 OpenGL 的近似效果是否令人满意再对不够满意的地方做出调整。和表面的感觉不同,OpenGL 把看似精确的计算机图形变成了一个主观创意的问题。

问题域和人的价值

计算机领域的很多所谓『算法优化』其实是『问题域』的简化或者说窄化。一开始面对一个过于复杂的问题域,采用性能无法被接受的算法。而后慢慢收回过大的野心,用更粗糙的算法来满足更简单的问题。

对问题域的修改即使并非唯一方法,也是从硬件之外提升计算生产力的主要方式。比如代码优化这个问题,C++ 就开始放弃了对语义和程序员透明的原则,引入了需要程序员干预的 ROV 优化。相比之下『空间换时间』等等经典的优化理论受到硬件的制约比较大,可以视为硬件发展的附庸,比如廉价的内存才能保证大 cache 算法的可行。而且硬件的改进会让一些优化技术失效,比如近年 CPU 片内 cache 和主内存之间速度差距的迅速增大已经让编译器的『体积最大』优化策略难以换取『速度最快』的结果。

对原问题域的简化并非意味着对被简化部分的简单忽略,很多的简化是把问题中计算机可解部分和人类干预部分的合理划分 [5]。OpenGL 这样的计算机图形系统的功能必须通过各种建模工具的交互式界面和额外材料来填补其『面向绘制』问题域与普通人能胜任的『面向场景和摄制』问题域的差距,才能在人类的辅助下释放最大潜力。严格限制计算机可解部分而得到更高的计算效率,通过良好的UI 把其它交给人类解决。这也是 UI 设计的意义,精致 UI 的作用不光是让人类用户享有更好的用户体验,也是为了释放计算机自动处理部分的最大潜力。

注释:

  1. Viewport 可以理解为 OpenGL 中虚拟摄像机的底片在操作系统的窗口上的实际呈现。
  2. 这里的『无异』是在硬件呈现能力的范围内而言。不过今天的硬件也已经进入了 ratinal screen 的时代,可以说在人的感知能力范围内也可以做到『无异』了。
  3. 很多三维设计师的自我感觉更像摄影师或者场景布置师,这正是 3DS Max 或者 AutoCAD 等软件在 OpenGL 之上提供的附加值。
  4. 这种方法不一定是脱离计算机辅助的。比如上面提到的 AutoCAD 和 3DS Max 等软件的帮助。但是它们是 OpenGL 之外的。而且是通过人类主导的。
  5. 某些创造性工作或者人脑结构更适合解决的问题还能让人类保持一种优越感和尊严。