最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android Native fdsan檢測工具介紹

 更新時(shí)間:2023年02月10日 09:27:08   作者:蘆半山  
這篇文章主要為大家介紹了Android Native fdsan檢測工具介紹,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

正文

本文分析基于Android T(13)

fdsan,全名為file descriptor sanitizer,是Android中的一種檢測工具,用于檢測fd的use-after-close和double-close錯(cuò)誤。這兩個(gè)錯(cuò)誤會(huì)給設(shè)備留下安全漏洞,甚至造成數(shù)據(jù)泄露等安全問題。然而現(xiàn)實(shí)情況是這兩種錯(cuò)誤非常隱蔽,且難以排查。這才催生了fdsan的誕生。

fdsan由Google的工程師Josh Gao開發(fā)。最初在Android 10中引入,檢測到錯(cuò)誤時(shí)會(huì)打印log并繼續(xù)運(yùn)行。Android 11更改了運(yùn)行模式,一旦檢測到錯(cuò)誤就立即abort,讓問題暴露得更加醒目。

要讓這些問題可以被檢測,關(guān)鍵是要構(gòu)建fd的所有權(quán)體系。

這套體系的建立有兩個(gè)重要前提:

  • Android中大多數(shù)fd并非直接通過open/close的原生接口進(jìn)行管理,而是通過unique_fd,F(xiàn)ileOutputStream,ParcelFileDescriptor之類的封裝形式。
  • fd是一個(gè)整數(shù),且每個(gè)進(jìn)程所能創(chuàng)建的fd都有上限,早期為1024,現(xiàn)在為32768。因此即便為每個(gè)fd創(chuàng)建單獨(dú)的所有權(quán)管理數(shù)據(jù)也不會(huì)消耗多少空間。

一個(gè)fd由生到死的所有者

基于這兩個(gè)條件,fdsan使用一個(gè)64-bit的tag來表明一個(gè)fd由生到死的所有者。

tag組成

tag由兩部分組成,最高位的8-bit構(gòu)成type,后面的56-bit構(gòu)成value。Type表示fd通過何種封裝形式進(jìn)行管理,譬如ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD就表示fd通過unique_fd進(jìn)行管理。

對(duì)于應(yīng)用工程師而言,他們接觸到的大多為Java/Kotlin代碼,因此Java中常用的FileInputStream/FileOutputStream/ParcelFileDescriptor等封裝形式也有相應(yīng)的type。

詳細(xì)列表如下。

enum android_fdsan_owner_type {
  /*
   * Generic Java or native owners.
   *
   * Generic Java objects always use 255 as their type, using identityHashCode
   * as the value of the tag, leaving bits 33-56 unset. Native pointers are sign
   * extended from 48-bits of virtual address space, and so can have the MSB
   * set to 255 as well. Use the value of bits 49-56 to distinguish between
   * these cases.
   */
  ANDROID_FDSAN_OWNER_TYPE_GENERIC_00 = 0,
  ANDROID_FDSAN_OWNER_TYPE_GENERIC_FF = 255,
  /* FILE* */
  ANDROID_FDSAN_OWNER_TYPE_FILE = 1,
  /* DIR* */
  ANDROID_FDSAN_OWNER_TYPE_DIR = 2,
  /* android::base::unique_fd */
  ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD = 3,
  /* sqlite-owned file descriptors */
  ANDROID_FDSAN_OWNER_TYPE_SQLITE = 4,
  /* java.io.FileInputStream */
  ANDROID_FDSAN_OWNER_TYPE_FILEINPUTSTREAM = 5,
  /* java.io.FileOutputStream */
  ANDROID_FDSAN_OWNER_TYPE_FILEOUTPUTSTREAM = 6,
  /* java.io.RandomAccessFile */
  ANDROID_FDSAN_OWNER_TYPE_RANDOMACCESSFILE = 7,
  /* android.os.ParcelFileDescriptor */
  ANDROID_FDSAN_OWNER_TYPE_PARCELFILEDESCRIPTOR = 8,
  /* ART FdFile */
  ANDROID_FDSAN_OWNER_TYPE_ART_FDFILE = 9,
  /* java.net.DatagramSocketImpl */
  ANDROID_FDSAN_OWNER_TYPE_DATAGRAMSOCKETIMPL = 10,
  /* java.net.SocketImpl */
  ANDROID_FDSAN_OWNER_TYPE_SOCKETIMPL = 11,
  /* libziparchive's ZipArchive */
  ANDROID_FDSAN_OWNER_TYPE_ZIPARCHIVE = 12,
};

