程序存储在硬盘中,需要执行的时候被加载到内存里,内存中的程序以进程的方式运行,进程会根据程序的内容去做读写文件,执行指令等操作。
文件/指令等都有自己的执行权限,符合权限的才能被执行。相应的,进程也需要有这些权限才能执行相应的操作。
进程权限
命令 cat /proc//status | egrep "Uid|Gid" 查看进程的权限:
[root@lianhua lib]$ cat /proc/37220/status | egrep "Uid|Gid" Uid: 1004 1004 1004 1004 Gid: 1007 1007 1007 1007
以第一行为例,从左到右分别表示进程的 real user id, effective user id,saved set user id 和 filesystem UID。
各 id 的意义如下:
read user id: 进程执行者 id,从父进程那里继承来的 user id。
effective user id: 进程执行的实际 id,通过这个 id 验证进程是否有文件的访问权限。如果设置了 SUID 则进程执行时的 effective user id 会成为执行文件/程序的 owner id,这时候 effective user id 和 real user id 是不一样的。比如,passwd 命令(只有 root 才能执行)设置了 SUID,如果进程以 1004 的身份去执行 passwd, effective user id 会成为 root 的 id:
[robot@lianhua ~]$ ll /bin/passwd -rwsr-xr-x. 1 root root 27832 Jan 30 2014 /bin/passwd [robot@lianhua ~]$ passwd Changing password for user robot. Changing password for robot. (current) UNIX password: [root@lianhua ~]$ ps -lA | grep passwd 4 S 0 38063 37943 0 80 0 - 47201 wait_w pts/15 00:00:00 passwd [root@lianhua ~]$ cat /proc/38063/status | egrep "Uid|Gid" Uid: 1004 0 0 0 Gid: 1007 1007 1007 1007
saved set user id: saved set user id 相当于是一个 buffer,在 exec 函数启动之后,它会拷贝 effective user id 位的信息覆盖自己。所以从上面例子看出 saved user id 也随之改成了 root 的 id 0。
程序实现
通过一个简单的小例子加深进程权限的印象。
写一个 copy.sh 脚本,它做的事情是拷贝一个 root 权限的文件到另一个目录,然后更改这个文件的属性:
[root@lianhua lib]$ cat copy.sh #!/bin/bash sleep 10 cp /home_local/robot/systemd/tmp.log /home_local/robot/systemd/lib/ chown test /home_local/robot/systemd/lib/tmp.log rm -rf /home_local/robot/systemd/lib/tmp.log sleep 10
写个服务 copy.service 将这个脚本添加到服务中,并且更改服务中执行脚本的用户(systemd Drop-in 的方式更改)为 robot:
[root@lianhua lib]$ systemctl cat copy.service # /usr/lib/systemd/system/copy.service [Unit] Description=a test copy demo for process conflict handle Documentation=man:systemd.unit(8) [Service] Type=simple ExecStart=/bin/bash /home_local/robot/systemd/lib/copy.sh Restart=on-failure # /usr/lib/systemd/system/copy.service.d/app.conf [Service] User= User=robot
启动 copy.service ,查看进程权限 id:
[root@lianhua ~]$ systemctl status copy.service ● copy.service - a test copy demo for process conflict handle Loaded: loaded (/usr/lib/systemd/system/copy.service; static; vendor preset: disabled) Drop-In: /usr/lib/systemd/system/copy.service.d └─app.conf Active: activating (start) since Sun 2020-05-10 16:24:40 CST; 7s ago Docs: man:systemd.unit(8) Control: 40081 (bash) Memory: 432.0K CGroup: /system.slice/copy.service ├─40081 /bin/bash /home_local/robot/systemd/lib/copy.sh └─40083 sleep 10 May 10 16:33:52 lianhua systemd[1]: Starting a test copy demo for process conflict handle... May 10 16:34:02 lianhua bash[40767]: chown: changing ownership of ‘/home_local/robot/systemd/lib/tmp.log’: Opera…ermitted [root@lianhua ~]$ cat /proc/40081/status| egrep "Uid|Gid" Uid: 1004 1004 1004 1004 Gid: 1007 1007 1007 1007 [root@lianhua ~]$ ps -lAf | grep copy.service 4 S root 40075 32280 0 80 0 - 33707 poll_s 16:24 pts/15 00:00:00 systemctl restart copy.service 0 S root 40130 32507 0 80 0 - 28179 pipe_w 16:25 pts/16 00:00:00 grep --color=auto copy.service [root@lianhua ~]$ ps -lAf | grep 40081 4 S robot 40081 1 0 80 0 - 28296 do_wai 16:24 ? 00:00:00 /bin/bash /home_local/robot/systemd/lib/copy.sh 0 S robot 40098 40081 0 80 0 - 26990 hrtime 16:24 ? 00:00:00 sleep 10 [root@lianhua lib]$ ll total 4 -rw-r--r-- 1 root root 197 May 10 16:24 copy.sh -rw-r--r-- 1 robot robot 0 May 10 16:26 tmp.log [root@lianhua lib]$ cd .. [root@lianhua systemd]$ ll total 0 drwxrwxrwx 2 root root 6 May 7 11:17 bin drwxrwxrwx 2 root root 36 May 10 16:24 lib -rw-r--r-- 1 root root 0 May 7 11:17 tmp.log
从上述结果可以看出:
1. systemd 以 root 身份执行 copy.service ,它的父进程是 bash 进程 32280。
2. systemd 以 robot 身份执行 copy.sh 脚本,默认 systemd 以 root 身份去执行,这里添加了 Drop-in 文件,使得 systemd 去掉 root 而以 robot 身份去执行该脚本。进程 id 是 40081,它的父进程是 id 为 1 的 systemd 进程。
3. 执行 copy.sh 脚本会产生一个 40081 的进程来执行脚本里的内容,它的 Uid/Gid 分别是 1004(robot 用户的 Uid) 和 1007(robot 用户的 Gid)。
4. 进程在执行 cp 过程时,会更改原本权限为 root/root 的 tmp.log 文件为自己的 Uid/Gid 对应的用户身份 robot/robot。
5. 脚本中使用的 chown 命令并未设置 SUID,所以进程 40081 执行 chown 会报错,显示权限不允许。
6. sleep 命令对于用户 robot 来说时可以执行的,内核以 fork and exec 的方式执行它,产生了一个 40098 的进程,它的父进程是 40081,且执行的用户身份是继承自父进程的。
SUID and SGID
针对上述第五点,进程 40081 没办法使用 chown 命令,这里简单介绍 SUID 以及 SGID,再手动更改 chown 的 SUID 使得进程可以执行它。
SUID:
-
SUID 仅对二进程程序有效;
-
执行者对于该程序需要有 x 的可执行权限;
-
执行者将执行程序时将取得该程序所有者的权限;
-
执行者取得该程序的权限仅在运行过程 (run-time) 中有效;
SGID 也是类似的,不介绍了。
查看 chown 的权限:
[root@lianhua ~]$ which chown /usr/bin/chown [root@lianhua ~]$ ll /usr/bin/chown -rwxr-xr-x. 1 root root 62904 Dec 4 2017 /usr/bin/chown
更改 chown 使它具有 SUID 权限:
[root@lianhua ~]$ chmod 4755 /usr/bin/chown [root@lianhua ~]$ ll /usr/bin/chown -rwsr-xr-x. 1 root root 62904 Dec 4 2017 /usr/bin/chown
chmod 执行的第一个参数表示设置 SUID/SGID/SBIT,其中 4 表示 SUID,2 表示 SGID,1表示 SBIT。
以 robot 用户执行 chown 命令:
[root@lianhua ~]$ su - robot [robot@lianhua ~]$ ll /home_local/robot/systemd/lib/tmp.log -rw-r--r-- 1 robot robot 0 May 10 17:14 /home_local/robot/systemd/lib/tmp.log [robot@lianhua ~]$ chown test /home_local/robot/systemd/lib/tmp.log [robot@lianhua ~]$ ll /home_local/robot/systemd/lib/tmp.log -rw-r--r-- 1 test robot 0 May 10 17:14 /home_local/robot/systemd/lib/tmp.log [root@lianhua lib]$ systemctl status copy.service ● copy.service - a test copy demo for process conflict handle Loaded: loaded (/usr/lib/systemd/system/copy.service; static; vendor preset: disabled) Drop-In: /usr/lib/systemd/system/copy.service.d └─app.conf Active: inactive (dead) Docs: man:systemd.unit(8) May 10 17:31:03 lianhua systemd[1]: Starting a test copy demo for process conflict handle... May 10 17:31:23 lianhua systemd[1]: Started a test copy demo for process conflict handle.
robot 用户可以执行 chown 命令,服务 copy.service 顺利执行。
(完)