mirror of
				https://github.com/topjohnwu/Magisk.git
				synced 2025-10-31 08:44:07 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			267 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			267 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include <unistd.h>
 | |
| #include <string>
 | |
| #include <cinttypes>
 | |
| #include <android/log.h>
 | |
| 
 | |
| #include <base.hpp>
 | |
| 
 | |
| #include "deny.hpp"
 | |
| 
 | |
| using namespace std;
 | |
| 
 | |
| extern "C" {
 | |
| 
 | |
| struct logger_entry {
 | |
|     uint16_t len;      /* length of the payload */
 | |
|     uint16_t hdr_size; /* sizeof(struct logger_entry) */
 | |
|     int32_t pid;       /* generating process's pid */
 | |
|     uint32_t tid;      /* generating process's tid */
 | |
|     uint32_t sec;      /* seconds since Epoch */
 | |
|     uint32_t nsec;     /* nanoseconds */
 | |
|     uint32_t lid;      /* log id of the payload, bottom 4 bits currently */
 | |
|     uint32_t uid;      /* generating process's uid */
 | |
| };
 | |
| 
 | |
| #define LOGGER_ENTRY_MAX_LEN (5 * 1024)
 | |
| struct log_msg {
 | |
|     union [[gnu::aligned(4)]] {
 | |
|         unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
 | |
|         struct logger_entry entry;
 | |
|     };
 | |
| };
 | |
| 
 | |
| typedef struct AndroidLogEntry_t {
 | |
|     time_t tv_sec;
 | |
|     long tv_nsec;
 | |
|     android_LogPriority priority;
 | |
|     int32_t uid;
 | |
|     int32_t pid;
 | |
|     int32_t tid;
 | |
|     const char *tag;
 | |
|     size_t tagLen;
 | |
|     size_t messageLen;
 | |
|     const char *message;
 | |
| } AndroidLogEntry;
 | |
| 
 | |
| [[gnu::weak]] struct logger_list *android_logger_list_alloc(int mode, unsigned int tail, pid_t pid);
 | |
| [[gnu::weak]] void android_logger_list_free(struct logger_list *list);
 | |
| [[gnu::weak]] int android_logger_list_read(struct logger_list *list, struct log_msg *log_msg);
 | |
| [[gnu::weak]] struct logger *android_logger_open(struct logger_list *list, log_id_t id);
 | |
| [[gnu::weak]] int android_log_processLogBuffer(struct logger_entry *buf, AndroidLogEntry *entry);
 | |
| 
 | |
| typedef struct [[gnu::packed]] {
 | |
|     int32_t tag;    // Little Endian Order
 | |
| } android_event_header_t;
 | |
| 
 | |
| typedef struct [[gnu::packed]] {
 | |
|     int8_t type;    // EVENT_TYPE_INT
 | |
|     int32_t data;   // Little Endian Order
 | |
| } android_event_int_t;
 | |
| 
 | |
| typedef struct [[gnu::packed]] {
 | |
|     int8_t type;    // EVENT_TYPE_STRING;
 | |
|     int32_t length; // Little Endian Order
 | |
|     char data[];
 | |
| } android_event_string_t;
 | |
| 
 | |
| typedef struct [[gnu::packed]] {
 | |
|     int8_t type;    // EVENT_TYPE_LIST
 | |
|     int8_t element_count;
 | |
| } android_event_list_t;
 | |
| 
 | |
| // 30014 am_proc_start (User|1|5),(PID|1|5),(UID|1|5),(Process Name|3),(Type|3),(Component|3)
 | |
| typedef struct [[gnu::packed]] {
 | |
|     android_event_header_t tag;
 | |
|     android_event_list_t list;
 | |
|     android_event_int_t user;
 | |
|     android_event_int_t pid;
 | |
|     android_event_int_t uid;
 | |
|     android_event_string_t process_name;
 | |
| //  android_event_string_t type;
 | |
| //  android_event_string_t component;
 | |
| } android_event_am_proc_start;
 | |
| 
 | |
| // 3040 boot_progress_ams_ready (time|2|3)
 | |
| 
 | |
| }
 | |
| 
 | |
| // zygote pid -> mnt ns
 | |
| static map<int, struct stat> zygote_map;
 | |
| bool logcat_exit;
 | |
| 
 | |
| static int read_ns(const int pid, struct stat *st) {
 | |
|     char path[32];
 | |
|     sprintf(path, "/proc/%d/ns/mnt", pid);
 | |
|     return stat(path, st);
 | |
| }
 | |
| 
 | |
| static int parse_ppid(int pid) {
 | |
|     char path[32];
 | |
|     int ppid;
 | |
|     sprintf(path, "/proc/%d/stat", pid);
 | |
|     auto stat = open_file(path, "re");
 | |
|     if (!stat) return -1;
 | |
|     // PID COMM STATE PPID .....
 | |
|     fscanf(stat.get(), "%*d %*s %*c %d", &ppid);
 | |
|     return ppid;
 | |
| }
 | |
| 
 | |
