# 特殊文件与进程
在第 6 章中讲到特殊权限 SUID、SGID、SBIT,那么这些权限对于你的 进程 是如何影响的?进程用到的系统资源,比如硬盘资源,使用 umount 硬盘时,出现提示 「device is busy」的提示是怎么回事?
# 具有 SUID、SGID 权限的指令执行状态
SUID 的权限与进程的相关性非常大,SUID 的程序是如何被一般用户执行,具有什么特色?
- SUID 权限仅对二进制程序(binary program)有效
- 执行者对于该进程需要具有 x 的可执行权限
- 本权限仅在执行程序的过程中有效(run-time)
- 执行者将具有该程序拥有者(owner)的权限
所以,整个 SUID 的权限会生效是由于具有该权限的程序被触发,一个进程表示一个程序的运行,所以执行者可以具有程序拥有者的权限就是在该程序变成进程的时候
比如执行了 passwd 后你就具有 root 的权限?是因为你再触发 passwd 后,会取得一个新的进程与 PID,该 PID 产生时通过 SUID 来给予该 PID 特殊的权限设置
下面使用 mrcode 登录系统并执行 passwd 后,通过工作控制来理解
[mrcode@study ~]$ export LANG=C
[mrcode@study ~]$ passwd
Changing password for user mrcode.
Changing password for mrcode.
(current) UNIX password: # 这里按下 ctrl + z,并按下 enter 键
[1]+ Stopped passwd
[mrcode@study ~]$ pstree -uA
systemd-+-ModemManager---2*[{ModemManager}]
|-sshd-+-sshd---sshd(mrcode)-+-bash---su(root)---bash
| | |-bash---top
| | |-bash---sleep
| | `-sftp-server
| `-sshd---sshd(mrcode)-+-bash-+-passwd(root)
| | `-pstree
| |-bash---top
| |-bash---sleep
| `-sftp-server
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
从上面的进程来看,在执行 passwd 前是 mrcode 的权限,passwd 则是 root 权限,passwd 是由 bash 衍生出来的,但是权限不一样,这样一来就能理解为什么不同程序所产生的权限不同了,是由于 SUID 程序运行过程中产生的进程的关系
[mrcode@study ~]$ type passwd
passwd is hashed (/usr/bin/passwd)
[mrcode@study ~]$ ll /usr/bin/passwd
-rwsr-xr-x. 1 root root 27856 Aug 9 2019 /usr/bin/passwd
#可以看到,的确该指令也有 s 权限
# 还可以通过以下指令查找 SUID/SGID 的文件
find / -perm /6000
2
3
4
5
6
7
8
# /proc/*
代表的意义
进程在内存中,内存中的数据都是写入到 /proc/*
目录下的,可以直接查看该目录
[mrcode@study ~]$ ll /proc/
total 0
dr-xr-xr-x. 9 root root 0 Mar 15 20:13 1
dr-xr-xr-x. 9 root root 0 Mar 15 20:13 10
dr-xr-xr-x. 9 root root 0 Mar 15 20:13 11
...
dr-xr-xr-x. 2 root root 0 Mar 15 20:54 sysvipc
-r--r--r--. 1 root root 0 Mar 15 20:54 timer_list
-rw-r--r--. 1 root root 0 Mar 15 20:54 timer_stats
dr-xr-xr-x. 4 root root 0 Mar 15 20:54 tty
-r--r--r--. 1 root root 0 Mar 15 20:16 uptime
-r--r--r--. 1 root root 0 Mar 15 20:54 version
-r--------. 1 root root 0 Mar 15 20:54 vmallocinfo
-r--r--r--. 1 root root 0 Mar 15 20:54 vmstat
-r--r--r--. 1 root root 0 Mar 15 20:54 zoneinfo
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
基本上,目前主机上面的各个进程的 PID 都是以目录的形态存在该目录中。如第 1 行的 PID 为 1,它是开机执行的第一个程序 systemd,该 PID 的所有相关信息都写入在 /proc/1/*
下面
[root@study ~]# ll /proc/1
total 0
dr-xr-xr-x. 2 root root 0 Mar 15 20:48 attr
-rw-r--r--. 1 root root 0 Mar 15 20:53 autogroup
-r--------. 1 root root 0 Mar 15 20:53 auxv
-r--r--r--. 1 root root 0 Mar 15 20:13 cgroup
-r--r--r--. 1 root root 0 Mar 15 20:13 cmdline # 指令串
-r--------. 1 root root 0 Mar 15 20:13 environ # 一些环节变量
lrwxrwxrwx. 1 root root 0 Mar 15 20:13 exe -> /usr/lib/systemd/systemd
2
3
4
5
6
7
8
9
10
里面数据很多,可以查询下 cmdline 的内容
[root@study ~]# cat /proc/1/cmdline
/usr/lib/systemd/systemd--switched-root--system--deserialize22
2
上面指令显示了是以什么参数启动的 systemd 指令,这个是针对 PID 有关的内容,下面是针对整个 Linux 系统相关的参数,对应与 /proc 目录下的文件如下
文件名 | 文件内容 |
---|---|
/proc/cmdline | 加载 kernel 时所下达的相关指令与参数,查询此文件,可了解指令是如何启动的 |
/proc/cpuinfo | 本机的 CPU 相关信息,包含频率、类型与计算功能等 |
/proc/devices | 系统各个主要装置的主要装置代号,与 mknod 有关 |
/proc/filesystems | 目前系统已经加载的文件系统 |
/proc/interrupts | 目前系统上 IRQ 分配状态 |
/proc/ioports | 目前系统上各个装置所配置的 I/O 地址 |
/proc/kcore | 内存大小,很大?不要读取该文件 |
/proc/loadavg | top 以及 uptime 的三个平均数值就是记录在这里的 |
/proc/meminfo | 使用 free 列出的内存信息,在这里也可以查询到 |
/proc/modules | 目前我们 LInux 已经加载的模块列表,可以看成是驱动程序 |
/proc/mounts | 系统已经挂载的数据,就是用 mount 指令查询出来的数据 |
/proc/swaps | 系统挂载的内存在哪里?使用掉的 partition 记录在这里 |
/proc/partitions | 使用 fsidk -l 会出现目前所有的 partition,在该文件中也有记录 |
/proc/uptime | 使用 uptime 出现的信息 |
/proc/version | 核心的版本,使用 uname -a 显示的信息 |
/proc/bus/* | 一些总线的装置,还有 USB 的装置也记录在这里 |
这些文件内容建议使用 cat 去查阅看看,不必深入了解,如果未来你要写某些工具软件,那么这个目录下相关文件可能会对你有点帮助
# 查询已开启文件或已执行进程开启之文件
还有一些与进程相关的指令可以参考与应用
# fuser:由文件(或文件系统)找出正在使用该文件的进程
fuser [-umv] [-k [i] [signal]] file/dir
选项与参数:
-u:除了进程的 PID 之外,同时列出该进程的拥有者
-m:后面接的文件名会主动的上提到该文件系统的最顶层,对 umount 不成功很有效
-v:可以列出每个文件与进程还有指令的完整相关性
-k:找出使用该文件/目录的 PID,并试图以 SIGKILL 这个信号给予该 PID
-i:必须与 -k 配合使用,在删除 PID 之前会先询问使用者
-signal:例如 -1 -15 等,若不加的话,预设是 -9:SIGKILL
2
3
4
5
6
7
8
9
# 范例 1:找出目前所在目录的使用 PID、所属账户、权限
[root@study ~]# fuser -uv .
USER PID ACCESS COMMAND
/root: root 2604 ..c.. (root)bash
2
3
4
5
有一个进程属于 root,而 ACCESS 项则略为复杂一点:
- c:此进程在当前的目录下(非次目录)
- e:可被触发为执行状态
- f:是一个被开启的文件
- r:代表顶层目录(root directory)
- F:该文件被开启了,不过在等待回应中
- m:可能为分享的动态函数库
如果想知道某个文件系统下又多少进程正在占用该文件系统时,可以使用 -m
选项
下面做几个简单测试,包括实体文件系统挂载与 /proc 虚拟文件系统的内容,看看有多少的进程对这些挂载点或其他目录的使用状态
# 范例 2:找到所有使用到 /proc 这个文件系统的进程
[root@study ~]# fuser -uv /proc/
USER PID ACCESS COMMAND
/proc: root kernel mount (root)/proc
rtkit 834 .rc.. (rtkit)rtkit-daemon
[root@study ~]# fuser -muv /proc/
USER PID ACCESS COMMAND
/proc: root kernel mount (root)/proc
root 1 f.... (root)systemd
root 589 f.... (root)systemd-journal
rtkit 834 .rc.. (rtkit)rtkit-daemon
root 844 f.... (root)udisksd
root 929 f.... (root)NetworkManager
root 1277 F.... (root)libvirtd
root 1638 F.... (root)X
gdm 1693 f.... (gdm)gnome-shell
root 1759 f.... (root)packagekitd
mrcode 2280 f.... (mrcode)top
mrcode 7722 f.... (mrcode)top
# 这就能看到有几个程序在对该目录进行存取
# 范例 3:找到所有使用到 /home 这个文件系统的进程
[root@study ~]# echo $$
2604 # 先确定下自己的 bash 的进程 PID
[root@study ~]# cd /home/
[root@study home]# fuser -muv .
USER PID ACCESS COMMAND
/home: root kernel mount (root)/home
mrcode 1346 ..c.. (mrcode)bash
mrcode 1371 ..c.. (mrcode)bash
mrcode 1378 ..c.. (mrcode)sleep
mrcode 1399 ..c.. (mrcode)sleep
mrcode 1958 ..c.. (mrcode)bash
mrcode 1991 ..c.. (mrcode)sftp-server
mrcode 1992 ..c.. (mrcode)bash
mrcode 2280 ..c.. (mrcode)top
root 2604 ..c.. (root)bash # 看这里,自己的 bash 存在列表中
mrcode 7294 ..c.. (mrcode)bash
mrcode 7358 ..c.. (mrcode)sftp-server
mrcode 7362 ..c.. (mrcode)bash
mrcode 7722 ..c.. (mrcode)top
root 8884 ..c.. (root)passwd
[root@study home]# cd ~
[root@study ~]# umount /home/
umount: /home: target is busy.
(In some cases useful info about processes that use
the device is found by lsof(8) or fuser(1))
# 通过 fuser 知道有好几个进程在该目录下运行,可以通过如下的方式一个一个删除
[root@study ~]# fuser -mki /home/
/home: 7294c 7358c 7362c 7722c 8884c 19238c 19289c 19291c 19601c 25650c 25674c 25685c 25746c
Kill process 7294 ? (y/N)
# 以上指令有一个问题,颇为棘手,就是很容易杀到自己 bash 的进程,那么久直接把直接踢掉了
# 不知道这个这么排除掉是出方便的
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
上面可以针对整个文件系统,其实也可以针对单一文件
# 范例 4:找到 /run 下属于 FIFO 类型的文件,并找出存取该文件的进程
[root@study ~]# find /run -type p
/run/dmeventd-client
/run/dmeventd-server
/run/systemd/inhibit/7.ref
/run/systemd/inhibit/6.ref
/run/systemd/inhibit/5.ref
/run/systemd/inhibit/4.ref
/run/systemd/inhibit/2.ref
/run/systemd/inhibit/1.ref
/run/systemd/sessions/13.ref
/run/systemd/sessions/5.ref
/run/systemd/sessions/c1.ref
/run/systemd/initctl/fifo
# 随便找到文件测试
[root@study ~]# fuser -uv /run/systemd/sessions/c1.ref
USER PID ACCESS COMMAND
/run/systemd/sessions/c1.ref:
root 842 f.... (root)systemd-logind
root 1649 F.... (root)gdm-session-wor
# 通常系统的 FIFO 文件都会放置到 /run 下,通过该方式来追踪该文件存取的 process
# 同样也能够看到系统有多忙碌(进程多当然就忙碌)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
fuser 的重点是可以让我们了解到某个文件系统或文件目前正在被哪些进程所使用
# lsof:列出被进程所开启的文件名
fuser 是通过文件或则装置名去找使用它的进程,而 lsof 则是通过某个进程去找它开启或使用的文件与装置
lsof [-aUu] [+d]
选项与参数:
-a:多想数据需要同时成立才显示出结果时
-U:仅列出 Unix like 系统的 socket 文件类型
-u:后面接 username,列出该使用者相关进程所开启的文件
+d:后面接目录,找出某个目录下已经被开启的文件
2
3
4
5
6
7
# 范例 1:列出目前系统上所有已经被开启的文件与装置
[root@study ~]# lsof
libvirtd 1277 1318 root mem REG 253,0 53848 9645351 /usr/lib64/libavahi-common.so.3.5.3
libvirtd 1277 1318 root mem REG 253,0 155784 8569818 /usr/lib64/libselinux.so.1
libvirtd 1277 1318 root mem REG 253,0 37056 8655202 /usr/lib64/libacl.so.1.1.0
# 文件很多很多,直接刷屏了
# 范例 2:仅列出关于 root 的所有进程开启的 socket 文件
[root@study ~]# lsof -u root -a -U
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
systemd 1 root 12u unix 0xffff8922437ed800 0t0 12513 /run/systemd/private
systemd 1 root 13u unix 0xffff892243dc2c00 0t0 25917 /run/systemd/journal/stdout
systemd 1 root 15u unix 0xffff892243e71800 0t0 25941 /run/systemd/journal/stdout
systemd 1 root 16u unix 0xffff892243e8fc00 0t0 25942 /run/systemd/journal/stdout
systemd 1 root 17u unix 0xffff892243e6ec00 0t0 26002 /run/systemd/journal/stdout
systemd 1 root 18u unix 0xffff892243e6dc00 0t0 26009 /run/systemd/journal/stdout
systemd 1 root 23u unix 0xffff89224359a800 0t0 7620 /run/systemd/notify
# 注意 -a 参数,分别执行 lsof -u root 及 lsof -U 信息都不同
# -a 取他们的交集结果
# 范例 3:列出目前系统上所有被启动的周边装置
[root@study ~]# lsof +d /dev/
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
systemd 1 root 0u CHR 1,3 0t0 5342 /dev/null
systemd 1 root 1u CHR 1,3 0t0 5342 /dev/null
systemd 1 root 2u CHR 1,3 0t0 5342 /dev/null
systemd 1 root 27r CHR 10,235 0t0 7250 /dev/autofs
systemd 1 root 30u unix 0xffff8922436ce000 0t0 7645 /dev/log
kdevtmpfs 13 root cwd DIR 0,5 3340 3 /dev
# 因为都在目录中,所以搜索目录即可
# 范例 4:列出 root 的 bash 程序开启的文件
[root@study ~]# lsof -u root | grep bash
ksmtuned 921 root txt REG 253,0 964600 309027 /usr/bin/bash
bash 20030 root cwd DIR 253,0 4096 25165889 /root
bash 20030 root rtd DIR 253,0 251 64 /
bash 20030 root txt REG 253,0 964600 309027 /usr/bin/bash
bash 20030 root mem REG 253,0 106075056 309022 /usr/lib/locale/locale-archive
bash 20030 root mem REG 253,0 61624 8548289 /usr/lib64/libnss_files-2.17.so
bash 20030 root mem REG 253,0 2156160 8532847 /usr/lib64/libc-2.17.so
bash 20030 root mem REG 253,0 19288 8532853 /usr/lib64/libdl-2.17.so
bash 20030 root mem REG 253,0 174576 8548350 /usr/lib64/libtinfo.so.5.9
bash 20030 root mem REG 253,0 163400 8532840 /usr/lib64/ld-2.17.so
bash 20030 root mem REG 253,0 26254 16946906 /usr/lib64/gconv/gconv-modules.cache
bash 20030 root 0u CHR 136,0 0t0 3 /dev/pts/0
bash 20030 root 1u CHR 136,0 0t0 3 /dev/pts/0
bash 20030 root 2u CHR 136,0 0t0 3 /dev/pts/0
bash 20030 root 255u CHR 136,0 0t0 3 /dev/pts/0
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
可以通过范例 4 找出某个进程是否有启用哪些信息
# pidof:找出某个正在运行的程序的 PID
pidof [-sx] program_name
选项与参数:
-s:仅列出一个 PID 而不列出所有的 PID
-x:同时列出该程序可能的 PPID 那个进程的 PID
2
3
4
5
# 范例 1:列出目前系统上 systemd 以及 rsyslogd 这两个程序的 PID
[root@study ~]# pidof systemd rsyslogd
1 1265
# 结果显示的是两个 PID
2
3
4
pidof 指令较简单,可配合 pas aux 与正则表示法,就可以很轻易的找到你想要的进程内容了。如果要找的是 bash,那就 pidof bash ,就列出一堆 PID 号码了
← 进程管理 SELinux 初探 →