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 <assert.h>
18 #include <ctype.h>
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <inttypes.h>
22 #include <limits.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/mman.h>
27 
28 #include <experimental/string_view>
29 #include <functional>
30 #include <string>
31 #include <unordered_map>
32 
33 #include <log/event_tag_map.h>
34 #include <log/log_properties.h>
35 #include <private/android_logger.h>
36 #include <utils/FastStrcmp.h>
37 #include <utils/RWLock.h>
38 
39 #include "log_portability.h"
40 #include "logd_reader.h"
41 
42 #define OUT_TAG "EventTagMap"
43 
44 class MapString {
45  private:
46   const std::string* alloc;                  // HAS-AN
47   const std::experimental::string_view str;  // HAS-A
48 
49  public:
operator const std::experimental::string_view() const50   operator const std::experimental::string_view() const {
51     return str;
52   }
53 
data() const54   const char* data() const {
55     return str.data();
56   }
length() const57   size_t length() const {
58     return str.length();
59   }
60 
operator ==(const MapString & rval) const61   bool operator==(const MapString& rval) const {
62     if (length() != rval.length()) return false;
63     if (length() == 0) return true;
64     return fastcmp<strncmp>(data(), rval.data(), length()) == 0;
65   }
operator !=(const MapString & rval) const66   bool operator!=(const MapString& rval) const {
67     return !(*this == rval);
68   }
69 
MapString(const char * str,size_t len)70   MapString(const char* str, size_t len) : alloc(NULL), str(str, len) {
71   }
MapString(const std::string & str)72   explicit MapString(const std::string& str)
73       : alloc(new std::string(str)), str(alloc->data(), alloc->length()) {
74   }
MapString(MapString && rval)75   MapString(MapString&& rval)
76       : alloc(rval.alloc), str(rval.data(), rval.length()) {
77     rval.alloc = NULL;
78   }
MapString(const MapString & rval)79   explicit MapString(const MapString& rval)
80       : alloc(rval.alloc ? new std::string(*rval.alloc) : NULL),
81         str(alloc ? alloc->data() : rval.data(), rval.length()) {
82   }
83 
~MapString()84   ~MapString() {
85     if (alloc) delete alloc;
86   }
87 };
88 
89 // Hash for MapString
90 template <>
91 struct std::hash<MapString>
92     : public std::unary_function<const MapString&, size_t> {
operator ()std::hash93   size_t operator()(const MapString& __t) const noexcept {
94     if (!__t.length()) return 0;
95     return std::hash<std::experimental::string_view>()(
96         std::experimental::string_view(__t));
97   }
98 };
99 
100 typedef std::pair<MapString, MapString> TagFmt;
101 
102 template <>
103 struct std::hash<TagFmt> : public std::unary_function<const TagFmt&, size_t> {
operator ()std::hash104   size_t operator()(const TagFmt& __t) const noexcept {
105     // Tag is typically unique.  Will cost us an extra 100ns for the
106     // unordered_map lookup if we instead did a hash that combined
107     // both of tag and fmt members, e.g.:
108     //
109     // return std::hash<MapString>()(__t.first) ^
110     //        std::hash<MapString>()(__t.second);
111     return std::hash<MapString>()(__t.first);
112   }
113 };
114 
115 // Map
116 struct EventTagMap {
117 #define NUM_MAPS 2
118   // memory-mapped source file; we get strings from here
119   void* mapAddr[NUM_MAPS];
120   size_t mapLen[NUM_MAPS];
121 
122  private:
123   std::unordered_map<uint32_t, TagFmt> Idx2TagFmt;
124   std::unordered_map<TagFmt, uint32_t> TagFmt2Idx;
125   std::unordered_map<MapString, uint32_t> Tag2Idx;
126   // protect unordered sets
127   android::RWLock rwlock;
128 
129  public:
EventTagMapEventTagMap130   EventTagMap() {
131     memset(mapAddr, 0, sizeof(mapAddr));
132     memset(mapLen, 0, sizeof(mapLen));
133   }
134 
~EventTagMapEventTagMap135   ~EventTagMap() {
136     Idx2TagFmt.clear();
137     TagFmt2Idx.clear();
138     Tag2Idx.clear();
139     for (size_t which = 0; which < NUM_MAPS; ++which) {
140       if (mapAddr[which]) {
141         munmap(mapAddr[which], mapLen[which]);
142         mapAddr[which] = 0;
143       }
144     }
145   }
146 
147   bool emplaceUnique(uint32_t tag, const TagFmt& tagfmt, bool verbose = false);
148   const TagFmt* find(uint32_t tag) const;
149   int find(TagFmt&& tagfmt) const;
150   int find(MapString&& tag) const;
151 };
152 
emplaceUnique(uint32_t tag,const TagFmt & tagfmt,bool verbose)153 bool EventTagMap::emplaceUnique(uint32_t tag, const TagFmt& tagfmt,
154                                 bool verbose) {
155   bool ret = true;
156   static const char errorFormat[] =
157       OUT_TAG ": duplicate tag entries %" PRIu32 ":%.*s:%.*s and %" PRIu32
158               ":%.*s:%.*s)\n";
159   android::RWLock::AutoWLock writeLock(rwlock);
160   {
161     std::unordered_map<uint32_t, TagFmt>::const_iterator it;
162     it = Idx2TagFmt.find(tag);
163     if (it != Idx2TagFmt.end()) {
164       if (verbose) {
165         fprintf(stderr, errorFormat, it->first, (int)it->second.first.length(),
166                 it->second.first.data(), (int)it->second.second.length(),
167                 it->second.second.data(), tag, (int)tagfmt.first.length(),
168                 tagfmt.first.data(), (int)tagfmt.second.length(),
169                 tagfmt.second.data());
170       }
171       ret = false;
172     } else {
173       Idx2TagFmt.emplace(std::make_pair(tag, tagfmt));
174     }
175   }
176 
177   {
178     std::unordered_map<TagFmt, uint32_t>::const_iterator it;
179     it = TagFmt2Idx.find(tagfmt);
180     if (it != TagFmt2Idx.end()) {
181       if (verbose) {
182         fprintf(stderr, errorFormat, it->second, (int)it->first.first.length(),
183                 it->first.first.data(), (int)it->first.second.length(),
184                 it->first.second.data(), tag, (int)tagfmt.first.length(),
185                 tagfmt.first.data(), (int)tagfmt.second.length(),
186                 tagfmt.second.data());
187       }
188       ret = false;
189     } else {
190       TagFmt2Idx.emplace(std::make_pair(tagfmt, tag));
191     }
192   }
193 
194   {
195     std::unordered_map<MapString, uint32_t>::const_iterator it;
196     it = Tag2Idx.find(tagfmt.first);
197     if (!tagfmt.second.length() && (it != Tag2Idx.end())) {
198       Tag2Idx.erase(it);
199       it = Tag2Idx.end();
200     }
201     if (it == Tag2Idx.end()) {
202       Tag2Idx.emplace(std::make_pair(tagfmt.first, tag));
203     }
204   }
205 
206   return ret;
207 }
208 
find(uint32_t tag) const209 const TagFmt* EventTagMap::find(uint32_t tag) const {
210   std::unordered_map<uint32_t, TagFmt>::const_iterator it;
211   android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
212   it = Idx2TagFmt.find(tag);
213   if (it == Idx2TagFmt.end()) return NULL;
214   return &(it->second);
215 }
216 
find(TagFmt && tagfmt) const217 int EventTagMap::find(TagFmt&& tagfmt) const {
218   std::unordered_map<TagFmt, uint32_t>::const_iterator it;
219   android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
220   it = TagFmt2Idx.find(std::move(tagfmt));
221   if (it == TagFmt2Idx.end()) return -1;
222   return it->second;
223 }
224 
find(MapString && tag) const225 int EventTagMap::find(MapString&& tag) const {
226   std::unordered_map<MapString, uint32_t>::const_iterator it;
227   android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
228   it = Tag2Idx.find(std::move(tag));
229   if (it == Tag2Idx.end()) return -1;
230   return it->second;
231 }
232 
233 // Scan one tag line.
234 //
235 // "*pData" should be pointing to the first digit in the tag number.  On
236 // successful return, it will be pointing to the last character in the
237 // tag line (i.e. the character before the start of the next line).
238 //
239 // lineNum = 0 removes verbose comments and requires us to cache the
240 // content rather than make direct raw references since the content
241 // will disappear after the call. A non-zero lineNum means we own the
242 // data and it will outlive the call.
243 //
244 // Returns 0 on success, nonzero on failure.
scanTagLine(EventTagMap * map,char ** pData,int lineNum)245 static int scanTagLine(EventTagMap* map, char** pData, int lineNum) {
246   char* cp;
247   unsigned long val = strtoul(*pData, &cp, 10);
248   if (cp == *pData) {
249     if (lineNum) {
250       fprintf(stderr, OUT_TAG ": malformed tag number on line %d\n", lineNum);
251     }
252     errno = EINVAL;
253     return -1;
254   }
255 
256   uint32_t tagIndex = val;
257   if (tagIndex != val) {
258     if (lineNum) {
259       fprintf(stderr, OUT_TAG ": tag number too large on line %d\n", lineNum);
260     }
261     errno = ERANGE;
262     return -1;
263   }
264 
265   while ((*++cp != '\n') && isspace(*cp)) {
266   }
267 
268   if (*cp == '\n') {
269     if (lineNum) {
270       fprintf(stderr, OUT_TAG ": missing tag string on line %d\n", lineNum);
271     }
272     errno = EINVAL;
273     return -1;
274   }
275 
276   const char* tag = cp;
277   // Determine whether "c" is a valid tag char.
278   while (isalnum(*++cp) || (*cp == '_')) {
279   }
280   size_t tagLen = cp - tag;
281 
282   if (!isspace(*cp)) {
283     if (lineNum) {
284       fprintf(stderr, OUT_TAG ": invalid tag chars on line %d\n", lineNum);
285     }
286     errno = EINVAL;
287     return -1;
288   }
289 
290   while (isspace(*cp) && (*cp != '\n')) ++cp;
291   const char* fmt = NULL;
292   size_t fmtLen = 0;
293   if (*cp != '#') {
294     fmt = cp;
295     while ((*cp != '\n') && (*cp != '#')) ++cp;
296     while ((cp > fmt) && isspace(*(cp - 1))) --cp;
297     fmtLen = cp - fmt;
298   }
299 
300   // KISS Only report identicals if they are global
301   // Ideally we want to check if there are identicals
302   // recorded for the same uid, but recording that
303   // unused detail in our database is too burdensome.
304   bool verbose = true;
305   while ((*cp != '#') && (*cp != '\n')) ++cp;
306   if (*cp == '#') {
307     do {
308       ++cp;
309     } while (isspace(*cp) && (*cp != '\n'));
310     verbose = !!fastcmp<strncmp>(cp, "uid=", strlen("uid="));
311   }
312 
313   while (*cp != '\n') ++cp;
314 #ifdef DEBUG
315   fprintf(stderr, "%d: %p: %.*s\n", lineNum, tag, (int)(cp - *pData), *pData);
316 #endif
317   *pData = cp;
318 
319   if (lineNum) {
320     if (map->emplaceUnique(tagIndex,
321                            TagFmt(std::make_pair(MapString(tag, tagLen),
322                                                  MapString(fmt, fmtLen))),
323                            verbose)) {
324       return 0;
325     }
326   } else {
327     // cache
328     if (map->emplaceUnique(
329             tagIndex,
330             TagFmt(std::make_pair(MapString(std::string(tag, tagLen)),
331                                   MapString(std::string(fmt, fmtLen)))))) {
332       return 0;
333     }
334   }
335   errno = EMLINK;
336   return -1;
337 }
338 
339 static const char* eventTagFiles[NUM_MAPS] = {
340   EVENT_TAG_MAP_FILE, "/dev/event-log-tags",
341 };
342 
343 // Parse the tags out of the file.
parseMapLines(EventTagMap * map,size_t which)344 static int parseMapLines(EventTagMap* map, size_t which) {
345   char* cp = static_cast<char*>(map->mapAddr[which]);
346   size_t len = map->mapLen[which];
347   char* endp = cp + len;
348 
349   // insist on EOL at EOF; simplifies parsing and null-termination
350   if (!len || (*(endp - 1) != '\n')) {
351 #ifdef DEBUG
352     fprintf(stderr, OUT_TAG ": map file %zu[%zu] missing EOL on last line\n",
353             which, len);
354 #endif
355     if (which) {  // do not propagate errors for other files
356       return 0;
357     }
358     errno = EINVAL;
359     return -1;
360   }
361 
362   bool lineStart = true;
363   int lineNum = 1;
364   while (cp < endp) {
365     if (*cp == '\n') {
366       lineStart = true;
367       lineNum++;
368     } else if (lineStart) {
369       if (*cp == '#') {
370         // comment; just scan to end
371         lineStart = false;
372       } else if (isdigit(*cp)) {
373         // looks like a tag; scan it out
374         if (scanTagLine(map, &cp, lineNum) != 0) {
375           if (!which || (errno != EMLINK)) {
376             return -1;
377           }
378         }
379         lineNum++;  // we eat the '\n'
380                     // leave lineStart==true
381       } else if (isspace(*cp)) {
382         // looks like leading whitespace; keep scanning
383       } else {
384         fprintf(stderr,
385                 OUT_TAG
386                 ": unexpected chars (0x%02x) in tag number on line %d\n",
387                 *cp, lineNum);
388         errno = EINVAL;
389         return -1;
390       }
391     } else {
392       // this is a blank or comment line
393     }
394     cp++;
395   }
396 
397   return 0;
398 }
399 
400 // Open the map file and allocate a structure to manage it.
401 //
402 // We create a private mapping because we want to terminate the log tag
403 // strings with '\0'.
android_openEventTagMap(const char * fileName)404 LIBLOG_ABI_PUBLIC EventTagMap* android_openEventTagMap(const char* fileName) {
405   EventTagMap* newTagMap;
406   off_t end[NUM_MAPS];
407   int save_errno, fd[NUM_MAPS];
408   size_t which;
409 
410   memset(fd, -1, sizeof(fd));
411   memset(end, 0, sizeof(end));
412 
413   for (which = 0; which < NUM_MAPS; ++which) {
414     const char* tagfile = fileName ? fileName : eventTagFiles[which];
415 
416     fd[which] = open(tagfile, O_RDONLY | O_CLOEXEC);
417     if (fd[which] < 0) {
418       if (!which) {
419         save_errno = errno;
420         fprintf(stderr, OUT_TAG ": unable to open map '%s': %s\n", tagfile,
421                 strerror(save_errno));
422         goto fail_errno;
423       }
424       continue;
425     }
426     end[which] = lseek(fd[which], 0L, SEEK_END);
427     save_errno = errno;
428     (void)lseek(fd[which], 0L, SEEK_SET);
429     if (!which && (end[0] < 0)) {
430       fprintf(stderr, OUT_TAG ": unable to seek map '%s' %s\n", tagfile,
431               strerror(save_errno));
432       goto fail_close;
433     }
434     if (fileName) break;  // Only allow one as specified
435   }
436 
437   newTagMap = new EventTagMap;
438   if (newTagMap == NULL) {
439     save_errno = errno;
440     goto fail_close;
441   }
442 
443   for (which = 0; which < NUM_MAPS; ++which) {
444     if (fd[which] >= 0) {
445       newTagMap->mapAddr[which] =
446           mmap(NULL, end[which], which ? PROT_READ : PROT_READ | PROT_WRITE,
447                which ? MAP_SHARED : MAP_PRIVATE, fd[which], 0);
448       save_errno = errno;
449       close(fd[which]);
450       fd[which] = -1;
451       if ((newTagMap->mapAddr[which] != MAP_FAILED) &&
452           (newTagMap->mapAddr[which] != NULL)) {
453         newTagMap->mapLen[which] = end[which];
454       } else if (!which) {
455         const char* tagfile = fileName ? fileName : eventTagFiles[which];
456 
457         fprintf(stderr, OUT_TAG ": mmap(%s) failed: %s\n", tagfile,
458                 strerror(save_errno));
459         goto fail_unmap;
460       }
461     }
462   }
463 
464   for (which = 0; which < NUM_MAPS; ++which) {
465     if (parseMapLines(newTagMap, which) != 0) {
466       delete newTagMap;
467       return NULL;
468     }
469   }
470 
471   return newTagMap;
472 
473 fail_unmap:
474   save_errno = EINVAL;
475   delete newTagMap;
476 fail_close:
477   for (which = 0; which < NUM_MAPS; ++which) close(fd[which]);
478 fail_errno:
479   errno = save_errno;
480   return NULL;
481 }
482 
483 // Close the map.
android_closeEventTagMap(EventTagMap * map)484 LIBLOG_ABI_PUBLIC void android_closeEventTagMap(EventTagMap* map) {
485   if (map) delete map;
486 }
487 
488 // Cache miss, go to logd to acquire a public reference.
489 // Because we lack access to a SHARED PUBLIC /dev/event-log-tags file map?
__getEventTag(EventTagMap * map,unsigned int tag)490 static const TagFmt* __getEventTag(EventTagMap* map, unsigned int tag) {
491   // call event tag service to arrange for a new tag
492   char* buf = NULL;
493   // Can not use android::base::StringPrintf, asprintf + free instead.
494   static const char command_template[] = "getEventTag id=%u";
495   int ret = asprintf(&buf, command_template, tag);
496   if (ret > 0) {
497     // Add some buffer margin for an estimate of the full return content.
498     char* cp;
499     size_t size =
500         ret - strlen(command_template) +
501         strlen("65535\n4294967295\t?\t\t\t?\t# uid=32767\n\n\f?success?");
502     if (size > (size_t)ret) {
503       cp = static_cast<char*>(realloc(buf, size));
504       if (cp) {
505         buf = cp;
506       } else {
507         size = ret;
508       }
509     } else {
510       size = ret;
511     }
512     // Ask event log tag service for an existing entry
513     if (__send_log_msg(buf, size) >= 0) {
514       buf[size - 1] = '\0';
515       unsigned long val = strtoul(buf, &cp, 10);        // return size
516       if ((buf != cp) && (val > 0) && (*cp == '\n')) {  // truncation OK
517         ++cp;
518         if (!scanTagLine(map, &cp, 0)) {
519           free(buf);
520           return map->find(tag);
521         }
522       }
523     }
524     free(buf);
525   }
526   return NULL;
527 }
528 
529 // Look up an entry in the map.
android_lookupEventTag_len(const EventTagMap * map,size_t * len,unsigned int tag)530 LIBLOG_ABI_PUBLIC const char* android_lookupEventTag_len(const EventTagMap* map,
531                                                          size_t* len,
532                                                          unsigned int tag) {
533   if (len) *len = 0;
534   const TagFmt* str = map->find(tag);
535   if (!str) {
536     str = __getEventTag(const_cast<EventTagMap*>(map), tag);
537   }
538   if (!str) return NULL;
539   if (len) *len = str->first.length();
540   return str->first.data();
541 }
542 
543 // Look up an entry in the map.
android_lookupEventFormat_len(const EventTagMap * map,size_t * len,unsigned int tag)544 LIBLOG_ABI_PUBLIC const char* android_lookupEventFormat_len(
545     const EventTagMap* map, size_t* len, unsigned int tag) {
546   if (len) *len = 0;
547   const TagFmt* str = map->find(tag);
548   if (!str) {
549     str = __getEventTag(const_cast<EventTagMap*>(map), tag);
550   }
551   if (!str) return NULL;
552   if (len) *len = str->second.length();
553   return str->second.data();
554 }
555 
556 // This function is deprecated and replaced with android_lookupEventTag_len
557 // since it will cause the map to change from Shared and backed by a file,
558 // to Private Dirty and backed up by swap, albeit highly compressible. By
559 // deprecating this function everywhere, we save 100s of MB of memory space.
android_lookupEventTag(const EventTagMap * map,unsigned int tag)560 LIBLOG_ABI_PUBLIC const char* android_lookupEventTag(const EventTagMap* map,
561                                                      unsigned int tag) {
562   size_t len;
563   const char* tagStr = android_lookupEventTag_len(map, &len, tag);
564 
565   if (!tagStr) return tagStr;
566   char* cp = const_cast<char*>(tagStr);
567   cp += len;
568   if (*cp) *cp = '\0';  // Trigger copy on write :-( and why deprecated.
569   return tagStr;
570 }
571 
572 // Look up tagname, generate one if necessary, and return a tag
android_lookupEventTagNum(EventTagMap * map,const char * tagname,const char * format,int prio)573 LIBLOG_ABI_PUBLIC int android_lookupEventTagNum(EventTagMap* map,
574                                                 const char* tagname,
575                                                 const char* format, int prio) {
576   size_t len = strlen(tagname);
577   if (!len) {
578     errno = EINVAL;
579     return -1;
580   }
581 
582   if ((prio != ANDROID_LOG_UNKNOWN) && (prio < ANDROID_LOG_SILENT) &&
583       !__android_log_is_loggable_len(prio, tagname, len,
584                                      __android_log_is_debuggable()
585                                          ? ANDROID_LOG_VERBOSE
586                                          : ANDROID_LOG_DEBUG)) {
587     errno = EPERM;
588     return -1;
589   }
590 
591   if (!format) format = "";
592   ssize_t fmtLen = strlen(format);
593   int ret = map->find(TagFmt(
594       std::make_pair(MapString(tagname, len), MapString(format, fmtLen))));
595   if (ret != -1) return ret;
596 
597   // call event tag service to arrange for a new tag
598   char* buf = NULL;
599   // Can not use android::base::StringPrintf, asprintf + free instead.
600   static const char command_template[] = "getEventTag name=%s format=\"%s\"";
601   ret = asprintf(&buf, command_template, tagname, format);
602   if (ret > 0) {
603     // Add some buffer margin for an estimate of the full return content.
604     char* cp;
605     size_t size =
606         ret - strlen(command_template) +
607         strlen("65535\n4294967295\t?\t\t\t?\t# uid=32767\n\n\f?success?");
608     if (size > (size_t)ret) {
609       cp = static_cast<char*>(realloc(buf, size));
610       if (cp) {
611         buf = cp;
612       } else {
613         size = ret;
614       }
615     } else {
616       size = ret;
617     }
618     // Ask event log tag service for an allocation
619     if (__send_log_msg(buf, size) >= 0) {
620       buf[size - 1] = '\0';
621       unsigned long val = strtoul(buf, &cp, 10);        // return size
622       if ((buf != cp) && (val > 0) && (*cp == '\n')) {  // truncation OK
623         val = strtoul(cp + 1, &cp, 10);                 // allocated tag number
624         if ((val > 0) && (val < UINT32_MAX) && (*cp == '\t')) {
625           free(buf);
626           ret = val;
627           // cache
628           map->emplaceUnique(ret, TagFmt(std::make_pair(
629                                       MapString(std::string(tagname, len)),
630                                       MapString(std::string(format, fmtLen)))));
631           return ret;
632         }
633       }
634     }
635     free(buf);
636   }
637 
638   // Hail Mary
639   ret = map->find(MapString(tagname, len));
640   if (ret == -1) errno = ESRCH;
641   return ret;
642 }
643