答案 0 :(得分:16)
system将调用shell(sh)来执行作为参数发送的命令。 system
的问题,因为shell行为取决于运行该命令的用户。一个小例子:
创建文件test.c
:
#include <stdio.h>
int main(void) {
if (system ("ls") != 0)
printf("Error!");
return 0;
}
然后:
$ gcc test.c -o test
$ sudo chown root:root test
$ sudo chmod +s test
$ ls -l test
-rwsr-sr-x 1 root root 6900 Dec 12 17:53 test
在当前目录中创建名为ls
的脚本:
$ cat > ls
#!/bin/sh
/bin/sh
$ chmod +x ls
现在:
$ PATH=. ./test
# /usr/bin/id
uid=1000(cuonglm) gid=1000(cuonglm) euid=0(root) egid=0(root) groups=0(root),
24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),105(scanner),
110(bluetooth),111(netdev),999(docker),1000(cuonglm)
# /usr/bin/whoami
root
糟糕,你有一个拥有root权限的shell。
execve不会调用shell。它执行作为第一个参数传递给它的程序。该程序必须是二进制可执行文件或以shebang行开头的脚本。
答案 1 :(得分:11)
system()
和execve()
以不同的方式工作。 system()
将始终调用shell,并且此shell将作为单独的进程执行该命令(这就是为什么在使用system()
时可以在命令行中使用通配符和其他shell工具的原因。)
execve()
(以及exec()
系列中的其他函数)将当前进程替换为直接生成的进程(execve()
函数不会返回,除非是大小写失败)。实际上system()
实现应该使用一系列fork()
,execve()
和wait()
调用来执行其功能。
当然,两者都很危险,具体取决于进程具有root权限时正在执行的操作。但是,system()
会带来一些额外的危险,因为额外的shell&#34;层&#34;它使用那个打开房间安全漏洞,因为它调用根shell,就像你的问题一样(即,进程有suid位)。
答案 2 :(得分:1)
除了system()
提到的安全问题之外,衍生进程还继承了主程序的环境。使用suid
时可能会出现问题,例如,当调用进程设置LD_LIBRARY_PATH
- 环境变量时。
使用exec()
- 系列,调用程序可以在调用exec()
之前将环境设置为所调用程序所需的(并且安全)。
当然,system()
调用的shell本身也存在安全问题。