| static void check_zygote() {
 | |
|     zygote_map.clear();
 | |
|     auto proc = open("/proc", O_RDONLY | O_CLOEXEC);
 | |
|     auto proc_dir = xopen_dir(proc);
 | |
|     if (!proc_dir) return;
 | |
|     dirent *entry;
 | |
|     int pid;
 | |
|     struct stat st{};
 | |
|     while ((entry = readdir(proc_dir.get()))) {
 | |
|         pid = parse_int(entry->d_name);
 | |
|         if (pid <= 0) continue;
 | |
|         if (fstatat(proc, entry->d_name, &st, 0)) continue;
 | |
|         if (st.st_uid != 0) continue;
 | |
|         if (proc_context_match(pid, "u:r:zygote:s0") && parse_ppid(pid) == 1) {
 | |
|             if (read_ns(pid, &st) == 0) {
 | |
|                 LOGI("logcat: zygote PID=[%d]\n", pid);
 | |
|                 zygote_map[pid] = st;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void handle_proc(int pid, bool app_zygote = false) {
 | |
|     if (fork_dont_care() == 0) {
 | |
|         if (app_zygote) {
 | |
|             revert_unmount(pid);
 | |
|             kill(pid, SIGCONT);
 | |
|             _exit(0);
 | |
|         }
 | |
| 
 | |
|         int ppid = parse_ppid(pid);
 | |
|         auto it = zygote_map.find(ppid);
 | |
|         if (it == zygote_map.end()) {
 | |
|             LOGW("logcat: skip PID=[%d] PPID=[%d]\n", pid, ppid);
 | |
|             _exit(0);
 | |
|         }
 | |
| 
 | |
|         char path[16];
 | |
|         struct stat st{};
 | |
|         sprintf(path, "/proc/%d", pid);
 | |
|         while (read_ns(pid, &st) == 0 && it->second.st_ino == st.st_ino) {
 | |
|             if (stat(path, &st) == 0 && st.st_uid == 0) {
 | |
|                 usleep(10 * 1000);
 | |
|             } else {
 | |
|                 LOGW("logcat: skip PID=[%d] UID=[%d]\n", pid, st.st_uid);
 | |
|                 _exit(0);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         revert_unmount(pid);
 | |
|         _exit(0);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void process_main_buffer(struct logger_entry *buf) {
 | |
|     AndroidLogEntry entry;
 | |
|     if (android_log_processLogBuffer(buf, &entry) < 0) return;
 | |
|     entry.tagLen--;
 | |
|     auto tag = string_view(entry.tag, entry.tagLen);
 | |
| 
 | |
|     static bool ready = false;
 | |
|     if (tag == "AppZygote") {
 | |
|         if (entry.uid != 1000) return;
 | |
|         if (entry.message[0] == 'S') {
 | |
|             ready = true;
 | |
|         } else {
 | |
|             ready = false;
 | |
|         }
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     if (!ready || tag != "AppZygoteInit") return;
 | |
|     if (!proc_context_match(buf->pid, "u:r:app_zygote:s0")) return;
 | |
|     ready = false;
 | |
| 
 | |
|     char cmdline[1024];
 | |
|     sprintf(cmdline, "/proc/%d/cmdline", buf->pid);
 | |
|     if (auto f = open_file(cmdline, "re")) {
 | |
|         fgets(cmdline, sizeof(cmdline), f.get());
 | |
|     } else {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     if (is_deny_target(entry.uid, cmdline)) {
 | |
|         kill(buf->pid, SIGSTOP);
 | |
|         LOGI("logcat: [%s] PID=[%d] UID=[%d]\n", cmdline, buf->pid, entry.uid);
 | |
|         handle_proc(buf->pid, true);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void process_events_buffer(struct logger_entry *buf) {
 | |
|     if (buf->uid != 1000) return;
 | |
|     auto *event_data = reinterpret_cast<const unsigned char *>(buf) + buf->hdr_size;
 | |
|     auto *event_header = reinterpret_cast<const android_event_header_t *>(event_data);
 | |
|     if (event_header->tag == 30014) {
 | |
|         auto *am_proc_start = reinterpret_cast<const android_event_am_proc_start *>(event_data);
 | |
|         auto proc = string_view(am_proc_start->process_name.data,
 | |
|                                 am_proc_start->process_name.length);
 | |
|         if (is_deny_target(am_proc_start->uid.data, proc)) {
 | |
|             LOGI("logcat: [%.*s] PID=[%d] UID=[%d]\n",
 | |
|                  am_proc_start->process_name.length, am_proc_start->process_name.data,
 | |
|                  am_proc_start->pid.data, am_proc_start->uid.data);
 | |
|             handle_proc(am_proc_start->pid.data);
 | |
|         }
 | |
|         return;
 | |
|     }
 | |
|     if (event_header->tag == 3040) {
 | |
|         LOGD("logcat: soft reboot\n");
 | |
|         check_zygote();
 | |
|     }
 | |
| }
 | |
| 
 | |
| [[noreturn]] void run() {
 | |
|     while (true) {
 | |
|         const unique_ptr<logger_list, decltype(&android_logger_list_free)> logger_list{
 | |
|             android_logger_list_alloc(0, 1, 0), &android_logger_list_free};
 | |
| 
 | |
|         for (log_id id: {LOG_ID_MAIN, LOG_ID_EVENTS}) {
 | |
|             auto *logger = android_logger_open(logger_list.get(), id);
 | |
|             if (logger == nullptr) continue;
 | |
|         }
 | |
| 
 | |
|         struct log_msg msg{};
 | |
|         while (true) {
 | |
|             if (logcat_exit) {
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             if (android_logger_list_read(logger_list.get(), &msg) <= 0) {
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             switch (msg.entry.lid) {
 | |
|                 case LOG_ID_EVENTS:
 | |
|                     process_events_buffer(&msg.entry);
 | |
|                     break;
 | |
|                 case LOG_ID_MAIN:
 | |
|                     process_main_buffer(&msg.entry);
 | |
|                 default:
 | |
|                     break;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if (logcat_exit) {
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         sleep(1);
 | |
|     }
 | |
| 
 | |
|     LOGD("logcat: terminate\n");
 | |
|     pthread_exit(nullptr);
 | |
| }
 | |
| 
 | |
| void *logcat(void *) {
 | |
|     check_zygote();
 | |
|     run();
 | |
| }
 | 