tag中的value主要用作唯一性標(biāo)識(shí)。對(duì)于native層的封裝(譬如unique_fd)而言,value為封裝對(duì)象的指針值;對(duì)于Java層的封裝(譬如FileInputStream)而言,value為封裝對(duì)象的hash code。這兩種值在同一個(gè)進(jìn)程里都具有唯一性。

tag的創(chuàng)建和檢驗(yàn)過程

了解完tag的構(gòu)成后,接下來便是tag的創(chuàng)建和檢驗(yàn)過程。

通過封裝對(duì)象創(chuàng)建相應(yīng)fd時(shí)(通常在對(duì)象的構(gòu)造函數(shù)內(nèi)),tag便會(huì)創(chuàng)建。而所有的close都會(huì)去進(jìn)行tag檢驗(yàn),不論該close是通過封裝對(duì)象的析構(gòu)調(diào)用還是直接調(diào)用。舉個(gè)例子,當(dāng)一個(gè)fd通過FileInputStream創(chuàng)建時(shí),對(duì)象回收期間便會(huì)close fd。可是如果我們不小心將此fd傳到了JNI函數(shù)中,通過close函數(shù)直接去操作它,那么檢測時(shí)我們就會(huì)發(fā)現(xiàn):期望的tag是一個(gè)非零值(由type和value構(gòu)成),實(shí)際的tag為0(通過原生close函數(shù)進(jìn)行操作時(shí)tag為0),繼而報(bào)錯(cuò)。

典型的報(bào)錯(cuò)log如下(與上述例子無關(guān)),一個(gè)通過opendir打開的fd,最終卻直接通過close關(guān)閉,而不是closedir。

pid: 610, tid: 610, name: lmkd  >>> /system/bin/lmkd <<<
uid: 1069
signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr --------
Abort message: 'fdsan: attempted to close file descriptor 15, expected to be unowned, actually owned by DIR* 0x745b003c00'
    x0  0000000000000000  x1  0000000000000262  x2  0000000000000006  x3  0000007fc8696f90
    x4  0000000000000000  x5  0000000000000000  x6  0000000000000000  x7  0000000000000010
    x8  00000000000000f0  x9  643eeef5a527dc04  x10 0000000000000001  x11 0000000000000000
    x12 0000000000000008  x13 0000000060345fc8  x14 000216096eb6f000  x15 000024dad07fc39e
    x16 000000745b715948  x17 000000745b6f4390  x18 000000745c0bc000  x19 0000000000000262
    x20 0000000000000262  x21 000000745bc34000  x22 000000745cfdeb5c  x23 0000000000000003
    x24 0000007fc8697080  x25 ffffff80ffffffc8  x26 0000007fc8696d00  x27 0000007fc8696cc0
    x28 0000000000000000  x29 0000007fc8697020
    lr  000000745b6abf4c  sp  0000007fc8696c40  pc  000000745b6abf6c  pst 0000000000001000
backtrace:
      #00 pc 000000000008df6c  /apex/com.android.runtime/lib64/bionic/libc.so (fdsan_error(char const*, ...)+588)
      #01 pc 000000000008dc68  /apex/com.android.runtime/lib64/bionic/libc.so (android_fdsan_close_with_tag+740)
      #02 pc 000000000008e3d0  /apex/com.android.runtime/lib64/bionic/libc.so (close+16)
      #03 pc 000000000000b110  /system/bin/lmkd (start_wait_for_proc_kill(int)+184)
      #04 pc 000000000000a45c  /system/bin/lmkd (find_and_kill_process(int, int, char const*, meminfo*, timespec*, bool)+744)
      #05 pc 00000000000098a0  /system/bin/lmkd (mp_event_common(int, unsigned int, polling_params*)+2140)
      #06 pc 000000000000ba1c  /system/bin/lmkd (call_handler(event_handler_info*, polling_params*, unsigned int)+64)
      #07 pc 00000000000053a8  /system/bin/lmkd (main+2440)
      #08 pc 000000000008506c  /apex/com.android.runtime/lib64/bionic/libc.so (__libc_init+108)

且慢,討論了這么久的tag到底存在什么地方?可以肯定的是存在一個(gè)全局的table中,由于fd是一個(gè)32768以內(nèi)的整數(shù),因此可以將fd作為table的索引。此外,Josh將這個(gè)table設(shè)計(jì)成可擴(kuò)容的,初始大小為128,擴(kuò)容后可以存放下所有fd的tag。這樣對(duì)于大多數(shù)fd創(chuàng)建數(shù)量較少的進(jìn)程,便可以使用較小的table來節(jié)省內(nèi)存。

