工作中,有时候我们需要知道某个文件是否被修改了, 被哪个程序修改了. Linux 下可以很方便地监控某个文件被修改的记录. 根据目的不同, Linux 下有不同的监视文件或文件夹的方案.


Table of Contents

  1. A. Auditd
    1. 安装 auditd
    2. 配置 audit 监视规则
    3. 检查文件操作记录
  2. Systemtap
    1. 安装 Systemtap
    2. 获取文件信息
    3. Systemtap 监控脚本
    4. 监控文件
  3. inotifywait
    1. 安装 inotify-tools
    2. 监控 文件夹下的文件产生,修改,删除

A. Auditd

Auditd 可以很方便监控记录哪些程序和用户对指定文件(即使不存在)做的操作.

安装 auditd

  1. 一般发行版软件仓库里都会有 auditd 安装包. 如果默认没有安装,可以很方便地利用包管理器来安装
1
2
3
4
5
6
## Fedora
$ sudo dnf install -y audit
## CentOS
$ sudo yum install -y audit
## Debian / Ubuntu
$ sudo apt install -y audit
  1. 启动 audit 服务
1
$ sudo systemctl enable --now auditd
  1. 检查 audit 服务状态
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ sudo systemctl status auditd
● auditd.service - Security Auditing Service
Loaded: loaded (/usr/lib/systemd/system/auditd.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2018-09-07 08:47:53 CST; 10min ago
Docs: man:auditd(8)
https://github.com/linux-audit/audit-documentation
Process: 28126 ExecStartPost=/sbin/augenrules --load (code=exited, status=0/SUCCESS)
Process: 28121 ExecStart=/sbin/auditd (code=exited, status=0/SUCCESS)
Main PID: 28122 (auditd)
Tasks: 5 (limit: 4915)
Memory: 3.3M
CGroup: /system.slice/auditd.service
├─28122 /sbin/auditd
├─28124 /sbin/audispd
└─28127 /usr/sbin/sedispatch

这就表示服务正常.

配置 audit 监视规则

  1. 为了监视文件的访问操作, 需要在/etc/audit/rules.d/audit.rules 添加如下规则, 其中 perm 是要监控的操作, key 是在查寻时指定的关键字, path 是要监控的文件路径.
1
2
$ vi /etc/audit/rules.d/audit.rules
-a always,exit -F path=/path/to/file -F perm=warx -F key=keyword-for-filter-log
  1. 重启 audit 服务
1
2
### Note: use service instead of systemctl
$ sudo service auditd restart
  1. 检查 audit 规则.
1
2
$ sudo auditctl -l
-a always,exit -F path=/path/to/file -F perm=warx -F key=keyword-for-filter-log

检查文件操作记录

假如我们监控 /root/test.txt 的操作, 规则是

1
-a always,exit -F path=/root/test.txt -F perm=warx -F key=test-filter

然后对其做一些操作

1
2
3
$ ls /root/test.txt
$ cat /root/test.txt
$ touch /root/test.txt

然后通过如下命令查询操作记录.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ ausearch -k test-filter

time->Fri Sep 7 09:23:24 2018
type=PROCTITLE msg=audit(1536283404.017:39844): proctitle=63617400746573742E747874
type=PATH msg=audit(1536283404.017:39844): item=0 name="test.txt" inode=1587579 dev=103:08 mode=0100644 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL cap_fp=0000000000000000 cap_fi=0000000000000000 cap_fe=0 cap_fver=0
type=CWD msg=audit(1536283404.017:39844): cwd="/root"
type=SYSCALL msg=audit(1536283404.017:39844): arch=c000003e syscall=257 success=yes exit=3 a0=ffffff9c a1=7fff145999ed a2=0 a3=0 items=1 ppid=32477 pid=10767 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts4 ses=3 comm="cat" exe="/usr/bin/cat" key="test-filter"
----
time->Fri Sep 7 09:27:22 2018
type=PROCTITLE msg=audit(1536283642.307:40008): proctitle=6C73002D2D636F6C6F723D6175746F
type=PATH msg=audit(1536283642.307:40008): item=0 name="test.txt" inode=1587579 dev=103:08 mode=0100644 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL cap_fp=0000000000000000 cap_fi=0000000000000000 cap_fe=0 cap_fver=0
type=CWD msg=audit(1536283642.307:40008): cwd="/root"
type=SYSCALL msg=audit(1536283642.307:40008): arch=c000003e syscall=191 success=no exit=-61 a0=7ffcd0a58c40 a1=7f4b30ece210 a2=7ffcd0a58c00 a3=14 items=1 ppid=1617 pid=12314 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts6 ses=3 comm="ls" exe="/usr/bin/ls" key="test-filter"
----
time->Fri Sep 7 09:27:29 2018
type=PROCTITLE msg=audit(1536283649.775:40009): proctitle=746F75636800746573742E747874
type=PATH msg=audit(1536283649.775:40009): item=1 name="test.txt" inode=1587579 dev=103:08 mode=0100644 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL cap_fp=0000000000000000 cap_fi=0000000000000000 cap_fe=0 cap_fver=0
type=PATH msg=audit(1536283649.775:40009): item=0 name="/root" inode=1569793 dev=103:08 mode=040550 ouid=0 ogid=0 rdev=00:00 nametype=PARENT cap_fp=0000000000000000 cap_fi=0000000000000000 cap_fe=0 cap_fver=0
type=CWD msg=audit(1536283649.775:40009): cwd="/root"
type=SYSCALL msg=audit(1536283649.775:40009): arch=c000003e syscall=257 success=yes exit=3 a0=ffffff9c a1=7fff075909e1 a2=941 a3=1b6 items=2 ppid=1617 pid=12367 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts6 ses=3 comm="touch" exe="/usr/bin/touch" key="test-filter"

我们可以看到都有 cat, ls, touch 在相应的时间对其做了什么操作. aureport 可以给出更直观的报告,

1
2
3
4
$ ausearch -k test_filter | aureport -f -i
33. 09/07/2018 09:56:23 test.txt getxattr no /usr/bin/ls amito 41596
34. 09/07/2018 09:56:26 test.txt openat yes /usr/bin/cat amito 41600
35. 09/07/2018 09:56:28 test.txt openat yes /usr/bin/touch amito 41607

Systemtap

systemtap 功能非常强大,可以监控系统调用, 也可检测文件的修改操作. 但是需要安装系统的 debug 模块. 可能需要在相应的 repo 中 设置 debug 为enabled=1

安装 Systemtap

1
2
3
4
## Fedora
$ sudo dnf install -y kernel-debuginfo kernel-debuginfo-common systemtap systemtap-client systemtap-runtime systemtap-devel
## CentOS
$ sudo yum install -y kernel-debuginfo kernel-debuginfo-common systemtap systemtap-client systemtap-runtime systemtap-devel

获取文件信息

1
2
$ stat -c '%D %i' test.txt
10308 1587579

Systemtap 监控脚本

下面这个脚本可以监控文件的修改记录.将脚本保存为 inodewatch.stp

1
2
3
4
5
6
7
8
9
10
11
#! /usr/bin/env stap

probe vfs.write, vfs.read
{
# dev and ino are defined by vfs.write and vfs.read
if (dev == MKDEV($1,$2) # major/minor device
&& ino == $3)
printf ("%s(%d) %s 0x%x/%u\n",
execname(), pid(), ppfunc(), dev, ino)
}

监控文件

1
$ sudo stap sudo stap inodewatch.stp 0x103 0x08 1587579

其中连个十六进制数字 0x103 0x08 是上面得到的文件设备ID 10308. 现在对 test.txt 做一些操作.

1
2
vim test.txt
cat test.txt

脚本会给出如下类似的信息

1
2
3
4
5
6
7
8
vim(22230) vfs_read 0x10300008/1587579
vim(22230) vfs_read 0x10300008/1587579
vim(22230) vfs_read 0x10300008/1587579
vim(22230) vfs_read 0x10300008/1587579
vim(22230) vfs_read 0x10300008/1587579
vim(22230) vfs_write 0x10300008/1587579
cat(22303) vfs_read 0x10300008/1587579
cat(22303) vfs_read 0x10300008/1587579

我们可以看到 vim, cattest.txt做了一些读写操作.

inotifywait

inotifywaitinotify-tools 里带的工具可以监控文件的修改建立等等.

安装 inotify-tools

1
2
3
$ sudo dnf install -y inotify-tools
# or
$ sudo apt install -y inotify-tools

监控 文件夹下的文件产生,修改,删除

1
2
3
4
5
$ inotifywait -m /path/to/watch -r -e create -e moved_to -e delete -e modify | while read path action file; do
$ ...
$ your action here
$ ...
$ done

比如, 在特定文件 test.txt 产生时,给特定邮箱发邮件, 并删除它

1
2
3
4
5
6
7
$ inotifywait -m /path -e create -e moved_to | while read path action file; do
$ echo "The file '$file' appeared in directory '$path' via '$action'."
$ if [[ $file == "test.txt" ]]; then
$ echo "The file '$file' appeared in directory '$path' via '$action'. Deleting"|mutt -s "Deleting $file" your_email
$ sudo rm -rf /path/test.txt
$ fi
$ done