日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

中fuse_一个Fanotify和FUSE配合使用导致的问题

發布時間:2025/3/20 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 中fuse_一个Fanotify和FUSE配合使用导致的问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

說明:本文所使用的內核版本為3.10.0-1062.el7.x86_64。

前面文章介紹的fanotify機制可用于監控文件操作產生的事件(比如open, read等),而這些文件會來自不同類型的文件系統,其中比較特殊的一種是FUSE。那fanotify能不能支持對FUSE類型文件系統的監控呢?

【現象】

還是拿fuse.sshfs來進行實驗,這里使用的"sshfs"是基于SFTP文件傳輸協議來掛載遠端目錄的(遠端為sftp server)。不過為了測試的方便(不用再找另一臺機器),采用的方式是將本機的一個目錄"/home/src"作為“遠端”,掛載到本地的"/mnt/src"目錄。

sshfs localhost:/home/src /mnt/dst

掛載成功后,啟動應用層的fanotify監控進程(一個用于文件安全分析的listerner),然后在"/mnt/dst"目錄下進行一些文件操作,很快,系統就卡死了。

【排查】

這種本機掛載sshfs的方式理論上是沒有問題的(就像socket既可以用于網絡上不同主機間的通信,也可用于同一主機上不同進程間的通信),但終歸不是一種常規的使用方式。那用真正的“遠端”目錄來掛載下試試呢?

sshfs :/home/src /mnt/dst

接下來按照與先前同樣的步驟進行操作,問題沒有再出現。隱隱覺得是因為本機掛載的方式形成了一種循環,不過直覺歸直覺,總得找出確鑿的證據不是。

回到出現問題的“本機掛載”的方式,為了進一步縮小范圍,嘗試了幾種最簡單的文件操作,發現即便是在"/mnt/dst"目錄下通過"touch"命令創建一個文件,也可以讓問題100%地穩定復現。那我們就使用這個"touch"操作,結合一些調試手段,來探究下系統卡死的根本原因。

【分析】

首先使用最易用的"strace"工具來追蹤下"touch"命令的執行,跟預想的差不多,是在進行 ?open()系統調用的時候卡住的:

strace只能追蹤system call,要想知道open()之后到底發生了什么,得深入到內核里面去看看,這就要用到Linux自帶的ftrace工具了。把"fanotify"和"fsnotify"相關的函數加入待觀測的列表,抓取"touch"命令執行后的ftrace結果:

由于"fsnotify"的若干函數打印輸出過多,對主干的分析形成了一定的干擾,于是將下列三個函數的記錄排除在外:

調整之后可以看到,此過程所涉及的進程主要有"touch", "sshfs", "sftp-se"(即sftp server)和"listener"。

經過對ftrace所展現的交互流程的梳理,感覺離真相已經很接近了,但還是缺少了一些關鍵信息,沒有形成一個完整的邏輯鏈。不過,還剩一個終極手段沒有用,那就是在系統卡死的時候強制產生coredump,然后用crash工具來分析(前提是你有這個內核的debuginfo)。

一般強制觸發crash的方式是在終端輸入"echo c > /proc/sysrq-trigger",但在系統卡死的這種情景下,搶時間點完成這個輸入有一些困難,如果是在KVM的環境中,可以通過以下命令,導出虛擬機的內存轉儲:

virsh dump ?--memory-only ?--format=kdump-zlib

有了coredump和debuginfo,就可以開始hack了。從源頭入手,先來看下"touch"進程的back trace。很明顯,它對文件的open操作被fanotify劫持了,但還沒有等到listener的處理結果:

那為什么listener沒有返回結果呢?繼續看下listener進程中負責處理fanotify的線程的棧信息:

作為監控listener,它會去嘗試打開下這個文件,以判斷這個文件的內容是否安全,由于該文件屬于FUSE文件系統,所以需要將操作的請求上報給用戶態的daemon進程(即sshfs)。listener陷入等待之后,沒有收到sshfs的返回結果。

那到底是listener的fuse request沒有發出去呢,還是sshfs沒有做出respond呢?這可以通過查看該"fuse_req"的狀態來確定,要查看狀態的值就得知道它的內存地址,而在x64體系中,為了提高效率,函數的前面幾個參數通常使用寄存器傳遞,這就給直接從棧信息來獲取參數的地址帶來了困難。

因此,只能迂回一下,借助它的下級函數中保存的寄存器值來尋找和"fuse_req"的關聯。這里,"rbx", "r12"到"r15"都是潛在的突破口:

瀏覽wait_answer_interruptible()函數的源代碼,其中有兩處對"fuse_req"指針的引用:

void wait_answer_interruptible(struct fuse_conn *fc, struct fuse_req *req)

{

if (signal_pending(current))return;spin_unlock(&fc->lock);wait_event_interruptible(req->waitq, req->state == FUSE_REQ_FINISHED);

spin_lock(&fc->lock);

}

總結

以上是生活随笔為你收集整理的中fuse_一个Fanotify和FUSE配合使用导致的问题的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。