Linux的`/proc文件系统`学习


=Start=

缘由:

在部分场合下要用到/proc文件系统的知识,所以需要较为深入的学习了解一下相关知识,方便以后使用。

正文:

参考解答:
虚拟文件系统

/proc 文件系统是一个虚拟文件系统,通过它可以使用一种新的方法在 Linux 内核空间和用户空间之间进行通信。最初开发 /proc 文件系统是为了提供有关系统中进程的信息。但是由于这个文件系统非常有用,因此内核中的很多元素也开始使用它来报告信息,或启用动态运行时配置(sysctl 命令是另外一种实现动态内核配置的方法)。

这个虚拟文件系统让你可以和内核内部数据结构进行交互,获取有关进程的有用信息,在运行中(on the fly)改变设置(通过改变内核参数)。与其他文件系统不同,/proc 存在于内存之中而不是硬盘上。所以在对 /proc 进行一次 `ls -l` 时可以看到大部分文件都是 0 字节大的;不过在实际查看(cat/more/less)这些文件的时候,确实可以看到一些信息。这怎么可能?这是因为 /proc 文件系统和其他常规的文件系统一样把自己注册到虚拟文件系统层(VFS)了。然而,直到当 VFS 调用它,请求文件、目录的 i-node 的时候,/proc 文件系统才根据内核中的信息建立相应的文件和目录。

查看

获取系统/内核信息

/proc 文件系统可以被用于收集有用的关于系统和运行中的内核的信息。下面是一些重要的文件:

  • /proc/cpuinfo – CPU 的信息 (型号, 家族, 缓存大小等)
  • /proc/meminfo – 物理内存、交换空间等的信息
  • /proc/mounts – 已加载的文件系统的列表
  • /proc/devices – 可用设备的列表
  • /proc/filesystems – 被支持的文件系统
  • /proc/modules – 已加载的模块
  • /proc/version – 内核版本
  • /proc/cmdline – 系统启动时输入的内核命令行参数

需要说明的是 /proc 文件系统中的文件远不止上面列出的这么多。想要进一步了解的读者可以对 /proc 的每一个 文件都`less`一下或读参考文献以获取更多的有关 /proc 目录中的文件的信息。我建议使用`less`而不是`cat`,除非你知道这个文件很小,因为有些文件(比如 kcore)可能会非常长。

获取进程信息

/proc 文件系统可以用于获取正在运行中的进程的信息。在 /proc 中有一些数字编号的子目录,每个数字编号的目录对应一个进程id(PID)。这样,每一个运行中的进程 /proc 中都有一个用它的 PID 命名的目录。这些子目录中包含可以提供有关进程的状态和环境的重要细节信息的文件。

/* https://www.kernel.org/doc/Documentation/filesystems/proc.txt */
/* http://www.itshanghai.net/technology/2009/0209/article_238.html */
Table 1-1: Process specific entries in /proc
..............................................................................
 File		Content
 clear_refs	Clears page referenced bits shown in smaps output
 cmdline	启动当前进程的完整命令(以'\0'字符分隔),但僵尸进程目录中的此文件不包含任何信息
 cpu		Current and last cpu in which it was executed	(2.4)(smp)
 cwd		指向当前进程运行目录的一个符号链接
 environ	当前进程的环境变量列表,彼此间用空字符('\0')隔开;变量用大写字母表示,其值用小写字母表示
 exe		指向启动当前进程的可执行文件(完整路径)的符号链接
 fd		这是个目录,包含当前进程打开的每一个文件的文件描述符(file descriptor),这些文件描述符是指向实际文件的一个符号链接
 maps	当前进程关联到的每个可执行文件和库文件在内存中的映射区域及其访问权限所组成的列表(2.4)
 mem	当前进程所占用的内存空间,由open、read和lseek等系统调用使用,不能被用户读取
 root		指向当前进程运行根目录的符号链接;在Unix和Linux系统上,通常采用chroot命令使每个进程运行于独立的根目录
 stat		当前进程的状态信息,包含一系统格式化后的数据列,可读性差,通常由ps命令使用
 statm	当前进程占用内存的状态信息,通常以“页面”(page)表示
 status	与stat所提供信息类似,但可读性较好
 wchan	Present with CONFIG_KALLSYMS=y: it shows the kernel function
		symbol the task is blocked in - or "0" if not blocked.
 pagemap	Page table
 stack	Report full stack trace, enable via CONFIG_STACKTRACE
 smaps	an extension based on maps, showing the memory consumption of
		each mapping and flags associated with it
 numa_maps	an extension based on maps, showing the memory locality and
		binding policy as well as mem usage (in pages) of each mapping.
..............................................................................

/proc/self 是一个有趣的子目录,它使得程序可以方便地使用 /proc 查找当前进程的信息。/proc/self 是一个链接到 /proc 中访问 /proc 的进程所对应的 PID 的目录的符号链接。

修改

