内容纲要

proc文件

Linux 内核提供了一种通过 proc 文件系统,在运行时访问内核内部数据结构、改变内核设置的机制。

proc 文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。它以文件系统的方式为访问系统内核数据的操作提供接口

用户和应用程序可以通过 proc 得到系统的信息,并可以改变内核的某些参数。由于系统的信息,如进程,是动态改变的,所以用户或应用程序读取 proc 文件时,proc 文件系统是动态从系统内核读出所需信息并提交的

在 proc 下还有三个很重要的目录:net,scsi 和 sys。

sys 目录是可写的,可以通过它来访问或修改内核的参数。

而 net 和 scsi 则依赖于内核配置。

例如,如果系统不支持 scsi,则 scsi 目录不存在。

系统中当前运行的每一个进程都有对应的一个目录在 proc 下,以进程的 PID 号为目录名,它们是读取进程信息的接口。而 self 目录则是读取进程本身的信息接口,是一个 link。

image-20210509005532815

image-20210509012219929

/proc/self

这是一个link,当进程访问此链接时,就会访问这个进程本身的/proc/[pid]目录

image-20210509013846399

/proc/thread-self

这是一个link,当访问次链接时,就会访问进程的/proc/self/task/[tid]目录。

image-20210509014115525

/prco/[pid]

每一个运行的进程都存在pid,对应的在/proc就存在一个/proc/pid的目录.

每一个/proc/pid目录中还存在一系列目录和文件,这些文件和目录记录的都是关于pid对应进程的信息

image-20210509012555870

例如,在/proc/[pid]的目录下存在一个task目录,在task目录下又存在task/[tid]这样的目录,这个目录就是包含此进程中的每个线程的信息,其中的tid是内核线程的tid;通过 GETDENTS(2) 遍历/proc就能够看到所有的/proc/pid的目录,当然通过 ls -al /proc的方式也可以看到所有的信息.

image-20210509012848548

image-20210509013056485

通常情况下每个/proc/pid是属于运行进程的有效用户的UID和GID.但是如果一个进程的dumpable属性的值大于1,从安全角度考虑,/proc/pid的属性就是root:root.

在4.11的内核版本之前,root:root表示的是全局UID(userid)和GID (groupid)(在初始化的用户空间中的UID和GID都是0).但是在4.11之后的内核版本,如果这个进程不是在初始化的用户空间中,它的UID却是0,那么对应的/proc/pid的权限也是root:root.这就意味着在docker容器内,如果将进程的PID设置为0,那么这个进程在容器内就是以root权限运行的。

进程的dumpable的属性可能因为如下的原先发生改变:

  • 通过 prctl 设置了 PR_SET_DUMPABLE 属性
  • 通过 /proc/sys/fs/suid_dumpable文件修改

