比方说,以下程序是由非root用户从setuid-root二进制文件执行的:
int main()
{
if (fork()) {
/* Parent process */
int wstatus; wait(&wstatus);
if (WEXITSTATUS(wstatus) == 0) {
/* Child process exited with return code indicating success */
do_something_potentially_dangerous();
return 0;
} else {
/* Child process exited with return code indicating failure */
puts("Access denied");
return 1;
}
} else {
/* Child process */
setuid(getuid());
/*
...
*/
return do_critical_security_check(); /* let's say this returns 0 if it's safe */
}
}
setuid程序通常以额外的安全措施运行,以防止启动它的用户篡改其(特权)执行。我只能假定在派生子进程时会保留此状态。
但是,当子进程放弃root特权时,它也失去任何这种保护吗?除非子进程的代码中存在漏洞,否则非特权用户将能够干扰do_critical_security_check()
,否则将迫使子进程在不应该返回0的情况下返回? (假设kernel.yama.ptrace_scope
设置为0。)
ptrace
手册页指定它将((我强调):
如果以下都不是],则拒绝访问:
目标的真实,有效,和
保存设置用户ID与呼叫者的用户ID相匹配,并且真实,有效和保存的设置目标的组ID与呼叫者的组ID相匹配。调用方在目标的用户名称空间中具有
CAP_SYS_PTRACE
功能。因此,如果存在跟踪者不可用的已保存UID,则跟踪过程将无法附加并劫持孩子以访问它。
如果孩子无法撤销地放弃其EUID(使用setresuid()
,则跟踪过程可以附加,但没有保存的UID可供滥用。