如果一个进程从一个 setuid 二进制 forks 开始,并且子进程放弃了特权,那么这个子进程仍然可以信任吗?
If a process started from a setuid binary forks, and the child drops privileges, can the child still be trusted?
假设以下程序是由非 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()
,或者在不应该的情况下强制子进程为 return 0? (假设 kernel.yama.ptrace_scope
设置为 0。)
ptrace
手册页指定它将(我强调的):
Deny access if neither of the following is true:
The real, effective, and saved-set user IDs of the target match the caller's user ID, and the real, effective, and saved-set
group IDs of the target match the caller's group ID.
The caller has the CAP_SYS_PTRACE
capability in the user namespace of the target.
因此,如果跟踪器无法使用已保存的 UID,则跟踪进程无法附加和劫持 child 来访问它。
如果 child 不可撤销地删除其 EUID(使用 setresuid()
),则跟踪进程可以附加,但没有保存的 UID 可供滥用。
假设以下程序是由非 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()
,或者在不应该的情况下强制子进程为 return 0? (假设 kernel.yama.ptrace_scope
设置为 0。)
ptrace
手册页指定它将(我强调的):
Deny access if neither of the following is true:
The real, effective, and saved-set user IDs of the target match the caller's user ID, and the real, effective, and saved-set group IDs of the target match the caller's group ID.
The caller has the
CAP_SYS_PTRACE
capability in the user namespace of the target.
因此,如果跟踪器无法使用已保存的 UID,则跟踪进程无法附加和劫持 child 来访问它。
如果 child 不可撤销地删除其 EUID(使用 setresuid()
),则跟踪进程可以附加,但没有保存的 UID 可供滥用。