Ubuntu 22.04下C程序无需system()调用执行systemctl重启服务的方法
实现SUID Root程序重启指定系统服务(Ubuntu 22.04)
核心问题原因
system()函数会启动shell进程,而Ubuntu默认shell(bash)启动时会主动重置SUID权限(安全机制),所以即便你的程序设置了SUID root,shell进程也会失去root权限,导致systemctl无法执行。解决办法是绕过shell,直接调用exec系列函数执行systemctl,这样能保留程序的SUID root权限。
方案一:SUID Root + 直接调用execvp
C代码示例(固定指定服务)
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <errno.h> int main() { // 验证SUID是否生效,确保有效用户ID为root if (geteuid() != 0) { fprintf(stderr, "Error: Program must be setuid root.\n"); return 1; } // 构造systemctl的参数列表,末尾必须以NULL结尾 char *const argv[] = { "systemctl", "restart", "someService", // 替换为你需要重启的目标服务名 NULL }; // 直接调用execvp,替换当前进程为systemctl进程 execvp(argv[0], argv); // 若execvp返回,说明执行失败,输出错误信息 perror("execvp failed"); return errno; }
编译与权限配置
- 编译程序:
gcc -o restart_service restart_service.c
- 设置程序所有者为root并添加SUID权限:
sudo chown root:root restart_service sudo chmod u+s restart_service sudo chmod a+x restart_service
完成后,任何普通用户执行./restart_service即可重启指定服务。
方案二:使用Linux Capabilities(更安全的替代方案)
SUID root权限范围过大,存在安全风险。可以通过给程序添加细粒度能力,让它无需全root权限就能执行服务重启操作:
步骤
- 编译上述C代码(无需设置SUID)。
- 给程序添加
CAP_SYSTEM_CONTROL能力(该能力允许管理systemd服务):
sudo setcap cap_system_control+ep restart_service
- 验证能力是否生效:
getcap restart_service
输出显示restart_service = cap_system_control+ep即成功,此时普通用户执行程序即可重启指定服务。
安全注意事项
- 固定服务名:不要让程序接受外部输入的服务名称,避免被滥用重启其他系统服务。
- 限制程序文件权限:执行
chmod 755 restart_service,确保只有root能修改程序,防止恶意篡改。 - 优先使用Capabilities:相比SUID root,Capabilities权限范围更小,能有效降低安全风险。
内容的提问来源于stack exchange,提问作者Sunny
相关产品推荐
相关产品推荐

