blob: de435f7edd980a52e8feec8e72fd4ef1583723a1 [file] [log] [blame]
Mark Salyzynfacf94c2016-03-01 13:45:42 -08001/*
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
29static int pmsgAvailable(log_id_t logId);
30static int pmsgVersion(struct android_log_logger *logger,
31 struct android_log_transport_context *transp);
32static int pmsgRead(struct android_log_logger_list *logger_list,
33 struct android_log_transport_context *transp,
34 struct log_msg *log_msg);
35static void pmsgClose(struct android_log_logger_list *logger_list,
36 struct android_log_transport_context *transp);
37static int pmsgClear(struct android_log_logger *logger,
38 struct android_log_transport_context *transp);
39
40LIBLOG_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
57static 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 */
69static bool uid_has_log_permission(uid_t uid)
70{
71 return (uid == AID_SYSTEM) || (uid == AID_LOG) || (uid == AID_ROOT);
72}
73
74static 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
115static 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 */
128static int pmsgVersion(struct android_log_logger *logger __unused,
129 struct android_log_transport_context *transp __unused)
130{
131 return 4;
132}
133
134static 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
249static 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}