1. 程式人生 > >Android 8.0 system app載入so Permission denied 解決

Android 8.0 system app載入so Permission denied 解決

在預置包含react native 的Android app 預置到mtk 6739的系統中,此app 具體 platform 簽名。此app啟動會載入一些 facebook的so庫
在這裡插入圖片描述
發現此app 如果預置到system/app下,啟動會報錯。開始以為是沒有把相關的so庫 放到 system/app/xx/lib 下。在Android 6.0我都是可以正常啟動的。發現在8.0 仍然會報錯。
報錯如下

2010-01-01 08:27:30.951 1887-1887/xxx W/Thread-2: type=1400 audit(0.0:19): avc: denied { execute } for path="/data/data/xxx/lib-main/libgnustl_shared.so" dev="dm-0" ino=1733 scontext=u:r:system_app:s0 tcontext=u:object_r:system_app_data_file:s0 tclass=file permissive=0
2010-01-01 08:27:30.957 1887-1915/xxx E/AndroidRuntime: FATAL EXCEPTION: Thread-2
    Process: xxx, PID: 1887
    java.lang.UnsatisfiedLinkError: dlopen failed: couldn't map "/data/data/xxx/lib-main/libgnustl_shared.so" segment 2: Permission denied
        at java.lang.Runtime.load0(Runtime.java:928)
        at java.lang.System.load(System.java:1621)
        at com.facebook.soloader.DirectorySoSource.loadLibraryFrom(DirectorySoSource.java:71)
        at com.facebook.soloader.DirectorySoSource.loadLibrary(DirectorySoSource.java:42)
        at com.facebook.soloader.SoLoader.loadLibraryBySoName(SoLoader.java:299)
        at com.facebook.soloader.DirectorySoSource.loadLibraryFrom(DirectorySoSource.java:65)
        at com.facebook.soloader.DirectorySoSource.loadLibrary(DirectorySoSource.java:42)
        at com.facebook.soloader.SoLoader.loadLibraryBySoName(SoLoader.java:299)
        at com.facebook.soloader.DirectorySoSource.loadLibraryFrom(DirectorySoSource.java:65)
        at com.facebook.soloader.DirectorySoSource.loadLibrary(DirectorySoSource.java:42)
        at com.facebook.soloader.SoLoader.loadLibraryBySoName(SoLoader.java:299)
        at com.facebook.soloader.DirectorySoSource.loadLibraryFrom(DirectorySoSource.java:65)
        at com.facebook.soloader.DirectorySoSource.loadLibrary(DirectorySoSource.java:42)
        at com.facebook.soloader.SoLoader.loadLibraryBySoName(SoLoader.java:299)
        at com.facebook.soloader.SoLoader.loadLibrary(SoLoader.java:247)
        at com.facebook.react.bridge.ReactBridge.staticInit(ReactBridge.java:18)
        at com.facebook.react.bridge.NativeMap.<clinit>(NativeMap.java:19)
        at com.facebook.react.bridge.JSCJavaScriptExecutorFactory.create(JSCJavaScriptExecutorFactory.java:21)
        at com.facebook.react.ReactInstanceManager$5.run(ReactInstanceManager.java:912)
        at java.lang.Thread.run(Thread.java:764)
2010-01-01 08:27:30.958 1887-1887/xxx D/Surface: Surface::allocateBuffers(this=0x9820a800)
2010-01-01 08:27:30.962 651-673/system_process I/WindowManager: Focus moving from null to Window{52abab1 u0 xxx/xxx.MainActivity}
2010-01-01 08:27:30.964 651-662/system_process W/ActivityManager:   Force finishing activity xxx/.MainActivity
2010-01-01 08:27:30.970 651-1917/system_process W/AES: Exception Log handling...

之後把libgnustl_shared.so 放到 /system/lib下。這個錯誤仍然出現。
通過報錯的log可以知道 react 不是通過System.loadLibrary載入libgnustl_shared.so,而是動態的通過dlopen 載入so。如果通過System.loadLibrary 載入 ,我已經把libgnustl_shared.so 放到 /system/lib下,就不會報這個錯誤。
System.loadLibrary()裝載一個庫是在Dalvik虛擬機器中,而dlopen()只在你的本地程序中裝載庫
個人猜測 包含react native的app 在安裝的時候會把 相關的so解壓到/data/data/xxx/lib/下,然後dlopen("/data/data/xxx/lib")
通過adb 進入到/data/data/xxx/lib/下 發現 so檔案都存在。

couldn't map "/data/data/xxx/lib-main/libgnustl_shared.so" segment 2: Permission denied

報錯的意思並不是檔案不存在。而是load載入失敗,失敗原因是Permission denied。
那為什麼Permission denied ?

avc: denied { execute } for path="/data/data/xxx/lib-main/libgnustl_shared.so" dev="dm-0" ino=1733 scontext=u:r:system_app:s0 tcontext=u:object_r:system_app_data_file:s0 tclass=file permissive=0

因為 libgnustl_shared.so 在system_app_data_file域目錄下。system_app 對system_app_data_file 是沒有execute 許可權。
system_app_data_file 是什麼鬼,
在external/sepolicy/file.te 下

type system_app_data_file, file_type, data_file_type, mlstrustedobject;

data_file_type 就是data分割槽下檔案。
說白了就是 system許可權的app 無法執行data分割槽下檔案。讀寫應該沒有問題。應該是防止有些流氓軟體在data分割槽下隱藏可以執行檔案。
所以給systemapp加可執行許可權

device/mediatek/sepolicy/basic/non_plat/system_app.te
allow system_app system_app_data_file:dir {getattr search };
allow system_app system_app_data_file:file {read getattr execute };

加完之後編譯發現報錯,原因是

libsepol.report_failure: neverallow on line 528 of system/sepolicy/private/app.te (or line 21726 of policy.conf) violated by allow system_app system_app_data_file:file { execute };

//system_data_file
/system/sepolicy/private/app.te

neverallow {
  bluetooth
  isolated_app
  nfc
  radio
  shared_relro
  system_app
} {
  data_file_type
  -dalvikcache_data_file
  -system_data_file # shared libs in apks
  -apk_data_file
}:file no_x_file_perms;

禁止system_app no_x_file_perms(執行) data_file_type(system_app_data_file)下的檔案。
所以我修改app.te檔案中的system_app去掉

neverallow {
  bluetooth
  isolated_app
  nfc
  radio
  shared_relro
} {
  data_file_type
  -dalvikcache_data_file
  -system_data_file # shared libs in apks
  -apk_data_file
}:file no_x_file_perms;

這個存在一個問題就是過不了谷歌cts測試。另外還有一種方法繞過這種過不了谷歌測試cts問題,我不想寫了,修改system_app_data_file的type,這個 type就是本篇文章中,有誰知道的可以把這個方法列出來?