SUID或SGID程序中能不能用system函数
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程序的代码如下:
/* 这个程序的作用是获取进程的三个用户ID,它的可执行文件被做了一个软链接到/home/michael/bin下面
* */
#include<errno.h>
#include<string.h>
#include<stdlib.h>
#include<stdarg.h>
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#define BUFSIZE 512
void err_exit(char *fmt,...);
int main(int argc,char *argv[])
{
uid_t ruid,euid,suid; if(- == getresuid(&ruid,&euid,&suid))
err_exit("[getresuid]: ");
printf("real:%d\teffective:%d\tset-user:%d\n",ruid,euid,suid); return ;
}
system程序的代码如下:
#include<stdlib.h>
#include<stdio.h>
int main(int argc,char *argv[])
{
uid_t ruid,euid,suid; if(- == getresuid(&ruid,&euid,&suid))
err_exit("[getresuid]: ");
printf("real:%d\teffective:%d\tset-user:%d\n",ruid,euid,suid); system("getresuid");
return ;
}
这个system程序的功能就是首先输出进程的real uid,effective 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。
SUID或SGID程序中能不能用system函数的更多相关文章
- C程序中引用自定义的C函数模块
原文:C程序中引用自定义的C函数模块 我们知道,刚开始接触C语言编程,一般都是在一个.c或者.cpp(以下只说.c)的文件中编写代码,其中一定会有一个入口函数, 也就是main()函数,你可以将程序代 ...
- c#程序中对密码进行加密的方法
在ADO.NET中,向数据库添加数据时,怎样对数据中的密码进行加密?(也就是说在数据表中也看不到用户的密 码,只是一些经过编译后的字符串,以防止数据库管理员利用用户的密码进行非法操作.) 首先, ...
- Linux中文件的SUID、SGID、Sticky权限说明
1.SUID 首先我们要了解,在Linux中启动一个程序或者启动一个进程是需要有用户的,一个文件的存在是要有用户和组的,一个进程启动后,它的属主取决于进程的发起者,比如 我用root用户启动了一个 c ...
- linux:SUID、SGID详解
linux:SUID.SGID详解 文章转载至:http://tech.ccidnet.com/art/2583/20071030/1258885_1.html 如果你对SUID.SGID仍有迷惑可以 ...
- 特殊权限 SUID、SGID、Sticky
摘录之----------QuintinX 一. 前提 本篇主要讲解SUID, SGID, Sticky三个权限的基本原理和应用. 为什么要使用特殊权限? 比如系统中假如有超过四类人然而每一类人都需要 ...
- Linux文件权限与属性详解 之 SUID、SGID & SBIT
Linux文件权限与属性详解 之 一般权限 Linux文件权限与属性详解 之 ACL Linux文件权限与属性详解 之 SUID.SGID & SBIT Linux文件权限与属性详解 之 ch ...
- SUID、SGID详解
文章转载至:http://tech.ccidnet.com/art/2583/20071030/1258885_1.html 如果你对SUID.SGID仍有迷惑可以好好参考一下! Copyright ...
- (转)Linux 文件目录特殊权限设定(SUID,SGID,SBIT)
原文:https://blog.csdn.net/leshami/article/details/77184029 Linux文件及目录的权限设定,除了我们孰知的读写执行(rwx)之外,还有一些特殊的 ...
- 【linux命令 】文件特殊权限(SUID、SGID、SBIT)
chmod 2770 /home/admins,刚看到这个命令,有点不解,后边770分别表示用户,组,其他人,前面的2不知道代表的是什么意思.百度之后发现2是代表八进制数,也是一种权限,它的三个bit ...
随机推荐
- GNU C/C++ __attributes__ GCC中的弱符号与强符号
最近在看一些源代码,遇到了一些使用__attribute__修饰函数和变量的属性方面的代码,不是太了解,很是汗颜,再此做个总结: GCC使用__attribute__关键字来描述函数,变量和数据类 ...
- A SQLite client library written in Modern C++
smartdb是一个纯c++11开发,header-only,简洁高效的sqlite封装库. github地址:https://github.com/chxuan/smartdb,如果您觉得不错,请不 ...
- 开发工具 之 PowerDesigner
PowerDesigner是一款功能非常强大的建模工具软件,足以与Rose比肩,同样是当今最著名的建模软件之一.Rose是专攻UML对象模型的建模工具,之后才向数据库建模发展,而PowerDesign ...
- FOR XML PATH 解决联接返回结果集各记录问题
FOR XML PATH 有的人可能知道有的人可能不知道,其实它就是将查询结果集以XML形式展现,有了它我们可以简化我们的查询语句实现一些以前可能需要借助函数活存储过程来完成的工作.那么以一个实例为主 ...
- linux记录登录ip方法
PS:Linux用户操作记录一般通过命令history来查看历史记录,但是如果因为某人误操作了删除了重要的数据,这种情况下history命令就不会有什么作用了.以下方法可以实现通过记录登陆IP地址和所 ...
- NSOperation使用系统提供子类的方法--处理复杂任务
//创建一个队列 NSOperationQueue *operation=[[NSOperationQueue alloc]init]; //把任务放在NSBlockOperation里面 NSBlo ...
- ReSharper 8.0.2000.2660
user:dobit sn:G/YgFyekI7EL0oBc5YBWKI5WCi3pwXWP 下载地址
- Android学习笔记④——页面的布局方式
FrameLayout(帧布局) 这个布局的特点是简单的默认把每一个视图组件都放在边框内且放在左上角,即使添加多个视图组件,他们也都是重叠在左上角,新的视图会遮挡住旧的视图.可以根据gravity来改 ...
- 《算法导论》习题解答 Chapter 22.1-8(变换邻接表的数据结构)
一般散列表都与B+树进行比较,包括在信息检索中也是. 确定某条边是否存在需要O(1). 不足: (1)散列冲突. (2)哈希函数需要不断变化以适应需求. 另外:B+树.(见第18章) 与散列表相比的不 ...
- Plupload文件上传组件使用API
Plupload有以下功能和特点: 1.拥有多种上传方式:HTML5.flash.silverlight以及传统的<input type=”file” />.Plupload会自动侦测当前 ...