将dumpable重置为1,就可以恢复/proc/[pid]/*文件到进程有效的UID和GID.

/proc/[pid]/attr

/proc/pid/attr是一个目录,这个目录下的文件的作用是为安全模块提供了API.通过这些文件我们可以读取或者设置一些安全相关的选项.这个目录目前能够支持SELinux,但是本意是为了能够支持更多的其他的安全模块。

image-20210509015720119

/proc/[pid]/attr/current

记录了当前进程的安全属性。

/proc/[pid]/attr/exec

给进程的execve(内核级系统调用)的属性。

/proc/[pid]/attr/fscreate

进程与文件有关的权限。(包括open mkdir symlink mknod)

/proc/[pid]/attr/keycreate

如果进程将安全上下文写入此文件,那么所有创建key的行为都会被加载到此上下文中。

/proc/[pid]/attr/prev

进程在执行最后一个execve的安全上下文.

/proc/[pid]/attr/socketcreate

如果一个进程向这个文件写入安全上下文,那么之后所有的sockets的创建行为都会在此进程上下文中。

/proc/[pid]/autogroup

sched-CPU调度

/proc/[pid]/auxv

/proc/[pid]/auxv 包含在进程执行时传递给进程的 ELF 解释器信息,格式是每一项都是一个 unsigned long长度的 ID 加上一个 unsigned long 长度的值。最后一项以连续的两个 0x00 开头。

image-20210509011356491

但并不是都能显示

image-20210509011535135

auxv

/proc/[pid]/cmdline

只读文件,包含了进程执行的完整命令。如果此进程是一个僵尸进程,那么次文件没有任何的内容。

/proc/[pid]/comm

记录进程命令的comm包含进程的命令名。在同一个进程中的不同线程的comm可能不同,可以访问/proc/[pid]/task/[tid]/comm获取进程中的每个线程的comm。通过向/proc/self/task/tid/comm写入就能够修改自己或者其他线程的comm.如果comm超过TASK_COMM_LEN(16)就会被截断。

这个文件的值可以通过 prctl(2) 的PR_SET_NAME和PR_GET_NAME的操作来设置和获取,通过 pthread_setname_np(3) 能够设置线程的comm

image-20210509022117030

/proc/[pid]/cwd

当前的进程的工作目录的符号链接。

image-20210509021802687

在bash环境下,可能会出现/bin/pwd: couldn’t find directory entry in ‘..’ with matching i-node的错误,这是因为pwd通常是shell内置的,需要使用这样的命令:

/proc/4451/cwd; pwd -P

在多线程的程序中,如果主线程已经退出了,那么cwd的结果就是空.
取消或者是读取(readlink(2))这个链接的内容的权限是由ptrace的访问模式PTRACE_MODE_READ_FSCREDS来控制的,参考ptrace(2)

image-20210509022316389

/proc/[pid]/environ

显示进程的环境变量。

image-20210509022521191

/proc/[pid]/exe

实际运行程序的符号链接。

image-20210509022632527

/proc/[pid]/fd

一个目录,包含进程打开文件的情况。

image-20210509022820697

/proc/[pid]/maps

显示进程的内存区域映射信息。

image-20210509023150639

[stack:] 是线程的堆栈信息,对应于 /proc/[pid]/task/[tid]/ 路径。

/proc/[pid]/stack

当前进程的内核调用栈信息,只有内核编译时打开了 CONFIG_STACKTRACE 编译选项,才会生成这个文件。

image-20210509023258364

image-20210509023814291

/proc/[pid]/statm

显示进程所占用内存大小的统计信息。包含七个值,度量单位是 page(page大小可通过 getconf PAGESIZE 得到)。

各个值含义:

a)进程占用的总的内存
b)进程当前时刻占用的物理内存
c)同其它进程共享的内存
d)进程的代码段
e)共享库(从2.6版本起,这个值为0)
f)进程的堆栈
g)dirty pages(从2.6版本起,这个值为0)

image-20210509023403462

/proc/[pid]/status

包含进程的状态信息。其很多内容与 /proc/[pid]/stat 和 /proc/[pid]/statm 相同,但是却是以一种更清晰地方式展现出来。

zhoujingni@ubuntu:/proc/4060$ cat status
Name:   gvfsd-dnssd
Umask:  0002
State:  S (sleeping)
Tgid:   4060
Ngid:   0
Pid:    4060
PPid:   3073
TracerPid:  0
Uid:    1000    1000    1000    1000
Gid:    1000    1000    1000    1000
FDSize: 64
Groups: 4 24 27 30 46 116 126 1000 
NStgid: 4060
NSpid:  4060
NSpgid: 3073
NSsid:  3073
VmPeak:   441476 kB
VmSize:   375940 kB
VmLck:         0 kB
VmPin:         0 kB
VmHWM:      7636 kB
VmRSS:      7440 kB
RssAnon:         924 kB
RssFile:        6516 kB
RssShmem:          0 kB
VmData:    34036 kB
VmStk:       132 kB
VmExe:        28 kB
VmLib:     11696 kB
VmPTE:       236 kB
VmSwap:        0 kB
HugetlbPages:          0 kB
CoreDumping:    0
THP_enabled:    1
Threads:    3
SigQ:   0/7645
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000001000
SigCgt: 0000000180000800
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
NoNewPrivs: 0
Seccomp:    0
Speculation_Store_Bypass:   thread vulnerable
Cpus_allowed:   ffffffff,ffffffff,ffffffff,ffffffff
Cpus_allowed_list:  0-127
Mems_allowed:   00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001
Mems_allowed_list:  0
voluntary_ctxt_switches:    138
nonvoluntary_ctxt_switches: 61

关于信号(signal)的信息:SigQ 分为两部分(例如 0/7645),前面表示当前处在队列中的信号(0),后面则表示队列一共可以存储多少信号(7645);

SigPnd 表示当前线程 pending 的信号,而ShdPnd 则表示整个进程 pending 的信号;

SigBlk、SigIgn 和 SigCgt 分别表示对信号的处理是阻塞,忽略,捕获。

proc/[pid]/syscall

/proc/[pid]/syscall 显示当前进程正在执行的系统调用。

image-20210509023755279

第一个值是系统调用号,后面跟着 6 个系统调用的参数值(位于寄存器中),最后两个值依次是堆栈指针和指令计数器的值。如果当前进程虽然阻塞,但阻塞函数并不是系统调用,则系统调用号的值为 -1,后面只有堆栈指针和指令计数器的值。如果进程没有阻塞,则这个文件只有一个 running 的字符串。

内核编译时打开了 CONFIG_HAVE_ARCH_TRACEHOOK 编译选项,才会生成这个文件。

https://www.hi-linux.com/posts/64295.html#vip-container

超详细的proc文件介绍