在 C 中运行 setuid 程序的正确方法
我有一个权限为4750的进程。我的Linux系统中存在两个用户。 root 用户和 appz 用户。该进程继承以“appz”用户身份运行的进程管理器的权限。
我有两个基本例程:
void do_root (void)
{
int status;
status = seteuid (euid);
if (status < 0) {
exit (status);
}
}
/* undo root permissions */
void undo_root (void)
{
int status;
status = seteuid (ruid);
if (status < 0) {
exit (status);
}
status = setuid(ruid);
if (status < 0) {
exit (status);
}
}
我的流程如下:
int main() {
undo_root();
do some stuff;
do_root();
bind( port 80); //needs root perm
undo_root();
while(1) {
accept commads()
if ( commands needs root user access)
{
do_root();
execute();
undo_root();
}
}
正如您所看到的,我想以 root 身份执行一些命令。我试图暂时删除权限,如果任务需要 root 访问权限,我会将命令包装在 do_root 和 undo_root 调用之间。
然而我的程序似乎不起作用。
规范的方法是什么?
I have a process with permissions 4750. Two users exist in my Linux system. The root user and the appz user. The process inherits the permissions of a process manager that runs as "appz" user.
I have two basic routines:
void do_root (void)
{
int status;
status = seteuid (euid);
if (status < 0) {
exit (status);
}
}
/* undo root permissions */
void undo_root (void)
{
int status;
status = seteuid (ruid);
if (status < 0) {
exit (status);
}
status = setuid(ruid);
if (status < 0) {
exit (status);
}
}
My flow is the following:
int main() {
undo_root();
do some stuff;
do_root();
bind( port 80); //needs root perm
undo_root();
while(1) {
accept commads()
if ( commands needs root user access)
{
do_root();
execute();
undo_root();
}
}
As you can see I want to execute some commands as root. I am trying to drop permissions temporarily and if the tasks needs root access I wrap the command between a do_root and undo_root call.
However it seems that my program is not working.
What is the canonical way to do it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
老式的方法是在 do_root 和 undo_root 中使用 setreuid() 来交换 ruid 和 euid:
如果程序小到足以进行完整的安全审核,那么这是完全可以接受的。
新派的方式要复杂得多,涉及到 fork() 掉一个接受作为 root 做什么的指令的子进程,然后执行 setuid(getuid()) 永久删除父进程中的 root 权限。子进程负责验证它收到的所有指令。对于足够大的程序,这会减少必须进行安全审核的代码量,并允许用户通过作业控制来管理进程或终止它等。
The old-school way is to in both do_root and undo_root to use setreuid() to swap ruid and euid:
This is perfectly acceptable if the program is small enough to do a complete security audit.
The new-school way is far more complex and involves fork()ing off a child that accepts directives for what to do as root and then doing setuid(getuid()) to drop root permanently in the parent.. The child is responsible for validating all directives it receives. For a large enough program, this drops the amount of code that must be security audited, and allows the user to manage the process with job control or kill it, etc.
有一篇论文“Setuid 揭秘”,作者:Hao Chen 、大卫·瓦格纳和德鲁·迪恩。它在 USENIX 2002 上发布。它详细描述了 setuid() 和转换如何工作(截至 2002 年正确)。这本书非常值得一读(好几遍——我一定是逾期了一两年才重读它)。
从根本上来说,正如 Petesh 在评论中指出的那样,当 EUID 0 的进程执行
setuid(nuid)
使用nuid != 0
时,无法返回到root
(EUID 0) 权限。事实上,这一点至关重要。否则,当您登录时,让您登录的root
进程无法限制您自己的权限 - 您可以返回到root
。保存的 UID 使事情变得复杂,但我不认为它会影响 EUID 0 执行setuid()
的单向陷阱。There is a paper 'Setuid Demystified' by Hao Chen, David Wagner, and Drew Dean. It was presented at USENIX 2002. It describes how
setuid()
and transitions work in great detail (correct as of 2002). It is well worth reading (several times - I must be a year or two overdue on a re-read of it).Fundamentally, as Petesh noted in a comment, when a process with EUID 0 does
setuid(nuid)
withnuid != 0
, there is no way back toroot
(EUID 0) privileges. And, indeed, it is vital that it is so. Otherwise, when you login, theroot
process that logs you in could not limit you to your own privileges - you'd be able to get back toroot
. Saved UID complicates things, but I don't believe it affects the one-way trap of EUID 0 doingsetuid()
.setuid
手册页内容如下:这意味着您无法使用
setuid()
。您必须使用seteuid()
,也可能使用setreuid()
。有关更多详细信息,请参阅 Setuid 程序示例。The
setuid
man page says the following:Meaning that you cannot use
setuid()
. You have to useseteuid()
and, possibly,setreuid()
. See Setuid Program Example for more details.