有时候为了系统安全,会将程序进行降权,但是当需要访问当前不允许访问的资源时,如何处理呢?那就是更改自己的用户ID或组ID,使新的ID具有合适的特权或访问权限,当处理完之后,再降低其特权,下面来介绍一下,如何在程序中动态修改程序的用户ID或组ID。
进程用户ID
首先,我们需要了解,一个进程相关联的ID有多少个,下面表格介绍:
ID | 作用 |
---|
实际用户ID | 我们实际上是谁 | 实际组ID | 我们实际上是谁 | 有效用户ID | 用于文件访问权限检查 | 有效组ID | 用于文件访问权限检查 | 附属组ID | 用于文件访问权限检查 | 保存的设置用户ID | 由exec()函数保存 | 保存的设置组ID | 由exec()函数保存 |
另外,我们可以通过 getuid() 和 geteuid() 函数分别或者实际用户ID和有效用户ID,而设置用户ID我们是没有函数可以直接获取的。
动态更换用户ID
当我们在root用户下通过 chmod +s YourExe 命令给我们的可执行程序设置SUID位(“u+s”设置文件的用户ID位,“g+s”设置组ID位),这个时候,我们可以通过seteuid()函数暂时性的获得root权限。 测试代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
int main(int argc, char *argv[])
{
int fd;
unsigned char *dev_name = "/dev/input/event0";
printf("uid = %d, gid = %d euid = %d\n", getuid(), getgid(), geteuid());
fd = open(dev_name, O_RDONLY);
if (fd < 0)
printf("open %s error,errno %d\n", dev_name, errno);
else {
printf("open %s ok\n", dev_name);
close(fd);
}
seteuid(0);
printf("uid = %d, gid = %d euid = %d\n", getuid(), getgid(), geteuid());
fd = open(dev_name, O_RDONLY);
if (fd < 0)
printf("open %s error,errno %d\n", dev_name, errno);
else {
printf("open %s ok\n", dev_name);
close(fd);
}
seteuid(2);
printf("uid = %d, gid = %d euid = %d\n", getuid(), getgid(), geteuid());
fd = open(dev_name, O_RDONLY);
if (fd < 0)
printf("open %s error,errno %d\n", dev_name, errno);
else {
printf("open %s ok\n", dev_name);
close(fd);
}
}
默认的,我们user是没有 /dev 目录下节点的读取权限的,当我们去打开该节点时,将会出现报错说没有权限,但是,这个时候,如果通过 seteuid() 函数将有效用户ID设置为 root 用户(ID = 0),则可以正常访问 /dev 目录下的节点,当访问结束后,再通过 seteuid() 函数还原即可,注意,是 seteuid() 函数而不是 setuid() 函数。
实际上,上面示例在user用户环境的的工作步骤如下:
-
程序文件由root用户拥有且在设置用户ID位已设置,在user用户空间运行的,所以用户ID信息如下:
实际用户ID = 我们的用户ID 有效用户ID = 我们的用户ID 保存的设置用户ID = root
所以第一次open /dev 节点将会出现没有权限。 -
当调用 seteuid(0) 之后,由于我们已经设置了用户ID位,所以这种行为是允许的,用户ID信息将变为以下:
实际用户ID = 我们的用户ID(未改变) 有效用户ID = root 保存的设置用户ID = root(未改变)
由于当前有效用户ID为root,所以可以正常访问 /dev 节点。 -
当调用 seteuid(2) 降权之后,用户ID信息将变为以下:
实际用户ID = 我们的用户ID(未改变) 有效用户ID = 我们的用户ID 保存的设置用户ID = root(未改变)
降权后访问 /dev 将会无权限。
通过上述的配置,我们可以动态修改用户 ID,但是程序得到了额外的权限,编写这种程序时谨慎处理。
参考
《UNIX环境高级编程第3版》
|