Mark Salyzyn | facf94c | 2016-03-01 13:45:42 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2007-2016 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #include <errno.h> |
| 18 | #include <fcntl.h> |
| 19 | #include <stdbool.h> |
| 20 | #include <string.h> |
| 21 | #include <sys/types.h> |
| 22 | |
| 23 | #include <private/android_filesystem_config.h> |
| 24 | #include <private/android_logger.h> |
| 25 | |
| 26 | #include "config_read.h" |
| 27 | #include "logger.h" |
| 28 | |
| 29 | static int pmsgAvailable(log_id_t logId); |
| 30 | static int pmsgVersion(struct android_log_logger *logger, |
| 31 | struct android_log_transport_context *transp); |
| 32 | static int pmsgRead(struct android_log_logger_list *logger_list, |
| 33 | struct android_log_transport_context *transp, |
| 34 | struct log_msg *log_msg); |
| 35 | static void pmsgClose(struct android_log_logger_list *logger_list, |
| 36 | struct android_log_transport_context *transp); |
| 37 | static int pmsgClear(struct android_log_logger *logger, |
| 38 | struct android_log_transport_context *transp); |
| 39 | |
| 40 | LIBLOG_HIDDEN struct android_log_transport_read pmsgLoggerRead = { |
| 41 | .node = { &pmsgLoggerRead.node, &pmsgLoggerRead.node }, |
| 42 | .name = "pmsg", |
| 43 | .available = pmsgAvailable, |
| 44 | .version = pmsgVersion, |
| 45 | .read = pmsgRead, |
| 46 | .poll = NULL, |
| 47 | .close = pmsgClose, |
| 48 | .clear = pmsgClear, |
| 49 | .setSize = NULL, |
| 50 | .getSize = NULL, |
| 51 | .getReadableSize = NULL, |
| 52 | .getPrune = NULL, |
| 53 | .setPrune = NULL, |
| 54 | .getStats = NULL, |
| 55 | }; |
| 56 | |
| 57 | static int pmsgAvailable(log_id_t logId) |
| 58 | { |
| 59 | if (logId > LOG_ID_SECURITY) { |
| 60 | return -EINVAL; |
| 61 | } |
| 62 | if (access("/dev/pmsg0", W_OK) == 0) { |
| 63 | return 0; |
| 64 | } |
| 65 | return -EBADF; |
| 66 | } |
| 67 | |
| 68 | /* Determine the credentials of the caller */ |
| 69 | static bool uid_has_log_permission(uid_t uid) |
| 70 | { |
| 71 | return (uid == AID_SYSTEM) || (uid == AID_LOG) || (uid == AID_ROOT); |
| 72 | } |
| 73 | |
| 74 | static uid_t get_best_effective_uid() |
| 75 | { |
| 76 | uid_t euid; |
| 77 | uid_t uid; |
| 78 | gid_t gid; |
| 79 | ssize_t i; |
| 80 | static uid_t last_uid = (uid_t) -1; |
| 81 | |
| 82 | if (last_uid != (uid_t) -1) { |
| 83 | return last_uid; |
| 84 | } |
| 85 | uid = __android_log_uid(); |
| 86 | if (uid_has_log_permission(uid)) { |
| 87 | return last_uid = uid; |
| 88 | } |
| 89 | euid = geteuid(); |
| 90 | if (uid_has_log_permission(euid)) { |
| 91 | return last_uid = euid; |
| 92 | } |
| 93 | gid = getgid(); |
| 94 | if (uid_has_log_permission(gid)) { |
| 95 | return last_uid = gid; |
| 96 | } |
| 97 | gid = getegid(); |
| 98 | if (uid_has_log_permission(gid)) { |
| 99 | return last_uid = gid; |
| 100 | } |
| 101 | i = getgroups((size_t) 0, NULL); |
| 102 | if (i > 0) { |
| 103 | gid_t list[i]; |
| 104 | |
| 105 | getgroups(i, list); |
| 106 | while (--i >= 0) { |
| 107 | if (uid_has_log_permission(list[i])) { |
| 108 | return last_uid = list[i]; |
| 109 | } |
| 110 | } |
| 111 | } |
| 112 | return last_uid = uid; |
| 113 | } |
| 114 | |
| 115 | static int pmsgClear(struct android_log_logger *logger __unused, |
| 116 | struct android_log_transport_context *transp __unused) |
| 117 | { |
| 118 | if (uid_has_log_permission(get_best_effective_uid())) { |
| 119 | return unlink("/sys/fs/pstore/pmsg-ramoops-0"); |
| 120 | } |
| 121 | errno = EPERM; |
| 122 | return -1; |
| 123 | } |
| 124 | |
| 125 | /* |
| 126 | * returns the logger version |
| 127 | */ |
| 128 | static int pmsgVersion(struct android_log_logger *logger __unused, |
| 129 | struct android_log_transport_context *transp __unused) |
| 130 | { |
| 131 | return 4; |
| 132 | } |
| 133 | |
| 134 | static int pmsgRead(struct android_log_logger_list *logger_list, |
| 135 | struct android_log_transport_context *transp, |
| 136 | struct log_msg *log_msg) |
| 137 | { |
| 138 | ssize_t ret; |
| 139 | off_t current, next; |
| 140 | uid_t uid; |
| 141 | struct android_log_logger *logger; |
| 142 | struct __attribute__((__packed__)) { |
| 143 | android_pmsg_log_header_t p; |
| 144 | android_log_header_t l; |
| 145 | } buf; |
| 146 | static uint8_t preread_count; |
| 147 | bool is_system; |
| 148 | |
| 149 | memset(log_msg, 0, sizeof(*log_msg)); |
| 150 | |
| 151 | if (transp->context.fd <= 0) { |
| 152 | int fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY); |
| 153 | |
| 154 | if (fd < 0) { |
| 155 | return -errno; |
| 156 | } |
| 157 | if (fd == 0) { /* Argggg */ |
| 158 | fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY); |
| 159 | close(0); |
| 160 | if (fd < 0) { |
| 161 | return -errno; |
| 162 | } |
| 163 | } |
| 164 | transp->context.fd = fd; |
| 165 | preread_count = 0; |
| 166 | } |
| 167 | |
| 168 | while(1) { |
| 169 | if (preread_count < sizeof(buf)) { |
| 170 | ret = TEMP_FAILURE_RETRY(read(transp->context.fd, |
| 171 | &buf.p.magic + preread_count, |
| 172 | sizeof(buf) - preread_count)); |
| 173 | if (ret < 0) { |
| 174 | return -errno; |
| 175 | } |
| 176 | preread_count += ret; |
| 177 | } |
| 178 | if (preread_count != sizeof(buf)) { |
| 179 | return preread_count ? -EIO : -EAGAIN; |
| 180 | } |
| 181 | if ((buf.p.magic != LOGGER_MAGIC) |
| 182 | || (buf.p.len <= sizeof(buf)) |
| 183 | || (buf.p.len > (sizeof(buf) + LOGGER_ENTRY_MAX_PAYLOAD)) |
| 184 | || (buf.l.id >= LOG_ID_MAX) |
| 185 | || (buf.l.realtime.tv_nsec >= NS_PER_SEC)) { |
| 186 | do { |
| 187 | memmove(&buf.p.magic, &buf.p.magic + 1, --preread_count); |
| 188 | } while (preread_count && (buf.p.magic != LOGGER_MAGIC)); |
| 189 | continue; |
| 190 | } |
| 191 | preread_count = 0; |
| 192 | |
| 193 | if ((transp->logMask & (1 << buf.l.id)) && |
| 194 | ((!logger_list->start.tv_sec && !logger_list->start.tv_nsec) || |
| 195 | ((logger_list->start.tv_sec <= buf.l.realtime.tv_sec) && |
| 196 | ((logger_list->start.tv_sec != buf.l.realtime.tv_sec) || |
| 197 | (logger_list->start.tv_nsec <= |
| 198 | buf.l.realtime.tv_nsec)))) && |
| 199 | (!logger_list->pid || (logger_list->pid == buf.p.pid))) { |
| 200 | uid = get_best_effective_uid(); |
| 201 | is_system = uid_has_log_permission(uid); |
| 202 | if (is_system || (uid == buf.p.uid)) { |
| 203 | ret = TEMP_FAILURE_RETRY(read(transp->context.fd, |
| 204 | is_system ? |
| 205 | log_msg->entry_v4.msg : |
| 206 | log_msg->entry_v3.msg, |
| 207 | buf.p.len - sizeof(buf))); |
| 208 | if (ret < 0) { |
| 209 | return -errno; |
| 210 | } |
| 211 | if (ret != (ssize_t)(buf.p.len - sizeof(buf))) { |
| 212 | return -EIO; |
| 213 | } |
| 214 | |
| 215 | log_msg->entry_v4.len = buf.p.len - sizeof(buf); |
| 216 | log_msg->entry_v4.hdr_size = is_system ? |
| 217 | sizeof(log_msg->entry_v4) : |
| 218 | sizeof(log_msg->entry_v3); |
| 219 | log_msg->entry_v4.pid = buf.p.pid; |
| 220 | log_msg->entry_v4.tid = buf.l.tid; |
| 221 | log_msg->entry_v4.sec = buf.l.realtime.tv_sec; |
| 222 | log_msg->entry_v4.nsec = buf.l.realtime.tv_nsec; |
| 223 | log_msg->entry_v4.lid = buf.l.id; |
| 224 | if (is_system) { |
| 225 | log_msg->entry_v4.uid = buf.p.uid; |
| 226 | } |
| 227 | |
| 228 | return ret; |
| 229 | } |
| 230 | } |
| 231 | |
| 232 | current = TEMP_FAILURE_RETRY(lseek(transp->context.fd, |
| 233 | (off_t)0, SEEK_CUR)); |
| 234 | if (current < 0) { |
| 235 | return -errno; |
| 236 | } |
| 237 | next = TEMP_FAILURE_RETRY(lseek(transp->context.fd, |
| 238 | (off_t)(buf.p.len - sizeof(buf)), |
| 239 | SEEK_CUR)); |
| 240 | if (next < 0) { |
| 241 | return -errno; |
| 242 | } |
| 243 | if ((next - current) != (ssize_t)(buf.p.len - sizeof(buf))) { |
| 244 | return -EIO; |
| 245 | } |
| 246 | } |
| 247 | } |
| 248 | |
| 249 | static void pmsgClose(struct android_log_logger_list *logger_list __unused, |
| 250 | struct android_log_transport_context *transp) { |
| 251 | if (transp->context.fd > 0) { |
| 252 | close (transp->context.fd); |
| 253 | } |
| 254 | transp->context.fd = 0; |
| 255 | } |