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