diff --git a/daemon/src/main/java/org/lsposed/lspd/service/BridgeService.java b/daemon/src/main/java/org/lsposed/lspd/service/BridgeService.java index 8dc68741..22c0e050 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/BridgeService.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/BridgeService.java @@ -136,6 +136,7 @@ public class BridgeService { data.writeInt(ACTION.ACTION_SEND_BINDER.ordinal()); Log.v(TAG, "binder " + binder.toString()); data.writeStrongBinder(binder); + data.writeParcelable(ConfigManager.getInstance().getAccessMatrixMemory(), 0); if (bridgeService == null) break; res = bridgeService.transact(TRANSACTION_CODE, data, reply, 0); reply.readException(); diff --git a/daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java b/daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java index 3786df43..3eff05c9 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java @@ -60,6 +60,7 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.Serializable; +import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.nio.file.FileVisitResult; import java.nio.file.Files; @@ -91,6 +92,9 @@ import hidden.HiddenApiBridge; public class ConfigManager { private static ConfigManager instance = null; + private final SharedMemory accessMatrixMemory; + // appid bitmap + private final ByteBuffer accessMatrix; private final SQLiteDatabase db = openDb(); @@ -340,6 +344,12 @@ public class ConfigManager { HandlerThread cacheThread = new HandlerThread("cache"); cacheThread.start(); cacheHandler = new Handler(cacheThread.getLooper()); + try { + accessMatrixMemory = SharedMemory.create("access", 1250); + accessMatrix = accessMatrixMemory.mapReadWrite(); + } catch (ErrnoException e) { + throw new RuntimeException(e); + } initDB(); updateConfig(); @@ -524,6 +534,13 @@ public class ConfigManager { } cachedModule.clear(); cachedScope.clear(); + clearAccessMatrix(); + } + + private void clearAccessMatrix() { + for (var i = 0; i < accessMatrix.capacity(); i++) { + accessMatrix.put(i, (byte) 0); + } } private synchronized void cacheModules() { @@ -639,6 +656,7 @@ public class ConfigManager { else lastScopeCacheTime = SystemClock.elapsedRealtime(); } cachedScope.clear(); + clearAccessMatrix(); try (Cursor cursor = db.query("scope INNER JOIN modules ON scope.mid = modules.mid", new String[]{"app_pkg_name", "module_pkg_name", "user_id"}, "enabled = 1", null, null, null, null)) { int appPkgNameIdx = cursor.getColumnIndex("app_pkg_name"); @@ -732,6 +750,12 @@ public class ConfigManager { cachedScope.forEach((ps, modules) -> { Log.d(TAG, ps.processName + "/" + ps.uid); modules.forEach(module -> Log.d(TAG, "\t" + module.packageName)); + var appId = ps.uid % PER_USER_RANGE; + if (appId >= 10000 && appId <= 19999) { + int idx = (appId - 10000) >> 3; + byte bit = (byte) (1 << ((appId - 10000) & 7)); + accessMatrix.put(idx, (byte) (accessMatrix.get(idx) | bit)); + } }); } @@ -1202,4 +1226,8 @@ public class ConfigManager { synchronized SharedMemory getPreloadDex() { return ConfigFileManager.getPreloadDex(dexObfuscate); } + + SharedMemory getAccessMatrixMemory() { + return accessMatrixMemory; + } } diff --git a/magisk-loader/src/main/java/org/lsposed/lspd/service/BridgeService.java b/magisk-loader/src/main/java/org/lsposed/lspd/service/BridgeService.java index f40e7962..ea88741a 100644 --- a/magisk-loader/src/main/java/org/lsposed/lspd/service/BridgeService.java +++ b/magisk-loader/src/main/java/org/lsposed/lspd/service/BridgeService.java @@ -26,9 +26,11 @@ import android.app.ActivityThread; import android.app.IApplicationThread; import android.content.Context; import android.os.Binder; +import android.os.Build; import android.os.IBinder; import android.os.Parcel; import android.os.RemoteException; +import android.os.SharedMemory; import android.util.Log; import androidx.annotation.NonNull; @@ -109,6 +111,19 @@ public class BridgeService { case ACTION_SEND_BINDER: { if (Binder.getCallingUid() == 0) { receiveFromBridge(data.readStrongBinder()); + try { + SharedMemory sm; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + sm = data.readParcelable(ClassLoader.getSystemClassLoader(), SharedMemory.class); + } else { + sm = data.readParcelable(ClassLoader.getSystemClassLoader()); + } + assert sm != null; + initializeAccessMatrix(sm); + sm.close(); + } catch (Throwable t) { + Log.e(TAG, "initialize shared memory", t); + } if (reply != null) { reply.writeNoException(); } @@ -217,4 +232,6 @@ public class BridgeService { reply.recycle(); } } + + private static native void initializeAccessMatrix(SharedMemory sm); } diff --git a/magisk-loader/src/main/jni/CMakeLists.txt b/magisk-loader/src/main/jni/CMakeLists.txt index b104dbb0..f88febfe 100644 --- a/magisk-loader/src/main/jni/CMakeLists.txt +++ b/magisk-loader/src/main/jni/CMakeLists.txt @@ -17,7 +17,7 @@ add_library(${PROJECT_NAME} SHARED ${SRC_LIST} ${CMAKE_CURRENT_BINARY_DIR}/src/l target_include_directories(${PROJECT_NAME} PUBLIC include) target_include_directories(${PROJECT_NAME} PRIVATE src) -target_link_libraries(${PROJECT_NAME} core log) +target_link_libraries(${PROJECT_NAME} core log android) if (DEFINED DEBUG_SYMBOLS_PATH) set(DEBUG_SYMBOLS_PATH ${DEBUG_SYMBOLS_PATH}/${API}) diff --git a/magisk-loader/src/main/jni/src/service.cpp b/magisk-loader/src/main/jni/src/service.cpp index 9db0fb3a..16e752fd 100644 --- a/magisk-loader/src/main/jni/src/service.cpp +++ b/magisk-loader/src/main/jni/src/service.cpp @@ -24,6 +24,9 @@ #include #include #include +#include +#include +#include #include "loader.h" #include "service.h" #include "context.h" @@ -31,28 +34,26 @@ #include "symbol_cache.h" #include "config_bridge.h" #include "elf_util.h" +#include "native_util.h" using namespace lsplant; namespace lspd { std::unique_ptr Service::instance_ = std::make_unique(); - std::atomic last_failed_id = ~0; + uint8_t* access_matrix = nullptr; class IPCThreadState { static IPCThreadState* (*selfOrNullFn)(); - static pid_t (*getCallingPidFn)(IPCThreadState*); static uid_t (*getCallingUidFn)(IPCThreadState*); public: - uint64_t getCallingId() { - if (getCallingUidFn != nullptr && getCallingPidFn != nullptr) [[likely]] { - auto pid = getCallingUidFn(this); - auto uid = getCallingPidFn(this); - return (static_cast(uid) << 32) | pid; + uid_t getCallingUid() { + if (getCallingUidFn != nullptr) [[likely]] { + return getCallingUidFn(this); } - return ~0; + return 0; } static IPCThreadState* selfOrNull() { @@ -69,17 +70,14 @@ namespace lspd { } selfOrNullFn = reinterpret_cast( binder->getSymbAddress("_ZN7android14IPCThreadState10selfOrNullEv")); - getCallingPidFn = reinterpret_cast( - binder->getSymbAddress("_ZNK7android14IPCThreadState13getCallingPidEv")); getCallingUidFn = reinterpret_cast( binder->getSymbAddress("_ZNK7android14IPCThreadState13getCallingUidEv")); - LOGI("libbinder selfOrNull {} getCallingPid {} getCallingUid {}", (void*) selfOrNullFn, (void*) getCallingPidFn, (void*) getCallingUidFn); + LOGD("libbinder selfOrNull {} getCallingUid {}", (void*) selfOrNullFn, (void*) getCallingUidFn); } }; IPCThreadState* (*IPCThreadState::selfOrNullFn)() = nullptr; uid_t (*IPCThreadState::getCallingUidFn)(IPCThreadState*) = nullptr; - pid_t (*IPCThreadState::getCallingPidFn)(IPCThreadState*) = nullptr; jboolean Service::exec_transact_replace(jboolean *res, JNIEnv *env, [[maybe_unused]] jobject obj, @@ -96,13 +94,6 @@ namespace lspd { *res = JNI_CallStaticBooleanMethod(env, instance()->bridge_service_class_, instance()->exec_transact_replace_methodID_, obj, code, data_obj, reply_obj, flags); - if (!*res) { - auto self = IPCThreadState::selfOrNull(); - if (self != nullptr) { - auto id = self->getCallingId(); - last_failed_id.store(id, std::memory_order_relaxed); - } - } return true; } else if (SET_ACTIVITY_CONTROLLER_CODE != -1 && code == SET_ACTIVITY_CONTROLLER_CODE) [[unlikely]] { @@ -132,9 +123,14 @@ namespace lspd { va_list args) { bool need_skip = false; if (auto self = IPCThreadState::selfOrNull(); self != nullptr) { - auto last = last_failed_id.load(std::memory_order_relaxed); - auto current = self->getCallingId(); - need_skip = last == current; + auto uid = self->getCallingUid(); + auto appId = uid % 100000; + if (appId >= 10000 && appId <= 19999 && access_matrix != nullptr) { + need_skip = (access_matrix[(appId - 10000) >> 3] & (1 << ((appId - 10000) & 7))) == 0; + } else { + // isolated + need_skip = appId >= 90000 && appId <= 99999; + } } if (!need_skip && methodId == instance()->exec_transact_backup_methodID_) [[unlikely]] { jboolean res = false; @@ -144,6 +140,19 @@ namespace lspd { return instance()->call_boolean_method_va_backup_(env, obj, methodId, args); } + LSP_DEF_NATIVE_METHOD(void, BridgeService, initializeAccessMatrix, jobject shared_memory) { + if (access_matrix != nullptr) return; + auto fd = ASharedMemory_dupFromJava(env, shared_memory); + auto addr = mmap(nullptr, 1250, PROT_READ, MAP_SHARED, fd, 0); + if (addr == MAP_FAILED) { + PLOGE("map access matrix"); + } else { + LOGD("access matrix at {}", addr); + access_matrix = reinterpret_cast(addr); + } + close(fd); + } + void Service::InitService(JNIEnv *env) { if (initialized_) [[unlikely]] return; @@ -283,6 +292,12 @@ namespace lspd { IPCThreadState::Init(binder.get()); lspd::GetLibBinder(true); + JNINativeMethod m[] = { + LSP_NATIVE_METHOD(BridgeService, initializeAccessMatrix, "(Landroid/os/SharedMemory;)V") + }; + + JNI_RegisterNatives(env, bridge_service_class_, m, 1); + LOGD("Done InitService"); }