From 44ba43389dd2bf71a30c6b80901af9537cf816dd Mon Sep 17 00:00:00 2001 From: Mygod Date: Wed, 12 Aug 2020 10:31:41 -0400 Subject: [PATCH] Locate system linker section automatically --- .../be/mygod/librootkotlinx/AppProcess.kt | 60 ++++++++++++++++++- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/mobile/src/main/java/be/mygod/librootkotlinx/AppProcess.kt b/mobile/src/main/java/be/mygod/librootkotlinx/AppProcess.kt index fe1740e9..e27f71b6 100644 --- a/mobile/src/main/java/be/mygod/librootkotlinx/AppProcess.kt +++ b/mobile/src/main/java/be/mygod/librootkotlinx/AppProcess.kt @@ -5,6 +5,7 @@ import android.os.Debug import android.os.Process import androidx.annotation.RequiresApi import java.io.File +import java.io.IOException object AppProcess { /** @@ -32,7 +33,49 @@ object AppProcess { return "/system/etc/ld.config.txt" } + /** + * Based on: https://android.googlesource.com/platform/bionic/+/30f2f05/linker/linker_config.cpp#182 + */ + @RequiresApi(29) + fun findLinkerSection(lines: Sequence, binaryRealPath: String): String { + for (untrimmed in lines) { + val line = untrimmed.substringBefore('#').trim() + if (line.isEmpty()) continue + if (line[0] == '[' && line.last() == ']') break + if (line.contains("+=")) continue + val chunks = line.split('=', limit = 2) + if (chunks.size < 2) { + Logger.me.w("warning: couldn't parse invalid format: $line (ignoring this line)") + continue + } + var (name, value) = chunks.map { it.trim() } + if (!name.startsWith("dir.")) { + Logger.me.w("warning: unexpected property name \"$name\", " + + "expected format dir. (ignoring this line)") + continue + } + if (value.endsWith('/')) value = value.dropLast(1) + if (value.isEmpty()) { + Logger.me.w("warning: property value is empty (ignoring this line)") + continue + } + try { + value = File(value).canonicalPath + } catch (e: IOException) { + Logger.me.i("warning: path \"$value\" couldn't be resolved: ${e.message}") + } + if (binaryRealPath.startsWith(value) && binaryRealPath[value.length] == '/') return name.substring(4) + } + throw IllegalArgumentException("No valid linker section found") + } + val myExe get() = "/proc/${Process.myPid()}/exe" + val myExeCanonical get() = try { + File("/proc/self/exe").canonicalPath + } catch (e: IOException) { + Logger.me.i("warning: couldn't resolve self exe: ${e.message}") + "/system/bin/app_process" + } /** * To workaround Samsung's stupid kernel patch that prevents exec, we need to relocate exe outside of /data. @@ -51,10 +94,17 @@ object AppProcess { // unfortunately native ld.config.txt only recognizes /data,/system,/system_ext as system directories; // to link correctly, we need to add our path to the linker config too val ldConfig = "$apexPath/etc/ld.config.txt" + val masterLdConfig = genericLdConfigFilePath + val section = try { + File(masterLdConfig).useLines { findLinkerSection(it, myExeCanonical) } + } catch (e: Exception) { + Logger.me.w("Failed to locate system section", e) + "system" + } script.appendln("[ -f $ldConfig ] || " + "mkdir -p $apexPath/etc && " + - "echo dir.system = $apexPath >$ldConfig && " + - "cat $genericLdConfigFilePath >>$ldConfig || exit 1") + "echo dir.$section = $apexPath >$ldConfig && " + + "cat $masterLdConfig >>$ldConfig || exit 1") "$apexPath/bin" to "$apexPath/bin/app_process" } script.appendln("[ -f $relocated ] || " + @@ -64,7 +114,11 @@ object AppProcess { return script to relocated } - fun launchString(packageCodePath: String, clazz: String, appProcess: String, niceName: String?): String { + /** + * Compute the shell script line that exec into the corresponding [clazz]. + * Extra params can be simply appended to the string. + */ + fun launchString(packageCodePath: String, clazz: String, appProcess: String, niceName: String? = null): String { val debugParams = if (Debug.isDebuggerConnected()) when (Build.VERSION.SDK_INT) { in 29..Int.MAX_VALUE -> "-XjdwpProvider:adbconnection" 28 -> "-XjdwpProvider:adbconnection -XjdwpOptions:suspend=n,server=y -Xcompiler-option --debuggable"