上面讨论的大部分 /proc 的文件是只读的。而实际上 /proc 文件系统通过 /proc 中可读写的文件提供了对内核的交互机制。写这些文件可以改变内核的状态,因而要慎重改动这些文件。/proc/sys 目录存放所有可读写的文件的目录,可以被用于改变内核行为。如果希望通过 /proc 文件系统来控制系统,可以参考「实时管理Linux」进行设置。

参考链接:

=END=

,

《 “Linux的`/proc文件系统`学习” 》 有 15 条评论

  1. Linux运维基础采集项
    https://github.com/open-falcon/book/blob/master/zh/faq/linux-metrics.md
    `
    kernel.files.allocated:读取的/proc/sys/fs/file-nr第一个Field

    #!/bin/bash
    # set -x

    interval=${1:-2} # set default interval to 2

    while true
    do
    R1=$(awk ‘{print $1}’ /proc/sys/fs/file-nr)
    echo -e “kernel.files.allocated = $R1 [$(date +%F_%T)]”
    sleep $interval
    done
    `
    怎样增大 Linux 系统的 open file(s) 上限
    http://www.chengweiyang.cn/2015/11/14/how-to-enlarge-linux-open-files-upper-cell/

  2. `
    /proc/$pid/comm 以字符串的形式存放「进程名」
    /proc/$pid/cmdline 进程启动时的命令行参数
    /proc/$pid/exe 实际执行进程所在路径的「符号链接」
    /proc/$pid/status 进程执行过程中的一些状态信息(Name/PPid/Uid/Gid/VmSize/Threads/…)
    /proc/$pid/environ 进程启动时的环境变量信息
    `

  3. http://man7.org/linux/man-pages/man5/proc.5.html
    `
    /proc/[pid]/attr/current (since Linux 2.6.0)
    The contents of this file represent the current security attributes of the process. 该文件内容表示当前进程的安全上下文

    In SELinux, this file is used to get the security context of a process. Prior to Linux 2.6.11, this file could not be used to set the security context (a write was always denied), since SELinux limited process security transitions to execve(2) (see the description of /proc/[pid]/attr/exec, below). Since Linux 2.6.11, SELinux lifted this restriction and began supporting “set” operations via writes to this node if authorized by policy, although use of this operation is only suitable for applications that are trusted to maintain any desired separation between the old and new security contexts. Prior to Linux 2.6.28, SELinux did not allow threads within a multi-threaded process to set their security context via this node as it would yield an inconsistency among the security contexts of the threads sharing the same memory space. Since Linux 2.6.28, SELinux lifted this restriction and began supporting “set” operations for threads within a multithreaded process if the new security context is bounded by the old security context, where the bounded relation is defined in policy and guarantees that the new security context has a subset of the permissions of the old security context. Other security modules may choose to support “set” operations via writes to this node.
    `

    SELinux策略语言–客体类别和许可
    http://blog.csdn.net/myarrow/article/details/10073853

    SEAndroid安全机制中的进程安全上下文关联分析
    http://blog.csdn.net/luoshengyang/article/details/38054645

    3.3.3 在/proc和/selinux文件系统中的策略
    http://book.51cto.com/art/200712/63229.htm
    `
    文件系统/proc将进程的安全属性设置记录在/proc//attr/文件中,这个文件允许用户访问一个进程的上下文信息,是进程号,用户可以得到和设置进程的安全属性。例如:init进程的安全属性文件列出如下:

    # ls /proc/1/attr
    current exec fscreate keycreate prev sockcreate
    # cat current
    system_u:system_r:init_t:s0
    # cat prev
    system_u:system_r:kernel_t:s0

    其中,current表示当前进程的安全上下文。pre表示在上次执行前的上下文,即调用这个进程的上下文,init进程重执行了自己,域从kernel_t转移到init_t。exec表示下一次执行的上下文,fscreate表示被这个进程创建的新文件使用的上下文,sockcreate表示被这个进程创建的socket使用的上下文。
    `

  4. 用 Falcon 进行 端口监控、进程监控
    http://book.open-falcon.org/zh/usage/proc-port-monitor.html
    `
    # 端口监控
    机器监听的端口可能很多很多,但是真正想做监控的端口可能不多,这会造成资源浪费
    目前Open-Falcon还不支持nodata监控,端口挂了不上报数据了,没有nodata机制,是发现不了的

    agent通过 ss -tln 命令拿到当前有哪些端口在监听,如果8080在监听,就设置value=1,汇报给transfer,如果发现8081没在监听,就设置value=0,汇报给transfer。

    # 进程监控
    name是从/proc/$pid/status文件采集的,cmdline是从/proc/$pid/cmdline采集的。这个文件存放的是你启动进程的时候用到的命令,比如你用java -c uic.properties启动了一个Java进程,进程名是java,其实所有的java进程,进程名都是java,那我们是没法通过name字段做区分的。怎么办呢?此时就要求助于这个/proc/$pid/cmdline文件的内容了。

    听起来是不是挺复杂的?呵呵,如果你的进程有端口在监听,就配置一个端口监控就可以了,无需既配置端口监控、又配置进程监控,毕竟如果进程挂了,端口肯定就不会监听了。
    `

  5. Nginx配置信息损毁又无备份时如何恢复
    https://mp.weixin.qq.com/s/Xh0-rKMPq5SXDhuAZuaBTw
    `
    恢复思路是看Nginx进程的内存中有没有存储配置信息,如果有那能不能dump出来。一搜还真有,文章 Dump Current Nginx Config 提供了个小脚本 dump.sh,这个脚本需要 GDB: The GNU Project Debugger 工具的支持。

    # Set pid of nginx master process here
    pid=339

    # generate gdb commands from the process’s memory mappings using awk
    cat /proc/$pid/maps | awk ‘$6 !~ “^/” {split ($1,addrs,”-“); print “dump memory mem_” addrs[1] ” 0x” addrs[1] ” 0x” addrs[2] ;}END{print “quit”}’ > gdb-commands

    # use gdb with the -x option to dump these memory regions to mem_* files
    gdb -p $pid -x gdb-commands

    # look for some (any) nginx.conf text
    grep worker_connections mem_*
    grep server_name mem_*
    `
    https://serverfault.com/questions/361421/dump-nginx-config-from-running-process

    Dump a linux process’s memory to file
    https://serverfault.com/questions/173999/dump-a-linux-processs-memory-to-file

  6. 从内核代码角度详解proc目录
    https://blog.spoock.com/2019/10/26/proc-from-kernel/
    `
    1. 说明
    2. proc目录结构分析
    3. 创建/proc目录
    3.1. proc_root_init
    3.2. proc_get_sb
    3.3. proc_fill_super

    3.4. proc_root
    3.4.1. proc_root_lookup
    3.4.2. proc_lookup
    3.4.3. proc_pid_lookup
    3.4.4. proc_base_lookup
    3.4.5. proc_self_inode_operations

    3.5. proc_root_readdir
    3.5.1. proc_pid_readir
    3.5.2. next_tgid()
    3.5.3. find_ge_pid
    3.5.4. find_pid_ns()
    3.5.5. next_pidmap()

    3.6. proc_pid_fill_cache
    3.6.1. proc_tgid_base_lookup
    3.6.2. proc_tgid_base_readdir

    3.7. pid_entry
    3.7.1. proc_pid_cmdline

    4. /proc操作
    4.1. create_proc_entry
    4.2. remove_proc_entry
    4.3. proc_mkdir
    5. 总结
    6. 参考
    `

  7. 内核proc文件系统与seq接口(2)—内核proc文件系统编程接口
    http://blog.chinaunix.net/uid-20543672-id-3221530.html

    第一个Linux驱动程序(四)——aMsg使用/proc文件系统
    https://zhoujianshi.github.io/articles/2017/%E7%AC%AC%E4%B8%80%E4%B8%AALinux%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F%EF%BC%88%E5%9B%9B%EF%BC%89%E2%80%94%E2%80%94aMsg%E4%BD%BF%E7%94%A8-proc%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F/index.html

    使用proc_create创建proc文件
    https://blog.csdn.net/jiangxin04211/article/details/50834177

    用户空间与内核空间数据交换的方式(2)——procfs
    https://www.cnblogs.com/hoys/archive/2011/04/10/2011141.html

    使用 /proc 文件系统来访问 Linux 内核的内容
    https://www.ibm.com/developerworks/cn/linux/l-proc.html

    linux proc_root_init
    https://blog.csdn.net/chenliang0224/article/details/78715271

    proc文件系统分析(二)
    http://blog.chinaunix.net/uid-20687780-id-375138.html

    proc文件系统分析(三)
    http://blog.chinaunix.net/uid-20687780-id-375239.html

    proc_fs下进程信息形成原理、目录遍历方式、位图查找
    https://www.cnblogs.com/Wandererzj/archive/2012/04/04/2432086.html

    修改linux内核达到隐藏进程目的(2.6.28)
    http://www.cppblog.com/csjiaxin/articles/136378.html

  8. 一行代码隐藏Linux进程
    https://zhuanlan.zhihu.com/p/187052665
    `
    本文介绍一种将Linux进程小隐于用户的非常规方法,仅仅一行代码:
    修改掉进程的pid即可。

    target->pid = 0x7fffffff;

    完整的脚本如下:

    #!/usr/bin/stap -g
    # hide.stp

    global pid;

    function hide(who:long)
    %{
    struct task_struct *target;

    target = pid_task(find_vpid(STAP_ARG_who), PIDTYPE_PID);
    target->pid = 0x7fffffff;
    %}

    probe begin
    {
    pid = $1
    hide(pid);
    exit();
    }

    简单的说一下原理。
    1. task被创建的时候,根据其pid注册procfs目录结构。
    2. 展示procfs目录结构的时候,遍历task list以其pid作为key来查找procfs目录结构。
    3. 0x7fffffff(或者任何其它合理的值)根本没有注册过,当然无法显示。
    `

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注