summaryrefslogtreecommitdiffstats
path: root/liblog/log_read.c
diff options
context:
space:
mode:
Diffstat (limited to 'liblog/log_read.c')
-rw-r--r--liblog/log_read.c193
1 files changed, 184 insertions, 9 deletions
diff --git a/liblog/log_read.c b/liblog/log_read.c
index ca5a1a7..5364e4f 100644
--- a/liblog/log_read.c
+++ b/liblog/log_read.c
@@ -19,6 +19,7 @@
#include <inttypes.h>
#include <poll.h>
#include <signal.h>
+#include <stdbool.h>
#include <stddef.h>
#define NOMINMAX /* for windows to suppress definition of min in stdlib.h */
#include <stdlib.h>
@@ -30,11 +31,17 @@
#include <cutils/sockets.h>
#include <log/log.h>
#include <log/logger.h>
+#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
/* branchless on many architectures. */
#define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
+#if (defined(USE_MINGW) || defined(HAVE_WINSOCK))
+#define WEAK static
+#else
#define WEAK __attribute__((weak))
+#endif
#ifndef __unused
#define __unused __attribute__((unused))
#endif
@@ -72,7 +79,7 @@ int WEAK socket_make_sockaddr_un(const char *name, int namespaceId,
switch (namespaceId) {
case ANDROID_SOCKET_NAMESPACE_ABSTRACT:
-#ifdef HAVE_LINUX_LOCAL_SOCKET_NAMESPACE
+#if defined(__linux__)
namelen = strlen(name);
/* Test with length +1 for the *initial* '\0'. */
@@ -87,7 +94,7 @@ int WEAK socket_make_sockaddr_un(const char *name, int namespaceId,
p_addr->sun_path[0] = 0;
memcpy(p_addr->sun_path + 1, name, namelen);
-#else /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/
+#else
/* this OS doesn't have the Linux abstract namespace */
namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX);
@@ -99,7 +106,7 @@ int WEAK socket_make_sockaddr_un(const char *name, int namespaceId,
strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX);
strcat(p_addr->sun_path, name);
-#endif /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/
+#endif
break;
case ANDROID_SOCKET_NAMESPACE_RESERVED:
@@ -353,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)));
}
@@ -560,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)
{
}
@@ -578,7 +749,11 @@ int android_logger_list_read(struct logger_list *logger_list,
return -EINVAL;
}
- if (logger_list->mode & O_NONBLOCK) {
+ 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;
sigemptyset(&ignore.sa_mask);
@@ -598,7 +773,7 @@ int android_logger_list_read(struct logger_list *logger_list,
}
strcpy(buffer,
- (logger_list->mode & O_NONBLOCK) ? "dumpAndClose" : "stream");
+ (logger_list->mode & ANDROID_LOG_NONBLOCK) ? "dumpAndClose" : "stream");
cp = buffer + strlen(buffer);
strcpy(cp, " lids");
@@ -636,14 +811,14 @@ int android_logger_list_read(struct logger_list *logger_list,
cp += ret;
}
- if (logger_list->mode & O_NONBLOCK) {
+ if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
/* Deal with an unresponsive logd */
sigaction(SIGALRM, &ignore, &old_sigaction);
old_alarm = alarm(30);
}
ret = write(sock, buffer, cp - buffer);
e = errno;
- if (logger_list->mode & O_NONBLOCK) {
+ if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
if (e == EINTR) {
e = ETIMEDOUT;
}
@@ -669,7 +844,7 @@ int android_logger_list_read(struct logger_list *logger_list,
while(1) {
memset(log_msg, 0, sizeof(*log_msg));
- if (logger_list->mode & O_NONBLOCK) {
+ if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
/* particularily useful if tombstone is reporting for logd */
sigaction(SIGALRM, &ignore, &old_sigaction);
old_alarm = alarm(30);
@@ -677,7 +852,7 @@ int android_logger_list_read(struct logger_list *logger_list,
/* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */
ret = recv(logger_list->sock, log_msg, LOGGER_ENTRY_MAX_LEN, 0);
e = errno;
- if (logger_list->mode & O_NONBLOCK) {
+ if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
if ((ret == 0) || (e == EINTR)) {
e = EAGAIN;
ret = -1;