原书名:Code Quality: The Open Source Perspective
<!---->1. <!---->深入剖析著名开源软件的质量问题<o:p></o:p>
<!---->2. <!---->全面阐述C、C++和Java代码中的常见编程错误<o:p></o:p>
<!---->3. <!---->指导你编写优秀代码的圣经<o:p></o:p>
更多详细信息:http://www.china-pub.com/37661<o:p></o:p>
----------------------------------------------------------------------------------------------------------------------<o:p></o:p>
<o:p> </o:p> 3.3 竞态条件
<!----><!----><!---->在安全领域,当一个原本应该是原子操作的<!---->[1]<!---->操作分两步进行时,我们就说这里出现了竞态条件(race condition)。第一步通常是获取对象的某个数据,而第二步则使用该数据对该对象做某种操作。这种类型的竞态条件通常被称为检查与使用时差(time-of-check-to-time-of-use,TOCTTOU)错误。<o:p></o:p>
利用竞态条件进行攻击的一般方式是,特权代码代表非特权用户检查文件的访问权限,然后在该特权代码对文件做进一步的操作时,假设仍然是可以访问的。攻击者通常是在权限检查与其他文件操作之间改变目标文件,以利用竞态条件进行攻击。由于值得攻击的文件通常位于攻击者没有权限读或写的目录中,常用的手段是建立一个符号链接,指向攻击者被允许处理的文件,激活有漏洞的程序对该链接进行操作,然后在这个过程中修改链接,让它指向攻击者想要访问的文件。<o:p></o:p>
<!----><!----><!----><!----><!----><!----><!----><!---->例如,考虑图3-2<!---->[2]<!---->所示的代码片断。这段代码是pppd点对点协议守护程序的一部分,它首先禁止对该守护程序所用的端口写入广播消息(例如“UPS:系统当前使用电池操作”),端口上出现这种消息将搞乱PPP协议处理程序。在文件被打开之后(图3-2:1),该段代码使用获得的文件描述符(ttyfd)来获取并改变对应文件的访问模式(图3-2:2)。到此为止这段代码都是正确的,它使用了fstat和fchmod系统调用来直接操作文件句柄。但是,在将文件访问模式恢复到原来值的时候,该代码错误地使用了chmod系统调用。
<!---->[1]<!----> 原子操作是不能再分割的操作。
<!---->[2]<!----> netbsdsrc/usr.sbin/pppd/pppd/main.c:435-763。
<!----><!---->恶意 用户可以执行一个程序(图3-3中的cracker),该程序在pppd调用chmod之前已经将指向原来文件的链接改为指向另一个文件,欺骗pppd去修改该文件的访问权限。在我们的例子中,攻击者可以让符号链接(图3-4中的slink-file)在一开始指向他或者她具有完全访问权限的文件(rw-file),然后将其修改为指向他或者她想要获得完全访问权限的文件(passwd)。事实上,我们所检查的漏洞的确曾经是一个安全建议的主题。<!---->[1]<!---->与指定文件相关的竞态条件是可以避免的,只要在相应的系统调用中使用一个文件句柄即可:fchdir、fchflags、fchmod、fchown、fstat、fstatfs、ftruncate以及futimes。在上述例子中,将最后一个调用改成fchmod(ttyfd, tty_mode)即可解决问题。
<!---->[1]<!----> ftp://ftp.NetBSD.org/pub/NetBSD/security/advisories/NetBSD-SA2002-010.txt.asc。
<!----><!----><!----><!----><!----><!---->在阅读代码的时候如果曾遇到了access系统调用,可能就意味着遇到了一个安全问题。对于以提升了的权限运行的应用程序,系统会记录是哪个用户执行了这个应用,即真实用户(real user),以及该应用程序是以哪个用户的权限在运行,即有效用户(effective user)。对于某些任务(例如,写入某个系统文件),应用需要使用有效用户的高权限,而对于其他操作(例如,读取某个用户指定的文件),应用只应该使用真实用户的权限。这种“精神分裂”式的运行行为是需要小心谨慎才能不出乱子的,否则非常容易出安全问题。在此类应用中,调用access被认为可以验证某个进程对应的真实用户(而不是有效用户)是否可以读、写或者执行某个文件。当然,在access调用返回之后,恶意攻击者完全可以利用访问检查与实际使用某个底层对象的间隙来将通过检查的对象替换。验证进程的真实用户是否具有适当访问权限的正确方法是,放弃提升的权限(通过调用seteuid、setegid以及setgroups),然后去执行对应的操作(例如,open或者exec)。例如,如下代码中对access的调用是多余的,后续对open的调用已经足够了:<!---->[1]<!---->
<!---->[1]<!----> netbsdsrc/usr.sbin/lpr/lpr/lpr.c:136-620。
本文仅供学习交流使用,严禁抄袭和转载,如果将本文内容用于商业用途,将追究法律责任!<o:p></o:p>
好书推荐,精彩明天继续······<o:p></o:p>
对于一位Developer而言,如何编写高质量的代码也许是一个永恒的话题,这是一门艺术,需要从实践中总结经验。下面我向朋友们推荐两本集大成之作,希望能对您有所启发!<o:p></o:p>
1.《修改代码的艺术》(原书名:Working Effectively with Legacy Code)<o:p></o:p>
<!---->(1) <!---->修改代码的集大成之作<o:p></o:p>
<!---->(2) <!---->Amazon全五星图书<o:p></o:p>
<!---->(3) <!---->适用于各种语言或平台<o:p></o:p>
<!---->(4) <!---->著译双馨的佳作<o:p></o:p>
更多详细信息:http://www.china-pub.com/36363
2.《重构——改善既有代码的设计》(原书名:Refactoring: Improving the Design of Existing Code)<o:p></o:p>
<!---->(1) <!---->修改代码的集大成之作软件开发的不朽经典<o:p></o:p>
<!---->(2) <!---->生动阐述重构原理和具体做法<o:p></o:p>
<!---->(3) <!---->新添大量重构方法,使你与时俱进<o:p></o:p>
<!---->(4) <!---->丰富的词汇和背景注释,助你轻松读经典<o:p></o:p>