fdsan自引入之際便全局打開,對(duì)于保障系統(tǒng)的安全至關(guān)重要。但受限于它的原理,仍然有一些fd的use-after-close和double-close錯(cuò)誤無法被檢出。它們是:

  • 不使用任何封裝形式,而只是通過open和close來操作fd。這樣即便對(duì)同一個(gè)fd double-close,由于期望的tag和實(shí)際的tag都為0,因此錯(cuò)誤無法檢出。
  • 使用自定義的封裝形式來操作fd,而沒有在自定義的形式中接入fdsan。無法檢出的理由同上。
  • 單純的use-after-close,而并非由double-close引發(fā)的use-after-close也無法檢出。嚴(yán)格意義上來說,我認(rèn)為這個(gè)工具只能檢出fd的double-close。原因是檢測代碼只插入在close函數(shù)里,對(duì)于fd的其他操作并無檢測。

除了檢測fd的錯(cuò)誤外,存在全局table中的tag數(shù)據(jù)在生成tombstone時(shí)也會(huì)輸出,表示每個(gè)fd的ownership。unowned表明該fd的創(chuàng)建未接入fdsan。

open files:
...
fd 47: /data/app/~~TPUHOtvHOT-iL2f4uUrFSg==/com.tencent.mm-FKuS1oTvzRpPMOXX-SE_ZQ==/base.apk (owned by ZipArchive 0xfffd2ae7dd90)
fd 48: /data/app/~~TPUHOtvHOT-iL2f4uUrFSg==/com.tencent.mm-FKuS1oTvzRpPMOXX-SE_ZQ==/split_config.arm64_v8a.apk (owned by ZipArchive 0xfffd2ae82390)
fd 49: /data/app/~~TPUHOtvHOT-iL2f4uUrFSg==/com.tencent.mm-FKuS1oTvzRpPMOXX-SE_ZQ==/split_config.en.apk (owned by ZipArchive 0xfffd2ae83ac0)
fd 50: /data/app/~~TPUHOtvHOT-iL2f4uUrFSg==/com.tencent.mm-FKuS1oTvzRpPMOXX-SE_ZQ==/split_config.hdpi.apk (owned by ZipArchive 0xfffd2ae84e00)
fd 51: /data/data/com.tencent.mm/files/splitcompat/2103/verified-splits/delivery.config.arm64_v8a.apk (owned by ZipArchive 0xfffd2ae80b10)
fd 52: /data/data/com.tencent.mm/files/splitcompat/2103/verified-splits/delivery.apk (owned by ZipArchive 0xfffd2ae803a0)
fd 53: anon_inode:[eventfd] (owned by unique_fd 0xfffd7ae85e84)
fd 54: anon_inode:[eventpoll] (owned by unique_fd 0xfffd7ae85edc)
fd 55: anon_inode:[eventfd] (owned by unique_fd 0xfffd7ae99ce4)
fd 56: anon_inode:[eventpoll] (owned by unique_fd 0xfffd7ae99d3c)
fd 57: /data/app/~~TPUHOtvHOT-iL2f4uUrFSg==/com.tencent.mm-FKuS1oTvzRpPMOXX-SE_ZQ==/base.apk (unowned)
fd 58: /data/app/~~TPUHOtvHOT-iL2f4uUrFSg==/com.tencent.mm-FKuS1oTvzRpPMOXX-SE_ZQ==/split_config.arm64_v8a.apk (unowned)

最后值得注意的一點(diǎn)是,fdsan在vfork得到的子進(jìn)程里是不工作的。原因是vfork得到的子進(jìn)程雖然會(huì)拷貝父進(jìn)程的fd,但是使用的地址空間仍然屬于父進(jìn)程。因此fd和存儲(chǔ)fd tag的內(nèi)存產(chǎn)生了錯(cuò)配,在子進(jìn)程中操作fd不會(huì)被父進(jìn)程感知到,而tag的修改則會(huì)直接影響父進(jìn)程的table。

【參考文檔】 android.googlesource.com/platform/bi…

以上就是Android Native fdsan檢測工具介紹的詳細(xì)內(nèi)容,更多關(guān)于Android Native fdsan檢測工具的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論

防城港市| 兴化市| 德清县| 宁远县| 南昌县| 甘孜| 新丰县| 延边| 巴彦淖尔市| 抚宁县| 铅山县| 西充县| 兰州市| 兴仁县| 大邑县| 徐闻县| 舞钢市| 樟树市| 保山市| 大关县| 防城港市| 隆回县| 井研县| 陆丰市| 沅江市| 芜湖市| 古交市| 察隅县| 翁源县| 张家口市| 广丰县| 杨浦区| 离岛区| 乐昌市| 兰坪| 崇信县| 蓬溪县| 凌海市| 垫江县| 鄱阳县| 临潭县|