воскресенье, 26 сентября 2021 г.

filesystem notifications in linux kernel

disclaimer

Filesystems are the most complex part of any OS. I am not a specialist in linux filesystems and even don`t commit the code to linux kernel. So all information here cannot be considered reliable, code has tons of bugs and can damage your machine and ruin the rest of your life

Usermode notifications

linux has 3 mechanisms for passing filesystem notification to user-mode:

  1. dnotify
  2. inotify
  3. new-fashioned fanotify
all they projected to used-mode as file (analogue of FilterConnectionPorts), so you can use lsof (or even just something like "ls /proc/*/fdinfo/* | xargs grep notify") to find then and what processes do they belong to. Unfortunately (as usually) this information is not enough. Let see for example function fanotify_fdinfo. We can notice that there are 3 possible source of notifications:
  1. just simple inode - for them dumped inode->i_ino & superblock s_dev - I don`t know how you can in usermode find mountpoint for this superblock
  2. mount point (btw struct mount even not described in linux/include). At least knowing mnt_id you can find name in /proc/pid/mountinfo file
  3. superblock - s_dev again dumping
Can you have real-time notifications about setting new xxnotify? Yes, via security_path_notify. At the same time no notifications about removing

Kernel mode notifications
Can you have the same functionality provided by xxnotify in kernel mode? Definitely yes - kernel audit uses it. I could not find any sample code to do this in your own driver so I wrote one. This is not very complex (although function fsnotify_destroy_group is not exported so you need some sort of kallsyms lookup). You can add to tracked_inode everything you want - like full filename, stat etc

And now the main question
Can you find all sources of filesystem notification?
Volatility cannot
I am not aware of any tools to do this so I wrote one by myself. Let`s think how we can implement this:
  1. we need enum superblocks first. Function iterate_supers is not exported (who can it stop?)
  2. then you can enum all mount points (mount_lock is not exported too)
  3. and enum inodes in current superblock and then enum installed fsnotify_marks (btw as you can guess functions fsnotify_first_mark/fsnotify_next_mark not exported too. My inner paranoia says that there is too many deliberately hidden functions)
Sample of output:

sudo ./lkmem -F -c ~/krnl/curr ~/krnl/System.map-5.11.0-34-generic
...
superblock[24] at 0xffff8a044be2a000 dev 8388610 flags 70018000 inodes 15923 sda2 mnt_count 43 root 0xffff8a0448f0ecc0 
 s_type: 0xffffffffa580eaa0 - kernel!ext4_fs_type
 s_op: 0xffffffffa5050080 - kernel!ext4_sops
 dq_op: 0xffffffffa50501c0 - kernel!ext4_quota_operations
 s_qcop: 0xffffffffa5050160 - kernel!ext4_qctl_operations
 s_export_op: 0xffffffffa5050020 - kernel!ext4_export_ops
 mnt[0] 0xffff8a04420fec80 mark_cnt 0 mnt_id 28 / rw,relatime shared:1 - ext4 /dev/sda2 rw,errors=remount-ro
  inode[1873] 0xffff8a0365f1e1a0 i_no 398369 i_flags 1000 FILE
    i_fsnotify_mask: 1FFE i_fsnotify_marks 0xffff8a036edb5de0 count 1
    fsnotify[0] 0xffff8a036ccb8720 mask 1FFE ignored_mask 0 flags 6
     group: 0xffff8a036ec09500
      ops: 0xffffffffc08f0160 - lkntfy


As you can see we successfully found inode on which my test notification was installed from driver,  event mask (0x1ffe - as in test-case), superblock and mount point - in this case this is root

P.S.: I don`t know why some super-blocks have huge amount of mount points (43 in the above sample). It is quite possible that this is another memory leak 

Комментариев нет:

Отправить комментарий