diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp index 22fde5ea4..7f450e6bc 100644 --- a/debuggerd/libdebuggerd/utility.cpp +++ b/debuggerd/libdebuggerd/utility.cpp @@ -22,16 +22,22 @@ #include #include #include +#include #include #include #include +#include +#include #include +#include #include #include #include +using android::base::unique_fd; + // Whitelist output desired in the logcat output. bool is_allowed_in_logcat(enum logtype ltype) { if ((ltype == HEADER) @@ -42,6 +48,19 @@ bool is_allowed_in_logcat(enum logtype ltype) { return false; } +static bool should_write_to_kmsg() { + // Write to kmsg if tombstoned isn't up, and we're able to do so. + if (!android::base::GetBoolProperty("ro.debuggable", false)) { + return false; + } + + if (android::base::GetProperty("init.svc.tombstoned", "") == "running") { + return false; + } + + return true; +} + __attribute__((__weak__, visibility("default"))) void _LOG(log_t* log, enum logtype ltype, const char* fmt, ...) { bool write_to_tombstone = (log->tfd != -1); @@ -49,6 +68,7 @@ void _LOG(log_t* log, enum logtype ltype, const char* fmt, ...) { && log->crashed_tid != -1 && log->current_tid != -1 && (log->crashed_tid == log->current_tid); + static bool write_to_kmsg = should_write_to_kmsg(); char buf[512]; va_list ap; @@ -70,6 +90,30 @@ void _LOG(log_t* log, enum logtype ltype, const char* fmt, ...) { if (log->amfd_data != nullptr) { *log->amfd_data += buf; } + + if (write_to_kmsg) { + unique_fd kmsg_fd(open("/dev/kmsg_debug", O_WRONLY | O_APPEND | O_CLOEXEC)); + if (kmsg_fd.get() >= 0) { + // Our output might contain newlines which would otherwise be handled by the android logger. + // Split the lines up ourselves before sending to the kernel logger. + if (buf[len - 1] == '\n') { + buf[len - 1] = '\0'; + } + + std::vector fragments = android::base::Split(buf, "\n"); + for (const std::string& fragment : fragments) { + static constexpr char prefix[] = "<3>DEBUG: "; + struct iovec iov[3]; + iov[0].iov_base = const_cast(prefix); + iov[0].iov_len = strlen(prefix); + iov[1].iov_base = const_cast(fragment.c_str()); + iov[1].iov_len = fragment.length(); + iov[2].iov_base = const_cast("\n"); + iov[2].iov_len = 1; + TEMP_FAILURE_RETRY(writev(kmsg_fd.get(), iov, 3)); + } + } + } } } @@ -205,7 +249,7 @@ void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* f } void read_with_default(const char* path, char* buf, size_t len, const char* default_value) { - android::base::unique_fd fd(open(path, O_RDONLY)); + unique_fd fd(open(path, O_RDONLY | O_CLOEXEC)); if (fd != -1) { int rc = TEMP_FAILURE_RETRY(read(fd.get(), buf, len - 1)); if (rc != -1) { diff --git a/init/Android.mk b/init/Android.mk index 2bf453de2..3886ed52f 100644 --- a/init/Android.mk +++ b/init/Android.mk @@ -9,12 +9,14 @@ init_options += \ -DALLOW_LOCAL_PROP_OVERRIDE=1 \ -DALLOW_PERMISSIVE_SELINUX=1 \ -DREBOOT_BOOTLOADER_ON_PANIC=1 \ + -DWORLD_WRITABLE_KMSG=1 \ -DDUMP_ON_UMOUNT_FAILURE=1 else init_options += \ -DALLOW_LOCAL_PROP_OVERRIDE=0 \ -DALLOW_PERMISSIVE_SELINUX=0 \ -DREBOOT_BOOTLOADER_ON_PANIC=0 \ + -DWORLD_WRITABLE_KMSG=0 \ -DDUMP_ON_UMOUNT_FAILURE=0 endif diff --git a/init/init.cpp b/init/init.cpp index dafaf2124..5e98707d2 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -933,6 +933,9 @@ static void selinux_restore_context() { LOG(INFO) << "Running restorecon..."; selinux_android_restorecon("/dev", 0); selinux_android_restorecon("/dev/kmsg", 0); + if constexpr (WORLD_WRITABLE_KMSG) { + selinux_android_restorecon("/dev/kmsg_debug", 0); + } selinux_android_restorecon("/dev/socket", 0); selinux_android_restorecon("/dev/random", 0); selinux_android_restorecon("/dev/urandom", 0); @@ -1037,7 +1040,13 @@ int main(int argc, char** argv) { setgroups(arraysize(groups), groups); mount("sysfs", "/sys", "sysfs", 0, NULL); mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL); + mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11)); + + if constexpr (WORLD_WRITABLE_KMSG) { + mknod("/dev/kmsg_debug", S_IFCHR | 0622, makedev(1, 11)); + } + mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8)); mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9));