1.system函数的用法
system函数能够执行函数参数中的命令。函数的定义如下:
#include <stdlib.h>
int system(const char* cmdstring);
当cmdstring为NULL:
如果shell可用则返回非0值,否则返回0.
因为system函数在其实现中调用了fork,exec和waitopid,分解开来相当于执行了:system函数有三种返回值:
1.如果fork失败或者waitpid返回出EINTR(EINTR为中断返回的错误类型)之外的错误,则system返回-1,而且errno中设
置了错误类型值。
2.如果exec失败(表示不能执行shell),则其返回值如同shell执行了exit(127)一样。
3.否则所有三个函数都执行成功,并且system的返回值是shell的终止状态,其格式已在waitpid中说明。
下面的程序调用system函数,并对返回值进行分析:
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
void pr_exit(int status){
printf("status = %d\n", status);
if(WIFEXITED(status)){
printf("normal terminaton, exit status = %d\n", WEXITSTATUS(status));
}else if(WIFSIGNALED(status)){
printf("abnormal termination, signal number = %d%s\n",
WTERMSIG(status),
#ifdef WCOREDUMP
WCOREDUMP(status)?"(core file generated)" : "");
#else
"");
#endif
}else if(WIFSTOPPED(status)){
printf("child stopped, signal number = %d\n", WSTOPSIG(status));
}
}
int main(int argc, char* argv[]){
if(argc != 2){
printf("usage:./a.out [cmdstring]\n");
return -1;
}
int status;
status = system(argv[1]);
pr_exit(status);
return 0;
}
执行上面的程序:
yan@yan-vm:~/apue$ ./a.out nosuchcmd
sh: 1: nosuchcmd: not found
status = 32512
normal terminaton, exit status = 127
nosuchcmd不是shell支持的命令,所以,shell命令返回了127(exec失败),对于system函数,返回值为127*256 = 32512;
因为shell的返回值是 system返回值的8~15位(所以在程序中返回超过255的错误代码是无意义的)。
yan@yan-vm:~/apue$ ./a.out "ls /a/b/c"
ls: cannot access /a/b/c: No such file or directory
status = 512
normal terminaton, exit status = 2
虽然没有这个/a/b/c目录,但是命令是成功执行了,所以没有返回127,而是返回了ls /a/b/c命令的错误代码2(2*256 = 512)。
yan@yan-vm:~/apue$ ./a.out "date"
Sat Jul 27 20:48:22 CST 2013
status = 0
normal terminaton, exit status = 0
system成功执行了date,date程序退出码为0。
2.system函数的一个漏洞
使用system函数执行命令行参数(a.out):
#include <stdio.h>
int main(int argc, char* argv[]){
if(argc < 2){
printf("usage:./a.out [cmdstring]\n");
return -1;
}
if(system(argv[1])<0){
perror("system\n");
return -1;
}
return 0;
}
打印程序的uid和euid(getuid):
#include <stdio.h>
int main(void){
printf("real uid =%d, effective uid=%d.\n",getuid(),geteuid());
return 0;
}
执行结果:
yan@yan-vm:~/apue$ ./a.out /home/yan/apue/getuid
real uid =1000, effective uid=1000. //使用普通用户打印的uid和euid是正常的。
yan@yan-vm:~/apue$ su
Password:
root@yan-vm:/home/yan/apue# chown root a.out //将程序的所有者改为root
root@yan-vm:/home/yan/apue# chmod u+s a.out //设置程序的setuid标志
root@yan-vm:/home/yan/apue# ll a.out
-rwsrwxr-x 1 root yan 7443 Jul 27 22:54 a.out* //确认成功设置
root@yan-vm:/home/yan/apue# exit //退出root用户
exit
yan@yan-vm:~/apue$ ./a.out /home/yan/apue/getuid
real uid =1000, effective uid=0. //euid变成了root
我们给予a.out超级用户权限在system中执行了fork和exec后仍然保持了下来。
如果一个进程正以特殊的权限(setuid或setgid)运行,它又想生成一个程序,则它应该直接使用fork和exec,而且fork以后,exec之前
要改回到普通权限,setuid或setgid的程序决不应调用system函数。