From 6eef4171195f83541b3ee62cdcc4eac863c5edd9 Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Mon, 15 Dec 2014 09:51:39 -0800 Subject: [PATCH] liblog: add pstore read Used to pull the Android log messages after a reboot. Adding an ANDROID_LOG_PSTORE flag to the mode parameter in calls to android_logger_list_alloc() and android_logger_list_alloc_time(). The side effects are that android_logger_clear() and android_logger_list_read() will react with the user space pstore driver. Forms a companion to the pstore console logs. Change-Id: I7bb07b87b3bf73f059a21af3f810af37c7715b6d --- include/log/logger.h | 1 + liblog/README | 6 +- liblog/log_read.c | 171 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+), 1 deletion(-) diff --git a/include/log/logger.h b/include/log/logger.h index 570f02bc7..f030dab5a 100644 --- a/include/log/logger.h +++ b/include/log/logger.h @@ -159,6 +159,7 @@ int android_logger_set_prune_list(struct logger_list *logger_list, #define ANDROID_LOG_RDWR O_RDWR #define ANDROID_LOG_ACCMODE O_ACCMODE #define ANDROID_LOG_NONBLOCK O_NONBLOCK +#define ANDROID_LOG_PSTORE 0x80000000 struct logger_list *android_logger_list_alloc(int mode, unsigned int tail, diff --git a/liblog/README b/liblog/README index 0676aecb8..461dfbe98 100644 --- a/liblog/README +++ b/liblog/README @@ -116,6 +116,10 @@ DESCRIPTION code, otherwise the android_logger_list_read call will block for new entries. + The ANDROID_LOG_PSTORE mode flag to the android_logger_open is used to + switch from the active logs to the persistent logs from before the last + reboot. + The value returned by android_logger_open can be used as a parameter to the android_logger_clear function to empty the sub-log. It is recom‐ mended to only open log ANDROID_LOG_WRONLY in that case. @@ -132,4 +136,4 @@ SEE ALSO - 17 Dec 2013 LIBLOG(3) + 24 Jan 2014 LIBLOG(3) diff --git a/liblog/log_read.c b/liblog/log_read.c index 0b126cf4d..5364e4f17 100644 --- a/liblog/log_read.c +++ b/liblog/log_read.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #define NOMINMAX /* for windows to suppress definition of min in stdlib.h */ #include @@ -30,6 +31,8 @@ #include #include #include +#include +#include /* branchless on many architectures. */ #define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y)))) @@ -357,10 +360,64 @@ static int check_log_success(char *buf, ssize_t ret) return 0; } +/* Determine the credentials of the caller */ +static bool uid_has_log_permission(uid_t uid) +{ + return (uid == AID_SYSTEM) || (uid == AID_LOG) || (uid == AID_ROOT); +} + +static uid_t get_best_effective_uid() +{ + uid_t euid; + uid_t uid; + gid_t gid; + ssize_t i; + static uid_t last_uid = (uid_t) -1; + + if (last_uid != (uid_t) -1) { + return last_uid; + } + uid = getuid(); + if (uid_has_log_permission(uid)) { + return last_uid = uid; + } + euid = geteuid(); + if (uid_has_log_permission(euid)) { + return last_uid = euid; + } + gid = getgid(); + if (uid_has_log_permission(gid)) { + return last_uid = gid; + } + gid = getegid(); + if (uid_has_log_permission(gid)) { + return last_uid = gid; + } + i = getgroups((size_t) 0, NULL); + if (i > 0) { + gid_t list[i]; + + getgroups(i, list); + while (--i >= 0) { + if (uid_has_log_permission(list[i])) { + return last_uid = list[i]; + } + } + } + return last_uid = uid; +} + int android_logger_clear(struct logger *logger) { char buf[512]; + if (logger->top->mode & ANDROID_LOG_PSTORE) { + if (uid_has_log_permission(get_best_effective_uid())) { + return unlink("/sys/fs/pstore/pmsg-ramoops-0"); + } + errno = EPERM; + return -1; + } return check_log_success(buf, send_log_msg(logger, "clear %d", buf, sizeof(buf))); } @@ -564,6 +621,116 @@ struct logger_list *android_logger_list_open(log_id_t id, return logger_list; } +static int android_logger_list_read_pstore(struct logger_list *logger_list, + struct log_msg *log_msg) +{ + ssize_t ret; + off_t current, next; + uid_t uid; + struct logger *logger; + struct __attribute__((__packed__)) { + android_pmsg_log_header_t p; + android_log_header_t l; + } buf; + static uint8_t preread_count; + + memset(log_msg, 0, sizeof(*log_msg)); + + if (logger_list->sock < 0) { + int fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY); + + if (fd < 0) { + return -errno; + } + logger_list->sock = fd; + preread_count = 0; + } + + ret = 0; + while(1) { + if (preread_count < sizeof(buf)) { + ret = TEMP_FAILURE_RETRY(read(logger_list->sock, + &buf.p.magic + preread_count, + sizeof(buf) - preread_count)); + if (ret < 0) { + return -errno; + } + preread_count += ret; + } + if (preread_count != sizeof(buf)) { + return preread_count ? -EIO : -EAGAIN; + } + if ((buf.p.magic != LOGGER_MAGIC) + || (buf.p.len <= sizeof(buf)) + || (buf.p.len > (sizeof(buf) + LOGGER_ENTRY_MAX_PAYLOAD)) + || (buf.l.id >= LOG_ID_MAX) + || (buf.l.realtime.tv_nsec >= NS_PER_SEC)) { + do { + memmove(&buf.p.magic, &buf.p.magic + 1, --preread_count); + } while (preread_count && (buf.p.magic != LOGGER_MAGIC)); + continue; + } + preread_count = 0; + + logger_for_each(logger, logger_list) { + if (buf.l.id != logger->id) { + continue; + } + + if ((logger_list->start.tv_sec || logger_list->start.tv_nsec) + && ((logger_list->start.tv_sec > buf.l.realtime.tv_sec) + || ((logger_list->start.tv_sec == buf.l.realtime.tv_sec) + && (logger_list->start.tv_nsec > buf.l.realtime.tv_nsec)))) { + break; + } + + if (logger_list->pid && (logger_list->pid != buf.p.pid)) { + break; + } + + uid = get_best_effective_uid(); + if (!uid_has_log_permission(uid) && (uid != buf.p.uid)) { + break; + } + + ret = TEMP_FAILURE_RETRY(read(logger_list->sock, + log_msg->entry_v3.msg, + buf.p.len - sizeof(buf))); + if (ret < 0) { + return -errno; + } + if (ret != (ssize_t)(buf.p.len - sizeof(buf))) { + return -EIO; + } + + log_msg->entry_v3.len = buf.p.len - sizeof(buf); + log_msg->entry_v3.hdr_size = sizeof(log_msg->entry_v3); + log_msg->entry_v3.pid = buf.p.pid; + log_msg->entry_v3.tid = buf.l.tid; + log_msg->entry_v3.sec = buf.l.realtime.tv_sec; + log_msg->entry_v3.nsec = buf.l.realtime.tv_nsec; + log_msg->entry_v3.lid = buf.l.id; + + return ret; + } + + current = TEMP_FAILURE_RETRY(lseek(logger_list->sock, + (off_t)0, SEEK_CUR)); + if (current < 0) { + return -errno; + } + next = TEMP_FAILURE_RETRY(lseek(logger_list->sock, + (off_t)(buf.p.len - sizeof(buf)), + SEEK_CUR)); + if (next < 0) { + return -errno; + } + if ((next - current) != (ssize_t)(buf.p.len - sizeof(buf))) { + return -EIO; + } + } +} + static void caught_signal(int signum __unused) { } @@ -582,6 +749,10 @@ int android_logger_list_read(struct logger_list *logger_list, return -EINVAL; } + if (logger_list->mode & ANDROID_LOG_PSTORE) { + return android_logger_list_read_pstore(logger_list, log_msg); + } + if (logger_list->mode & ANDROID_LOG_NONBLOCK) { memset(&ignore, 0, sizeof(ignore)); ignore.sa_handler = caught_signal;