Linux SUID程序调用execv后未保留euid问题咨询
解决SUID程序中exec bash后特权丢失的问题
这个问题我之前排查过,核心原因是bash在SUID模式启动时会主动放弃特权,咱们来一步步拆解分析:
问题场景回顾
你编写的test.c代码片段:
printf("ruid:%d, euid:%d\n",getuid(),geteuid()); char *args[] = {"/bin/bash","-c","exec id",0}; execv("/bin/bash",args);
通过以下命令编译并设置SUID位:
sudo gcc test.c -o test sudo chmod +s ./test
程序属主为root,运行后printf输出符合预期:ruid:1000, euid:0,但后续执行的id命令却显示ruid和euid均为1000。
原因分析
你的SUID程序确实成功获取了root的有效用户ID(euid=0),这点从printf的输出可以确认。但问题出在/bin/bash的安全机制上:
当bash检测到自身是以SUID方式启动(即有效用户ID euid和实际用户ID ruid不一致)时,会自动将euid重置为ruid,主动放弃特权身份。所以当bash启动后,它已经把权限降回了普通用户(ruid=1000),此时再执行exec id,自然会显示普通用户的身份信息。
解决方案
根据你的实际需求,有几种可行的解决方式:
1. 直接执行id,跳过bash中转
不需要通过bash来执行id,直接调用execv运行id程序,这样就能保留SUID带来的特权:
printf("ruid:%d, euid:%d\n",getuid(),geteuid()); char *args[] = {"/usr/bin/id", NULL}; execv("/usr/bin/id", args);
运行后,id会正确显示euid=0。
2. 用bash的-p参数强制保留特权
bash提供了-p参数,用来关闭自动丢弃特权的行为,让它保留当前的euid身份。修改你的args数组即可:
printf("ruid:%d, euid:%d\n",getuid(),geteuid()); char *args[] = {"/bin/bash","-p","-c","exec id",0}; execv("/bin/bash",args);
添加-p后,bash不会重置euid,执行id就能看到正确的特权信息了。
3. 手动切换实际用户ID为root(谨慎使用)
如果你的程序需要全程以root身份运行,可以在exec之前调用setuid(0),将实际用户ID也设置为root:
printf("ruid:%d, euid:%d\n",getuid(),geteuid()); setuid(0); // 将实际用户ID切换为root char *args[] = {"/bin/bash","-c","exec id",0}; execv("/bin/bash",args);
⚠️ 注意:这种方法会让程序全程拥有root权限,存在一定安全风险,只有在确实需要时才使用。
内容的提问来源于stack exchange,提问作者dcnh35
相关产品推荐
相关产品推荐

