网站的层级,内蒙古建筑信息平台,河北住房和城乡建设厅官方网站,广告传媒网站模板system()函数的声明和说明如下#xff1a; 注意它的描述那里#xff0c;system()执行一个由command参数定义的命令#xff0c;通过调用/bin/sh -c命令来实现这个功能。也就是说它的逻辑是这样的#xff01; 进程调用system函数#xff0c;system函数调用fork创建一个子进程… system()函数的声明和说明如下 注意它的描述那里system()执行一个由command参数定义的命令通过调用/bin/sh -c命令来实现这个功能。也就是说它的逻辑是这样的 进程调用system函数system函数调用fork创建一个子进程然后再调用exec函数来把这个子进程的正文段替换成/bin/sh命令的正文段。然后再由sh来执行exec将程序的正文段替换成command参数所代表的命令的正文段例如我的一个程序a.out来调用system函数来执行sleep 20命令它的进程示意图如下所示 可以参考下面这个例子如下图所示 这里我执行了一个system文件产生了两个进程3994和3995右边那个终端所示第一列是PPID第二列是PID这两个进程是父子关系值得注意的是这两个进程进程ID是连着的也就是说在这两个进程执行的时候没有新的进程产生。 接下来开始扯正题在《APUE》UNIX环境高级编程下文不再赘述的8.13节中作者强调SUID和SGID程序中不应该调用system函数。为什么呢我个人的理解是这样的。 以SUID权限为例SUID这种权限设立的目的是什么就是提供一种可控的超级权限。比如passwd命令运行passwd这个程序后进程的有效用户ID是root理论上可以为所欲为即对shadow这个文件想怎么改就怎么改但是passwd程序的代码已经被写死了用户所做的操作都要经过passwd这个程序的检验符合标准了才能够进行否则程序就会提示出错也就是说不能像vim那样随意对shadow文件进行更改只能在某种规范下进行更改。 同时这种权限应该是有限制的不能够进行任意传播。比如像man这种能够执行shell命令的程序它执行shell命令就是通过fork-exec机制来执行了在某些distribution中有一个man用户man程序属于这个用户并且设置了SUID位。也就是说我任意一个普通用户运行man程序后的有效用户都是man如果此时这个普通用户在man程序中执行shell命令的话这个shell命令进程的有效用户应不应该是man呢设置用户ID应不应该继续保留呢当然不行啦这样的话一个普通用户不就能够通过这种方式来具有了man用户的权限了如果保留了设置用户ID那么在子进程中可以调用setuid函数来使进程的有效用户ID变成设置用户ID同样能达到上面所说的目的 OK上面说的这么一大串就是为啥SUID或者SGID程序不应该调用system函数来执行一个shell命令因为这样会传播进程的设置用户ID和有效用户ID将它传递给子进程这样就会产生bug了。理论上是这样的但是实际中我发现貌似不行我的centos6.6上就不能模拟出这个bug来比如我有这么一段程序 getresuid程序的代码如下 1 /* 这个程序的作用是获取进程的三个用户ID它的可执行文件被做了一个软链接到/home/michael/bin下面2 * */3 #includeerrno.h4 #includestring.h5 #includestdlib.h6 #includestdarg.h7 #includestdio.h8 #includesys/types.h9 #includeunistd.h
10 #define BUFSIZE 512
11 void err_exit(char *fmt,...);
12 int main(int argc,char *argv[])
13 {
14 uid_t ruid,euid,suid;
15
16 if(-1 getresuid(ruid,euid,suid))
17 err_exit([getresuid]: );
18 printf(real:%d\teffective:%d\tset-user:%d\n,ruid,euid,suid);
19
20 return 0;
21 } system程序的代码如下 1 #includestdlib.h2 #includestdio.h3 int main(int argc,char *argv[])4 {5 uid_t ruid,euid,suid;6 7 if(-1 getresuid(ruid,euid,suid))8 err_exit([getresuid]: );9 printf(real:%d\teffective:%d\tset-user:%d\n,ruid,euid,suid);
10
11 system(getresuid);
12 return 0;
13 } 这个system程序的功能就是首先输出进程的real uideffective uid和set-user id然后再来通过system函数调用getresuid程序再来把这三个uid输出一遍我把system这个可执行文件变成root所有并加上suid权限执行的结果如下图 第一个uid的输出结果是符合预期的即由于SUID权限位的设置有效用户ID是0。但是后面第二个uid的输出却和想象的有点不同理论上system函数应该是能够传递set-user ID和有效用户ID给子进程的但是这里三个UID全部都变成了500没一个是root这个可能是因为system函数在exec之前将所有三个UID都变成了实际用户ID或者是sh命令在exec之前将所有三个UID都变成了实际用户ID。 照这么看来貌似在SUID程序中调用system函数也未尝不可但是为了保险起见还是自己通过fork和exec动手来实现一个system吧然后在exec之前把三个UID都设置成实际用户ID。转载于:https://www.cnblogs.com/bwangel23/p/4239889.html