《UNIX环境高级编程》笔记--system函数

来源:互联网 发布:ubuntu显示所有软件 编辑:程序博客网 时间:2024/05/21 14:00

1.system函数的用法

system函数能够执行函数参数中的命令。函数的定义如下:

#include <stdlib.h>int system(const char* cmdstring);

当cmdstring为NULL:

如果shell可用则返回非0值,否则返回0.

因为system函数在其实现中调用了fork,exec和waitopid,分解开来相当于执行了:

1.fork  生成一个子进程。
2. 在子进程执行 execl("/bin/sh","sh","-c" cmdstring,(char*)0);
3.waitpid
使用system函数而不直接使用fork,exec的原因是,system函数进行了各种出错处理以及各种信号的处理。

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函数。

原创粉丝点击