本节对使用超级用户模型和最小特权模型包围特权的方式进行比较。
/* Program start */ uid = getuid(); seteuid(uid); /* Privilege bracketing */ seteuid(0); /* Code requiring superuser capability */ ... /* End of code requiring superuser capability */ seteuid(uid); ... /* Give up superuser ability permanently */ setreuid(uid,uid);
此示例说明如何在最小特权模型中包围特权操作。此示例使用以下假定:
该程序为 setuid 0。
由于 setuid 0,允许集合和有效集合最初设置为所有特权。
可继承集合最初设置为基本特权。
有限集合最初设置为所有特权。
代码后面是该示例的说明。
1 #include <priv.h> 2 /* Always use the basic set. The Basic set might grow in future 3 * releases and potentially retrict actions that are currently 4 * unrestricted */ 5 priv_set_t *temp = priv_str_to_set("basic", ",", NULL); 6 /* PRIV_FILE_DAC_READ is needed in this example */ 7 (void) priv_addset(temp, PRIV_FILE_DAC_READ); 8 /* PRIV_PROC_EXEC is no longer needed after program starts */ 9 (void) priv_delset(temp, PRIV_PROC_EXEC); 10 /* Compute the set of privileges that are never needed */ 11 priv_inverse(temp); 12 /* Remove the set of unneeded privs from Permitted (and by 13 * implication from Effective) */ 14 (void) setppriv(PRIV_OFF, PRIV_PERMITTED, temp); 15 /* Remove unneeded priv set from Limit to be safe */ 16 (void) setppriv(PRIV_OFF, PRIV_LIMIT, temp); 17 /* Done with temp */ 18 priv_freeset(temp); 19 /* Now get rid of the euid that brought us extra privs */ 20 (void) seteuid(getuid()); 21 /* Toggle PRIV_FILE_DAC_READ off while it is unneeded */ 22 priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ, NULL); 23 /* Toggle PRIV_FILE_DAC_READ on when special privilege is needed*/ 24 priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ, NULL); 25 fd = open("/some/retricted/file", O_RDONLY); 26 /* Toggle PRIV_FILE_DAC_READ off after it has been used */ 27 priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ, NULL); 28 /* Remove PRIV_FILE_DAC_READ when it is no longer needed */ 29 priv_set(PRIV_OFF, PRIV_ALLSETS, PRIV_FILE_DAC_READ, NULL);
该程序定义了名为 temp 的变量。temp 变量确定此程序不需要的特权集合。最初,在第 5 行将 temp 定义为包含基本特权集合。在第 7 行将 file_dac_read 特权添加到 temp 中。proc_exec 特权对 exec(1) 新进程(在此程序中不允许)是必需的。因此,在第 9 行中从 temp 中删除了 proc_exec,从而使 exec(1) 命令无法执行新进程。
此时,temp 仅包含该程序所需的那些特权,即基本集合加上 file_dac_read,再删除 proc_exec。在第 11 行中,priv_inverse() 函数将计算 temp 的逆向值,并将 temp 的值重置为逆向值。逆向值是从所有可能特权集合中删除指定集合(在本例中为 temp)所得的结果。作为第 11 行的结果,temp 现在包含该程序永不使用的那些特权。在第 14 行中,从允许集合中删除了 temp 定义的不需要的特权。此删除操作还从有效集合中有效地删除了这些特权。在第 16 行中,从有限集合中删除了不需要的特权。在第 18 行中,因为不再需要 temp,因而释放了 temp 变量。
该程序可以识别特权。因此,该程序不使用 setuid,但可以将有效的 UID 重置为第 20 行中的用户的实际 UID。
在第 22 行中,通过从有效集合中删除 file_dac_read 特权禁用了该特权。在实际的程序中,需要 file_dac_read 特权之前,还将发生其他活动。在该样例程序中,读取第 25 行中的文件需要 file_dac_read。因此,在第 24 行中,启用了 file_dac_read。读取文件后,将再次从有效集合中立即删除 file_dac_read。读取所有文件后,通过在所有特权集合中禁用 file_dac_read,可永久地删除 file_dac_read。
下表说明了随着程序的运行如何转换特权集合。已指出了行号。
|