use shared memory

This commit is contained in:
5ec1cff 2024-01-27 00:34:28 +08:00 committed by JingMatrix
parent c5d7b32cc0
commit 44570c5ed0
5 changed files with 84 additions and 23 deletions

View File

@ -136,6 +136,7 @@ public class BridgeService {
data.writeInt(ACTION.ACTION_SEND_BINDER.ordinal()); data.writeInt(ACTION.ACTION_SEND_BINDER.ordinal());
Log.v(TAG, "binder " + binder.toString()); Log.v(TAG, "binder " + binder.toString());
data.writeStrongBinder(binder); data.writeStrongBinder(binder);
data.writeParcelable(ConfigManager.getInstance().getAccessMatrixMemory(), 0);
if (bridgeService == null) break; if (bridgeService == null) break;
res = bridgeService.transact(TRANSACTION_CODE, data, reply, 0); res = bridgeService.transact(TRANSACTION_CODE, data, reply, 0);
reply.readException(); reply.readException();

View File

@ -60,6 +60,7 @@ import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.Serializable; import java.io.Serializable;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.FileVisitResult; import java.nio.file.FileVisitResult;
import java.nio.file.Files; import java.nio.file.Files;
@ -91,6 +92,9 @@ import hidden.HiddenApiBridge;
public class ConfigManager { public class ConfigManager {
private static ConfigManager instance = null; private static ConfigManager instance = null;
private final SharedMemory accessMatrixMemory;
// appid bitmap
private final ByteBuffer accessMatrix;
private final SQLiteDatabase db = openDb(); private final SQLiteDatabase db = openDb();
@ -340,6 +344,12 @@ public class ConfigManager {
HandlerThread cacheThread = new HandlerThread("cache"); HandlerThread cacheThread = new HandlerThread("cache");
cacheThread.start(); cacheThread.start();
cacheHandler = new Handler(cacheThread.getLooper()); cacheHandler = new Handler(cacheThread.getLooper());
try {
accessMatrixMemory = SharedMemory.create("access", 1250);
accessMatrix = accessMatrixMemory.mapReadWrite();
} catch (ErrnoException e) {
throw new RuntimeException(e);
}
initDB(); initDB();
updateConfig(); updateConfig();
@ -524,6 +534,13 @@ public class ConfigManager {
} }
cachedModule.clear(); cachedModule.clear();
cachedScope.clear(); cachedScope.clear();
clearAccessMatrix();
}
private void clearAccessMatrix() {
for (var i = 0; i < accessMatrix.capacity(); i++) {
accessMatrix.put(i, (byte) 0);
}
} }
private synchronized void cacheModules() { private synchronized void cacheModules() {
@ -639,6 +656,7 @@ public class ConfigManager {
else lastScopeCacheTime = SystemClock.elapsedRealtime(); else lastScopeCacheTime = SystemClock.elapsedRealtime();
} }
cachedScope.clear(); 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"}, 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)) { "enabled = 1", null, null, null, null)) {
int appPkgNameIdx = cursor.getColumnIndex("app_pkg_name"); int appPkgNameIdx = cursor.getColumnIndex("app_pkg_name");
@ -732,6 +750,12 @@ public class ConfigManager {
cachedScope.forEach((ps, modules) -> { cachedScope.forEach((ps, modules) -> {
Log.d(TAG, ps.processName + "/" + ps.uid); Log.d(TAG, ps.processName + "/" + ps.uid);
modules.forEach(module -> Log.d(TAG, "\t" + module.packageName)); 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() { synchronized SharedMemory getPreloadDex() {
return ConfigFileManager.getPreloadDex(dexObfuscate); return ConfigFileManager.getPreloadDex(dexObfuscate);
} }
SharedMemory getAccessMatrixMemory() {
return accessMatrixMemory;
}
} }

View File

@ -26,9 +26,11 @@ import android.app.ActivityThread;
import android.app.IApplicationThread; import android.app.IApplicationThread;
import android.content.Context; import android.content.Context;
import android.os.Binder; import android.os.Binder;
import android.os.Build;
import android.os.IBinder; import android.os.IBinder;
import android.os.Parcel; import android.os.Parcel;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.SharedMemory;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -109,6 +111,19 @@ public class BridgeService {
case ACTION_SEND_BINDER: { case ACTION_SEND_BINDER: {
if (Binder.getCallingUid() == 0) { if (Binder.getCallingUid() == 0) {
receiveFromBridge(data.readStrongBinder()); 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) { if (reply != null) {
reply.writeNoException(); reply.writeNoException();
} }
@ -217,4 +232,6 @@ public class BridgeService {
reply.recycle(); reply.recycle();
} }
} }
private static native void initializeAccessMatrix(SharedMemory sm);
} }

View File

@ -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} PUBLIC include)
target_include_directories(${PROJECT_NAME} PRIVATE src) 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) if (DEFINED DEBUG_SYMBOLS_PATH)
set(DEBUG_SYMBOLS_PATH ${DEBUG_SYMBOLS_PATH}/${API}) set(DEBUG_SYMBOLS_PATH ${DEBUG_SYMBOLS_PATH}/${API})

View File

@ -24,6 +24,9 @@
#include <dobby.h> #include <dobby.h>
#include <thread> #include <thread>
#include <atomic> #include <atomic>
#include <android/sharedmem.h>
#include <android/sharedmem_jni.h>
#include <sys/mman.h>
#include "loader.h" #include "loader.h"
#include "service.h" #include "service.h"
#include "context.h" #include "context.h"
@ -31,28 +34,26 @@
#include "symbol_cache.h" #include "symbol_cache.h"
#include "config_bridge.h" #include "config_bridge.h"
#include "elf_util.h" #include "elf_util.h"
#include "native_util.h"
using namespace lsplant; using namespace lsplant;
namespace lspd { namespace lspd {
std::unique_ptr<Service> Service::instance_ = std::make_unique<Service>(); std::unique_ptr<Service> Service::instance_ = std::make_unique<Service>();
std::atomic<uint64_t> last_failed_id = ~0; uint8_t* access_matrix = nullptr;
class IPCThreadState { class IPCThreadState {
static IPCThreadState* (*selfOrNullFn)(); static IPCThreadState* (*selfOrNullFn)();
static pid_t (*getCallingPidFn)(IPCThreadState*);
static uid_t (*getCallingUidFn)(IPCThreadState*); static uid_t (*getCallingUidFn)(IPCThreadState*);
public: public:
uint64_t getCallingId() { uid_t getCallingUid() {
if (getCallingUidFn != nullptr && getCallingPidFn != nullptr) [[likely]] { if (getCallingUidFn != nullptr) [[likely]] {
auto pid = getCallingUidFn(this); return getCallingUidFn(this);
auto uid = getCallingPidFn(this);
return (static_cast<uint64_t>(uid) << 32) | pid;
} }
return ~0; return 0;
} }
static IPCThreadState* selfOrNull() { static IPCThreadState* selfOrNull() {
@ -69,17 +70,14 @@ namespace lspd {
} }
selfOrNullFn = reinterpret_cast<decltype(selfOrNullFn)>( selfOrNullFn = reinterpret_cast<decltype(selfOrNullFn)>(
binder->getSymbAddress("_ZN7android14IPCThreadState10selfOrNullEv")); binder->getSymbAddress("_ZN7android14IPCThreadState10selfOrNullEv"));
getCallingPidFn = reinterpret_cast<decltype(getCallingPidFn)>(
binder->getSymbAddress("_ZNK7android14IPCThreadState13getCallingPidEv"));
getCallingUidFn = reinterpret_cast<decltype(getCallingUidFn)>( getCallingUidFn = reinterpret_cast<decltype(getCallingUidFn)>(
binder->getSymbAddress("_ZNK7android14IPCThreadState13getCallingUidEv")); 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; IPCThreadState* (*IPCThreadState::selfOrNullFn)() = nullptr;
uid_t (*IPCThreadState::getCallingUidFn)(IPCThreadState*) = nullptr; uid_t (*IPCThreadState::getCallingUidFn)(IPCThreadState*) = nullptr;
pid_t (*IPCThreadState::getCallingPidFn)(IPCThreadState*) = nullptr;
jboolean jboolean
Service::exec_transact_replace(jboolean *res, JNIEnv *env, [[maybe_unused]] jobject obj, 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_, *res = JNI_CallStaticBooleanMethod(env, instance()->bridge_service_class_,
instance()->exec_transact_replace_methodID_, instance()->exec_transact_replace_methodID_,
obj, code, data_obj, reply_obj, flags); 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; return true;
} else if (SET_ACTIVITY_CONTROLLER_CODE != -1 && } else if (SET_ACTIVITY_CONTROLLER_CODE != -1 &&
code == SET_ACTIVITY_CONTROLLER_CODE) [[unlikely]] { code == SET_ACTIVITY_CONTROLLER_CODE) [[unlikely]] {
@ -132,9 +123,14 @@ namespace lspd {
va_list args) { va_list args) {
bool need_skip = false; bool need_skip = false;
if (auto self = IPCThreadState::selfOrNull(); self != nullptr) { if (auto self = IPCThreadState::selfOrNull(); self != nullptr) {
auto last = last_failed_id.load(std::memory_order_relaxed); auto uid = self->getCallingUid();
auto current = self->getCallingId(); auto appId = uid % 100000;
need_skip = last == current; 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]] { if (!need_skip && methodId == instance()->exec_transact_backup_methodID_) [[unlikely]] {
jboolean res = false; jboolean res = false;
@ -144,6 +140,19 @@ namespace lspd {
return instance()->call_boolean_method_va_backup_(env, obj, methodId, args); 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<uint8_t*>(addr);
}
close(fd);
}
void Service::InitService(JNIEnv *env) { void Service::InitService(JNIEnv *env) {
if (initialized_) [[unlikely]] return; if (initialized_) [[unlikely]] return;
@ -283,6 +292,12 @@ namespace lspd {
IPCThreadState::Init(binder.get()); IPCThreadState::Init(binder.get());
lspd::GetLibBinder(true); 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"); LOGD("Done InitService");
} }