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