sulog: add more info

This commit is contained in:
vvb2060 2023-06-20 01:52:58 +08:00 committed by John Wu
parent a5acf33ccd
commit c6efb51f61
7 changed files with 92 additions and 49 deletions

View File

@ -6,7 +6,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.util.* import java.util.*
@Database(version = 1, entities = [SuLog::class], exportSchema = false) @Database(version = 2, entities = [SuLog::class], exportSchema = false)
abstract class SuLogDatabase : RoomDatabase() { abstract class SuLogDatabase : RoomDatabase() {
abstract fun suLogDao(): SuLogDao abstract fun suLogDao(): SuLogDao

View File

@ -14,7 +14,10 @@ class SuLog(
val packageName: String, val packageName: String,
val appName: String, val appName: String,
val command: String, val command: String,
val action: Boolean, val action: Int,
val target: Int,
val context: String,
val gids: String,
val time: Long = System.currentTimeMillis() val time: Long = System.currentTimeMillis()
) { ) {
@PrimaryKey(autoGenerate = true) var id: Int = 0 @PrimaryKey(autoGenerate = true) var id: Int = 0
@ -25,7 +28,10 @@ fun PackageManager.createSuLog(
toUid: Int, toUid: Int,
fromPid: Int, fromPid: Int,
command: String, command: String,
policy: Int policy: Int,
target: Int,
context: String,
gids: String,
): SuLog { ): SuLog {
val appInfo = info.applicationInfo val appInfo = info.applicationInfo
return SuLog( return SuLog(
@ -35,7 +41,10 @@ fun PackageManager.createSuLog(
packageName = getNameForUid(appInfo.uid)!!, packageName = getNameForUid(appInfo.uid)!!,
appName = appInfo.getLabel(this), appName = appInfo.getLabel(this),
command = command, command = command,
action = policy == SuPolicy.ALLOW action = policy,
target = target,
context = context,
gids = gids,
) )
} }
@ -44,7 +53,10 @@ fun createSuLog(
toUid: Int, toUid: Int,
fromPid: Int, fromPid: Int,
command: String, command: String,
policy: Int policy: Int,
target: Int,
context: String,
gids: String,
): SuLog { ): SuLog {
return SuLog( return SuLog(
fromUid = fromUid, fromUid = fromUid,
@ -53,6 +65,9 @@ fun createSuLog(
packageName = "[UID] $fromUid", packageName = "[UID] $fromUid",
appName = "[UID] $fromUid", appName = "[UID] $fromUid",
command = command, command = command,
action = policy == SuPolicy.ALLOW action = policy,
target = target,
context = context,
gids = gids,
) )
} }

View File

@ -57,17 +57,20 @@ object SuCallbackHandler {
val toUid = data.getIntComp("to.uid", -1) val toUid = data.getIntComp("to.uid", -1)
val pid = data.getIntComp("pid", -1) val pid = data.getIntComp("pid", -1)
val command = data.getString("command", "") val command = data.getString("command", "")
val target = data.getIntComp("target", -1)
val seContext = data.getString("context", "")
val gids = data.getString("gids", "")
val pm = context.packageManager val pm = context.packageManager
val log = runCatching { val log = runCatching {
pm.getPackageInfo(fromUid, pid)?.let { pm.getPackageInfo(fromUid, pid)?.let {
pm.createSuLog(it, toUid, pid, command, policy) pm.createSuLog(it, toUid, pid, command, policy, target, seContext, gids)
} }
}.getOrNull() ?: createSuLog(fromUid, toUid, pid, command, policy) }.getOrNull() ?: createSuLog(fromUid, toUid, pid, command, policy, target, seContext, gids)
if (notify) if (notify)
notify(context, log.action, log.appName) notify(context, log.action == SuPolicy.ALLOW, log.appName)
runBlocking { ServiceLocator.logRepo.insert(log) } runBlocking { ServiceLocator.logRepo.insert(log) }
} }

View File

@ -3,6 +3,7 @@ package com.topjohnwu.magisk.ui.log
import androidx.databinding.Bindable import androidx.databinding.Bindable
import com.topjohnwu.magisk.BR import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.di.AppContext
import com.topjohnwu.magisk.core.ktx.timeDateFormat import com.topjohnwu.magisk.core.ktx.timeDateFormat
import com.topjohnwu.magisk.core.ktx.toTime import com.topjohnwu.magisk.core.ktx.toTime
import com.topjohnwu.magisk.core.model.su.SuLog import com.topjohnwu.magisk.core.model.su.SuLog
@ -14,7 +15,7 @@ class SuLogRvItem(val log: SuLog) : ObservableRvItem(), DiffItem<SuLogRvItem> {
override val layoutRes = R.layout.item_log_access_md2 override val layoutRes = R.layout.item_log_access_md2
val date = log.time.toTime(timeDateFormat) val info = genInfo()
@get:Bindable @get:Bindable
var isTop = false var isTop = false
@ -25,4 +26,28 @@ class SuLogRvItem(val log: SuLog) : ObservableRvItem(), DiffItem<SuLogRvItem> {
set(value) = set(value, field, { field = it }, BR.bottom) set(value) = set(value, field, { field = it }, BR.bottom)
override fun itemSameAs(other: SuLogRvItem) = log.appName == other.log.appName override fun itemSameAs(other: SuLogRvItem) = log.appName == other.log.appName
private fun genInfo(): String {
val res = AppContext.resources
val sb = StringBuilder()
val date = log.time.toTime(timeDateFormat)
val toUid = res.getString(R.string.target_uid, log.toUid)
val fromPid = res.getString(R.string.pid, log.fromPid)
sb.append("$date\n$toUid $fromPid")
if (log.target != -1) {
val pid = if (log.target == 0) "magiskd" else log.target.toString()
val target = res.getString(R.string.target_pid, pid)
sb.append(" $target")
}
if (log.context.isNotEmpty()) {
val context = res.getString(R.string.selinux_context, log.context)
sb.append("\n$context")
}
if (log.gids.isNotEmpty()) {
val gids = res.getString(R.string.supp_group, log.gids)
sb.append("\n$gids")
}
sb.append("\n${log.command}")
return sb.toString()
}
} }

View File

@ -25,9 +25,9 @@
<include <include
android:id="@+id/log_track_container" android:id="@+id/log_track_container"
bullet="@{item.log.action ? R.drawable.ic_check_md2 : R.drawable.ic_close_md2}" bullet="@{item.log.action == 2 ? R.drawable.ic_check_md2 : R.drawable.ic_close_md2}"
isBottom="@{item.isBottom}" isBottom="@{item.isBottom}"
isSelected="@{!item.log.action}" isSelected="@{item.log.action != 2}"
isTop="@{item.isTop}" isTop="@{item.isTop}"
layout="@layout/item_log_track_md2" layout="@layout/item_log_track_md2"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -54,48 +54,22 @@
android:text="@{item.log.appName}" android:text="@{item.log.appName}"
android:textAppearance="@style/AppearanceFoundation.Body" android:textAppearance="@style/AppearanceFoundation.Body"
android:textStyle="bold" android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@+id/log_date" app:layout_constraintBottom_toTopOf="@+id/log_info"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:text="@string/magisk" /> tools:text="@string/magisk" />
<TextView <TextView
android:id="@+id/log_date" android:id="@+id/log_info"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@{item.date}" android:text="@{item.info}"
android:textAppearance="@style/AppearanceFoundation.Caption.Variant" android:textAppearance="@style/AppearanceFoundation.Caption.Variant"
app:layout_constraintBottom_toTopOf="@+id/log_app_details" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/log_app_name" app:layout_constraintTop_toBottomOf="@+id/log_app_name"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent" />
tools:text="06:00 PM, 10 Oct 2019" />
<TextView
android:id="@+id/log_app_details"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@{String.format(`%s %s`, @string/pid(item.log.fromPid), @string/target_uid(item.log.toUid))}"
android:textAppearance="@style/AppearanceFoundation.Caption.Variant"
app:layout_constraintBottom_toTopOf="@id/log_command"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/log_date"
tools:text="PID: 7196 Target UID: 0" />
<TextView
android:id="@+id/log_command"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:fontFamily="monospace"
android:text="@{item.log.command}"
android:textAppearance="@style/AppearanceFoundation.Caption.Variant"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/log_app_details"
app:layout_constraintBottom_toBottomOf="parent"
tools:text="/system/bin/sh" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -88,6 +88,9 @@
<string name="logs_cleared">Log successfully cleared</string> <string name="logs_cleared">Log successfully cleared</string>
<string name="pid">PID: %1$d</string> <string name="pid">PID: %1$d</string>
<string name="target_uid">Target UID: %1$d</string> <string name="target_uid">Target UID: %1$d</string>
<string name="target_pid">Mount ns target PID: %s</string>
<string name="selinux_context">SELinux context: %s</string>
<string name="supp_group">Supplementary group: %s</string>
<!--SafetyNet--> <!--SafetyNet-->

View File

@ -32,27 +32,28 @@ class Extra {
enum { enum {
INT, INT,
BOOL, BOOL,
STRING STRING,
INTLIST,
} type; } type;
union { union {
int int_val; int int_val;
bool bool_val; bool bool_val;
const char *str_val; const char *str_val;
const vector<uint32_t> *intlist_val;
}; };
string str; string str;
public: public:
Extra(const char *k, int v): key(k), type(INT), int_val(v) {} Extra(const char *k, int v): key(k), type(INT), int_val(v) {}
Extra(const char *k, bool v): key(k), type(BOOL), bool_val(v) {} Extra(const char *k, bool v): key(k), type(BOOL), bool_val(v) {}
Extra(const char *k, const char *v): key(k), type(STRING), str_val(v) {} Extra(const char *k, const char *v): key(k), type(STRING), str_val(v) {}
Extra(const char *k, const vector<uint32_t> *v): key(k), type(INTLIST), intlist_val(v) {}
void add_intent(vector<const char *> &vec) { void add_intent(vector<const char *> &vec) {
char buf[32];
const char *val; const char *val;
switch (type) { switch (type) {
case INT: case INT:
vec.push_back("--ei"); vec.push_back("--ei");
ssprintf(buf, sizeof(buf), "%d", int_val); str = to_string(int_val);
str = buf;
val = str.data(); val = str.data();
break; break;
case BOOL: case BOOL:
@ -63,6 +64,15 @@ public:
vec.push_back("--es"); vec.push_back("--es");
val = str_val; val = str_val;
break; break;
case INTLIST:
vec.push_back("--es");
for (auto i : *intlist_val) {
str += to_string(i);
str += ",";
}
if (!str.empty()) str.pop_back();
val = str.data();
break;
} }
vec.push_back(key); vec.push_back(key);
vec.push_back(val); vec.push_back(val);
@ -92,6 +102,14 @@ public:
str += str_val; str += str_val;
} }
break; break;
case INTLIST:
str += ":s:";
for (auto i : *intlist_val) {
str += to_string(i);
str += ",";
}
if (str.back() == ',') str.pop_back();
break;
} }
vec.push_back("--extra"); vec.push_back("--extra");
vec.push_back(str.data()); vec.push_back(str.data());
@ -102,9 +120,11 @@ static bool check_no_error(int fd) {
char buf[1024]; char buf[1024];
auto out = xopen_file(fd, "r"); auto out = xopen_file(fd, "r");
while (fgets(buf, sizeof(buf), out.get())) { while (fgets(buf, sizeof(buf), out.get())) {
if (strncmp(buf, "Error", 5) == 0) if (strncasecmp(buf, "Error", 5) == 0) {
LOGD("exec_cmd: %s\n", buf);
return false; return false;
} }
}
return true; return true;
} }
@ -163,11 +183,14 @@ static void exec_cmd(const char *action, vector<Extra> &data,
void app_log(const su_context &ctx) { void app_log(const su_context &ctx) {
if (fork_dont_care() == 0) { if (fork_dont_care() == 0) {
vector<Extra> extras; vector<Extra> extras;
extras.reserve(6); extras.reserve(9);
extras.emplace_back("from.uid", ctx.info->uid); extras.emplace_back("from.uid", ctx.info->uid);
extras.emplace_back("to.uid", static_cast<int>(ctx.req.uid)); extras.emplace_back("to.uid", static_cast<int>(ctx.req.uid));
extras.emplace_back("pid", ctx.pid); extras.emplace_back("pid", ctx.pid);
extras.emplace_back("policy", ctx.info->access.policy); extras.emplace_back("policy", ctx.info->access.policy);
extras.emplace_back("target", ctx.req.target);
extras.emplace_back("context", ctx.req.context.data());
extras.emplace_back("gids", &ctx.req.gids);
extras.emplace_back("command", get_cmd(ctx.req)); extras.emplace_back("command", get_cmd(ctx.req));
extras.emplace_back("notify", (bool) ctx.info->access.notify); extras.emplace_back("notify", (bool) ctx.info->access.notify);