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

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

你可能感兴趣的:(《UNIX环境高级编程》笔记--system函数)