• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <ctype.h>
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <stdbool.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/types.h>
24 
25 #include <private/android_filesystem_config.h>
26 #include <private/android_logger.h>
27 
28 #include "config_read.h"
29 #include "logger.h"
30 
31 static int pmsgAvailable(log_id_t logId);
32 static int pmsgVersion(struct android_log_logger* logger,
33                        struct android_log_transport_context* transp);
34 static int pmsgRead(struct android_log_logger_list* logger_list,
35                     struct android_log_transport_context* transp, struct log_msg* log_msg);
36 static void pmsgClose(struct android_log_logger_list* logger_list,
37                       struct android_log_transport_context* transp);
38 static int pmsgClear(struct android_log_logger* logger,
39                      struct android_log_transport_context* transp);
40 
41 struct android_log_transport_read pmsgLoggerRead = {
42     .node = {&pmsgLoggerRead.node, &pmsgLoggerRead.node},
43     .name = "pmsg",
44     .available = pmsgAvailable,
45     .version = pmsgVersion,
46     .read = pmsgRead,
47     .poll = NULL,
48     .close = pmsgClose,
49     .clear = pmsgClear,
50     .setSize = NULL,
51     .getSize = NULL,
52     .getReadableSize = NULL,
53     .getPrune = NULL,
54     .setPrune = NULL,
55     .getStats = NULL,
56 };
57 
pmsgAvailable(log_id_t logId)58 static int pmsgAvailable(log_id_t logId) {
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 */
uid_has_log_permission(uid_t uid)69 static bool uid_has_log_permission(uid_t uid) {
70   return (uid == AID_SYSTEM) || (uid == AID_LOG) || (uid == AID_ROOT) || (uid == AID_LOGD);
71 }
72 
get_best_effective_uid()73 static uid_t get_best_effective_uid() {
74   uid_t euid;
75   uid_t uid;
76   gid_t gid;
77   ssize_t i;
78   static uid_t last_uid = (uid_t)-1;
79 
80   if (last_uid != (uid_t)-1) {
81     return last_uid;
82   }
83   uid = __android_log_uid();
84   if (uid_has_log_permission(uid)) {
85     return last_uid = uid;
86   }
87   euid = geteuid();
88   if (uid_has_log_permission(euid)) {
89     return last_uid = euid;
90   }
91   gid = getgid();
92   if (uid_has_log_permission(gid)) {
93     return last_uid = gid;
94   }
95   gid = getegid();
96   if (uid_has_log_permission(gid)) {
97     return last_uid = gid;
98   }
99   i = getgroups((size_t)0, NULL);
100   if (i > 0) {
101     gid_t list[i];
102 
103     getgroups(i, list);
104     while (--i >= 0) {
105       if (uid_has_log_permission(list[i])) {
106         return last_uid = list[i];
107       }
108     }
109   }
110   return last_uid = uid;
111 }
112 
pmsgClear(struct android_log_logger * logger __unused,struct android_log_transport_context * transp __unused)113 static int pmsgClear(struct android_log_logger* logger __unused,
114                      struct android_log_transport_context* transp __unused) {
115   if (uid_has_log_permission(get_best_effective_uid())) {
116     return unlink("/sys/fs/pstore/pmsg-ramoops-0");
117   }
118   errno = EPERM;
119   return -1;
120 }
121 
122 /*
123  * returns the logger version
124  */
pmsgVersion(struct android_log_logger * logger __unused,struct android_log_transport_context * transp __unused)125 static int pmsgVersion(struct android_log_logger* logger __unused,
126                        struct android_log_transport_context* transp __unused) {
127   return 4;
128 }
129 
pmsgRead(struct android_log_logger_list * logger_list,struct android_log_transport_context * transp,struct log_msg * log_msg)130 static int pmsgRead(struct android_log_logger_list* logger_list,
131                     struct android_log_transport_context* transp, struct log_msg* log_msg) {
132   ssize_t ret;
133   off_t current, next;
134   uid_t uid;
135   struct android_log_logger* logger;
136   struct __attribute__((__packed__)) {
137     android_pmsg_log_header_t p;
138     android_log_header_t l;
139     uint8_t prio;
140   } buf;
141   static uint8_t preread_count;
142   bool is_system;
143 
144   memset(log_msg, 0, sizeof(*log_msg));
145 
146   if (atomic_load(&transp->context.fd) <= 0) {
147     int i, fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY | O_CLOEXEC);
148 
149     if (fd < 0) {
150       return -errno;
151     }
152     if (fd == 0) { /* Argggg */
153       fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY | O_CLOEXEC);
154       close(0);
155       if (fd < 0) {
156         return -errno;
157       }
158     }
159     i = atomic_exchange(&transp->context.fd, fd);
160     if ((i > 0) && (i != fd)) {
161       close(i);
162     }
163     preread_count = 0;
164   }
165 
166   while (1) {
167     int fd;
168 
169     if (preread_count < sizeof(buf)) {
170       fd = atomic_load(&transp->context.fd);
171       if (fd <= 0) {
172         return -EBADF;
173       }
174       ret = TEMP_FAILURE_RETRY(read(fd, &buf.p.magic + preread_count, sizeof(buf) - preread_count));
175       if (ret < 0) {
176         return -errno;
177       }
178       preread_count += ret;
179     }
180     if (preread_count != sizeof(buf)) {
181       return preread_count ? -EIO : -EAGAIN;
182     }
183     if ((buf.p.magic != LOGGER_MAGIC) || (buf.p.len <= sizeof(buf)) ||
184         (buf.p.len > (sizeof(buf) + LOGGER_ENTRY_MAX_PAYLOAD)) || (buf.l.id >= LOG_ID_MAX) ||
185         (buf.l.realtime.tv_nsec >= NS_PER_SEC) ||
186         ((buf.l.id != LOG_ID_EVENTS) && (buf.l.id != LOG_ID_SECURITY) &&
187          ((buf.prio == ANDROID_LOG_UNKNOWN) || (buf.prio == ANDROID_LOG_DEFAULT) ||
188           (buf.prio >= ANDROID_LOG_SILENT)))) {
189       do {
190         memmove(&buf.p.magic, &buf.p.magic + 1, --preread_count);
191       } while (preread_count && (buf.p.magic != LOGGER_MAGIC));
192       continue;
193     }
194     preread_count = 0;
195 
196     if ((transp->logMask & (1 << buf.l.id)) &&
197         ((!logger_list->start.tv_sec && !logger_list->start.tv_nsec) ||
198          ((logger_list->start.tv_sec <= buf.l.realtime.tv_sec) &&
199           ((logger_list->start.tv_sec != buf.l.realtime.tv_sec) ||
200            (logger_list->start.tv_nsec <= buf.l.realtime.tv_nsec)))) &&
201         (!logger_list->pid || (logger_list->pid == buf.p.pid))) {
202       uid = get_best_effective_uid();
203       is_system = uid_has_log_permission(uid);
204       if (is_system || (uid == buf.p.uid)) {
205         char* msg = is_system ? log_msg->entry_v4.msg : log_msg->entry_v3.msg;
206         *msg = buf.prio;
207         fd = atomic_load(&transp->context.fd);
208         if (fd <= 0) {
209           return -EBADF;
210         }
211         ret = TEMP_FAILURE_RETRY(read(fd, msg + sizeof(buf.prio), buf.p.len - sizeof(buf)));
212         if (ret < 0) {
213           return -errno;
214         }
215         if (ret != (ssize_t)(buf.p.len - sizeof(buf))) {
216           return -EIO;
217         }
218 
219         log_msg->entry_v4.len = buf.p.len - sizeof(buf) + sizeof(buf.prio);
220         log_msg->entry_v4.hdr_size =
221             is_system ? sizeof(log_msg->entry_v4) : sizeof(log_msg->entry_v3);
222         log_msg->entry_v4.pid = buf.p.pid;
223         log_msg->entry_v4.tid = buf.l.tid;
224         log_msg->entry_v4.sec = buf.l.realtime.tv_sec;
225         log_msg->entry_v4.nsec = buf.l.realtime.tv_nsec;
226         log_msg->entry_v4.lid = buf.l.id;
227         if (is_system) {
228           log_msg->entry_v4.uid = buf.p.uid;
229         }
230 
231         return ret + sizeof(buf.prio) + log_msg->entry_v4.hdr_size;
232       }
233     }
234 
235     fd = atomic_load(&transp->context.fd);
236     if (fd <= 0) {
237       return -EBADF;
238     }
239     current = TEMP_FAILURE_RETRY(lseek(fd, (off_t)0, SEEK_CUR));
240     if (current < 0) {
241       return -errno;
242     }
243     fd = atomic_load(&transp->context.fd);
244     if (fd <= 0) {
245       return -EBADF;
246     }
247     next = TEMP_FAILURE_RETRY(lseek(fd, (off_t)(buf.p.len - sizeof(buf)), SEEK_CUR));
248     if (next < 0) {
249       return -errno;
250     }
251     if ((next - current) != (ssize_t)(buf.p.len - sizeof(buf))) {
252       return -EIO;
253     }
254   }
255 }
256 
pmsgClose(struct android_log_logger_list * logger_list __unused,struct android_log_transport_context * transp)257 static void pmsgClose(struct android_log_logger_list* logger_list __unused,
258                       struct android_log_transport_context* transp) {
259   int fd = atomic_exchange(&transp->context.fd, 0);
260   if (fd > 0) {
261     close(fd);
262   }
263 }
264 
realloc_or_free(void * ptr,size_t new_size)265 static void* realloc_or_free(void* ptr, size_t new_size) {
266   void* result = realloc(ptr, new_size);
267   if (!result) {
268     free(ptr);
269   }
270   return result;
271 }
272 
__android_log_pmsg_file_read(log_id_t logId,char prio,const char * prefix,__android_log_pmsg_file_read_fn fn,void * arg)273 ssize_t __android_log_pmsg_file_read(log_id_t logId, char prio, const char* prefix,
274                                      __android_log_pmsg_file_read_fn fn, void* arg) {
275   ssize_t ret;
276   struct android_log_logger_list logger_list;
277   struct android_log_transport_context transp;
278   struct content {
279     struct listnode node;
280     union {
281       struct logger_entry_v4 entry;
282       struct logger_entry_v4 entry_v4;
283       struct logger_entry_v3 entry_v3;
284       struct logger_entry_v2 entry_v2;
285       struct logger_entry entry_v1;
286     };
287   } * content;
288   struct names {
289     struct listnode node;
290     struct listnode content;
291     log_id_t id;
292     char prio;
293     char name[];
294   } * names;
295   struct listnode name_list;
296   struct listnode *node, *n;
297   size_t len, prefix_len;
298 
299   if (!fn) {
300     return -EINVAL;
301   }
302 
303   /* Add just enough clues in logger_list and transp to make API function */
304   memset(&logger_list, 0, sizeof(logger_list));
305   memset(&transp, 0, sizeof(transp));
306 
307   logger_list.mode = ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK | ANDROID_LOG_RDONLY;
308   transp.logMask = (unsigned)-1;
309   if (logId != LOG_ID_ANY) {
310     transp.logMask = (1 << logId);
311   }
312   transp.logMask &= ~((1 << LOG_ID_KERNEL) | (1 << LOG_ID_EVENTS) | (1 << LOG_ID_SECURITY));
313   if (!transp.logMask) {
314     return -EINVAL;
315   }
316 
317   /* Initialize name list */
318   list_init(&name_list);
319 
320   ret = SSIZE_MAX;
321 
322   /* Validate incoming prefix, shift until it contains only 0 or 1 : or / */
323   prefix_len = 0;
324   if (prefix) {
325     const char *prev = NULL, *last = NULL, *cp = prefix;
326     while ((cp = strpbrk(cp, "/:"))) {
327       prev = last;
328       last = cp;
329       cp = cp + 1;
330     }
331     if (prev) {
332       prefix = prev + 1;
333     }
334     prefix_len = strlen(prefix);
335   }
336 
337   /* Read the file content */
338   while (pmsgRead(&logger_list, &transp, &transp.logMsg) > 0) {
339     const char* cp;
340     size_t hdr_size = transp.logMsg.entry.hdr_size ? transp.logMsg.entry.hdr_size
341                                                    : sizeof(transp.logMsg.entry_v1);
342     char* msg = (char*)&transp.logMsg + hdr_size;
343     const char* split = NULL;
344 
345     if ((hdr_size < sizeof(transp.logMsg.entry_v1)) || (hdr_size > sizeof(transp.logMsg.entry))) {
346       continue;
347     }
348     /* Check for invalid sequence number */
349     if ((transp.logMsg.entry.nsec % ANDROID_LOG_PMSG_FILE_SEQUENCE) ||
350         ((transp.logMsg.entry.nsec / ANDROID_LOG_PMSG_FILE_SEQUENCE) >=
351          ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE)) {
352       continue;
353     }
354 
355     /* Determine if it has <dirbase>:<filebase> format for tag */
356     len = transp.logMsg.entry.len - sizeof(prio);
357     for (cp = msg + sizeof(prio); *cp && isprint(*cp) && !isspace(*cp) && --len; ++cp) {
358       if (*cp == ':') {
359         if (split) {
360           break;
361         }
362         split = cp;
363       }
364     }
365     if (*cp || !split) {
366       continue;
367     }
368 
369     /* Filters */
370     if (prefix_len && strncmp(msg + sizeof(prio), prefix, prefix_len)) {
371       size_t offset;
372       /*
373        *   Allow : to be a synonym for /
374        * Things we do dealing with const char * and do not alloc
375        */
376       split = strchr(prefix, ':');
377       if (split) {
378         continue;
379       }
380       split = strchr(prefix, '/');
381       if (!split) {
382         continue;
383       }
384       offset = split - prefix;
385       if ((msg[offset + sizeof(prio)] != ':') || strncmp(msg + sizeof(prio), prefix, offset)) {
386         continue;
387       }
388       ++offset;
389       if ((prefix_len > offset) &&
390           strncmp(&msg[offset + sizeof(prio)], split + 1, prefix_len - offset)) {
391         continue;
392       }
393     }
394 
395     if ((prio != ANDROID_LOG_ANY) && (*msg < prio)) {
396       continue;
397     }
398 
399     /* check if there is an existing entry */
400     list_for_each(node, &name_list) {
401       names = node_to_item(node, struct names, node);
402       if (!strcmp(names->name, msg + sizeof(prio)) && (names->id == transp.logMsg.entry.lid) &&
403           (names->prio == *msg)) {
404         break;
405       }
406     }
407 
408     /* We do not have an existing entry, create and add one */
409     if (node == &name_list) {
410       static const char numbers[] = "0123456789";
411       unsigned long long nl;
412 
413       len = strlen(msg + sizeof(prio)) + 1;
414       names = static_cast<struct names*>(calloc(1, sizeof(*names) + len));
415       if (!names) {
416         ret = -ENOMEM;
417         break;
418       }
419       strcpy(names->name, msg + sizeof(prio));
420       names->id = static_cast<log_id_t>(transp.logMsg.entry.lid);
421       names->prio = *msg;
422       list_init(&names->content);
423       /*
424        * Insert in reverse numeric _then_ alpha sorted order as
425        * representative of log rotation:
426        *
427        *   log.10
428        *   klog.10
429        *   . . .
430        *   log.2
431        *   klog.2
432        *   log.1
433        *   klog.1
434        *   log
435        *   klog
436        *
437        * thus when we present the content, we are provided the oldest
438        * first, which when 'refreshed' could spill off the end of the
439        * pmsg FIFO but retaining the newest data for last with best
440        * chances to survive.
441        */
442       nl = 0;
443       cp = strpbrk(names->name, numbers);
444       if (cp) {
445         nl = strtoull(cp, NULL, 10);
446       }
447       list_for_each_reverse(node, &name_list) {
448         struct names* a_name = node_to_item(node, struct names, node);
449         const char* r = a_name->name;
450         int compare = 0;
451 
452         unsigned long long nr = 0;
453         cp = strpbrk(r, numbers);
454         if (cp) {
455           nr = strtoull(cp, NULL, 10);
456         }
457         if (nr != nl) {
458           compare = (nl > nr) ? 1 : -1;
459         }
460         if (compare == 0) {
461           compare = strcmp(names->name, r);
462         }
463         if (compare <= 0) {
464           break;
465         }
466       }
467       list_add_head(node, &names->node);
468     }
469 
470     /* Remove any file fragments that match our sequence number */
471     list_for_each_safe(node, n, &names->content) {
472       content = node_to_item(node, struct content, node);
473       if (transp.logMsg.entry.nsec == content->entry.nsec) {
474         list_remove(&content->node);
475         free(content);
476       }
477     }
478 
479     /* Add content */
480     content = static_cast<struct content*>(
481         calloc(1, sizeof(content->node) + hdr_size + transp.logMsg.entry.len));
482     if (!content) {
483       ret = -ENOMEM;
484       break;
485     }
486     memcpy(&content->entry, &transp.logMsg.entry, hdr_size + transp.logMsg.entry.len);
487 
488     /* Insert in sequence number sorted order, to ease reconstruction */
489     list_for_each_reverse(node, &names->content) {
490       if ((node_to_item(node, struct content, node))->entry.nsec < transp.logMsg.entry.nsec) {
491         break;
492       }
493     }
494     list_add_head(node, &content->node);
495   }
496   pmsgClose(&logger_list, &transp);
497 
498   /* Progress through all the collected files */
499   list_for_each_safe(node, n, &name_list) {
500     struct listnode *content_node, *m;
501     char* buf;
502     size_t sequence, tag_len;
503 
504     names = node_to_item(node, struct names, node);
505 
506     /* Construct content into a linear buffer */
507     buf = NULL;
508     len = 0;
509     sequence = 0;
510     tag_len = strlen(names->name) + sizeof(char); /* tag + nul */
511     list_for_each_safe(content_node, m, &names->content) {
512       ssize_t add_len;
513 
514       content = node_to_item(content_node, struct content, node);
515       add_len = content->entry.len - tag_len - sizeof(prio);
516       if (add_len <= 0) {
517         list_remove(content_node);
518         free(content);
519         continue;
520       }
521 
522       if (!buf) {
523         buf = static_cast<char*>(malloc(sizeof(char)));
524         if (!buf) {
525           ret = -ENOMEM;
526           list_remove(content_node);
527           free(content);
528           continue;
529         }
530         *buf = '\0';
531       }
532 
533       /* Missing sequence numbers */
534       while (sequence < content->entry.nsec) {
535         /* plus space for enforced nul */
536         buf = static_cast<char*>(realloc_or_free(buf, len + sizeof(char) + sizeof(char)));
537         if (!buf) {
538           break;
539         }
540         buf[len] = '\f'; /* Mark missing content with a form feed */
541         buf[++len] = '\0';
542         sequence += ANDROID_LOG_PMSG_FILE_SEQUENCE;
543       }
544       if (!buf) {
545         ret = -ENOMEM;
546         list_remove(content_node);
547         free(content);
548         continue;
549       }
550       /* plus space for enforced nul */
551       buf = static_cast<char*>(realloc_or_free(buf, len + add_len + sizeof(char)));
552       if (!buf) {
553         ret = -ENOMEM;
554         list_remove(content_node);
555         free(content);
556         continue;
557       }
558       memcpy(buf + len, (char*)&content->entry + content->entry.hdr_size + tag_len + sizeof(prio),
559              add_len);
560       len += add_len;
561       buf[len] = '\0'; /* enforce trailing hidden nul */
562       sequence = content->entry.nsec + ANDROID_LOG_PMSG_FILE_SEQUENCE;
563 
564       list_remove(content_node);
565       free(content);
566     }
567     if (buf) {
568       if (len) {
569         /* Buffer contains enforced trailing nul just beyond length */
570         ssize_t r;
571         *strchr(names->name, ':') = '/'; /* Convert back to filename */
572         r = (*fn)(names->id, names->prio, names->name, buf, len, arg);
573         if ((ret >= 0) && (r > 0)) {
574           if (ret == SSIZE_MAX) {
575             ret = r;
576           } else {
577             ret += r;
578           }
579         } else if (r < ret) {
580           ret = r;
581         }
582       }
583       free(buf);
584     }
585     list_remove(node);
586     free(names);
587   }
588   return (ret == SSIZE_MAX) ? -ENOENT : ret;
589 }
590