当前位置:嗨网首页>书籍在线阅读

04-小心执行程序

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

38.3 小心执行程序

当一个特权程序通过exec()直接或通过system()、popen()以及类似的库函数间接地执行另一个程序时就需要小心处理了。

在执行另一个程序之前永久地删除权限

如果一个set-user-ID(或set-group-ID)程序执行了另外一个程序,那么就应该要确保所有的进程用户(组)ID被重置为真实用户(组)ID,这样新程序在启动时就不会拥有权限,并且也无法重新请求这些权限。完成这一任务的一种方式是在执行exec()之前使用第38.2节中介绍的技术来重置所有的ID。

在exec()调用之前调用setuid(getuid())能够取得同样的结果。虽然setuid()调用只修改了那些有效用户ID不为零的进程的有效用户ID,但权限还是会被删除,因为成功的exec()调用会将有效用户ID复制到saved set-user-ID。(如果exec()执行失败了,那么saved set-user-ID不会发生改变。这对于在exec()失败时需要执行其他特权工作的程序来讲是比较有用的。)

在set-group-ID程序中也可以采用类似的方式(即setgid(getgid())),因为成功的exec()调用也会将有效组ID复制到saved-setgroup-ID。

现在假设用户ID 200拥有一个set-user-ID程序,当ID为1000的用户执行这个程序时,结果进程的用户ID如下所示。

977.png 如果这个程序执行了setuid(getuid())调用,那么进程的用户ID将会变成如下。

978.png 当进程执行一个非特权程序时,进程的有效用户ID会被复制到saved set-user-ID,从而导致进程的用户ID变为:

979.png

避免执行一个拥有权限的shell(或其他解释器)

运行于用户控制之下的特权程序永远都不该直接或间接(通过system(), popen(), execlp(), execvp()或其他类似的库函数)地执行shell。shell(以及其他不受限的解释器,如awk)的复杂性和强大功能意味着几乎不可能消除所有的安全漏洞,即使被执行的shell不允许交互式访问。其可能引起的风险是用户可能能够在进程的有效用户ID下执行任意的shell命令。如果必须要执行shell,那么就需要确保在执行之前永久地删除权限。

在27.6节有关system()的讨论中介绍的安全漏洞就是执行shell时可能引起的一个漏洞。

一些UNIX实现在将权限位应用于解释器脚本时会采用set-user-ID和set-group-ID的权限位(参见27.3),因此当运行脚本时,执行脚本的进程的身份是其他(特权)用户。由于存在前面描述的安全风险,Linux与其他一些UNIX实现一样,在执行脚本时会毫无征兆地忽略set-user-ID和set-group-ID权限位。即使在允许set-user-ID和set-group-ID脚本的实现上也应该避免使用它们。

在exec()之前关闭所有用不到的文件描述符

在27.4节中提到过在默认情况下,在exec()调用之间文件描述符会保持在打开状态。特权进程可能会打开普通进程无法访问的文件,这种打开的文件描述符表示一种特权资源。在调用exec()之前应该关闭这种文件描述符,这样被执行的程序就无法访问相关的文件了。完成这个任务既可以通过显式关闭文件描述符,也可以设置程序的close-on-exec标记(参见27.4)。