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就是本篇文章中,有誰知道的可以把這個方法列出來?