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) noexcept
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 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 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 const char* android_lookupEventTag_len(const EventTagMap* map, size_t* len, unsigned int tag) {
539 if (len) *len = 0;
540 const TagFmt* str = map->find(tag);
541 if (!str) {
542 str = __getEventTag(const_cast<EventTagMap*>(map), tag);
543 }
544 if (!str) return NULL;
545 if (len) *len = str->first.length();
546 return str->first.data();
547 }
548
549 // Look up an entry in the map.
android_lookupEventFormat_len(const EventTagMap * map,size_t * len,unsigned int tag)550 const char* android_lookupEventFormat_len(const EventTagMap* map, size_t* len, unsigned int tag) {
551 if (len) *len = 0;
552 const TagFmt* str = map->find(tag);
553 if (!str) {
554 str = __getEventTag(const_cast<EventTagMap*>(map), tag);
555 }
556 if (!str) return NULL;
557 if (len) *len = str->second.length();
558 return str->second.data();
559 }
560
561 // This function is deprecated and replaced with android_lookupEventTag_len
562 // since it will cause the map to change from Shared and backed by a file,
563 // to Private Dirty and backed up by swap, albeit highly compressible. By
564 // deprecating this function everywhere, we save 100s of MB of memory space.
android_lookupEventTag(const EventTagMap * map,unsigned int tag)565 const char* android_lookupEventTag(const EventTagMap* map, unsigned int tag) {
566 size_t len;
567 const char* tagStr = android_lookupEventTag_len(map, &len, tag);
568
569 if (!tagStr) return tagStr;
570 char* cp = const_cast<char*>(tagStr);
571 cp += len;
572 if (*cp) *cp = '\0'; // Trigger copy on write :-( and why deprecated.
573 return tagStr;
574 }
575
576 // Look up tagname, generate one if necessary, and return a tag
android_lookupEventTagNum(EventTagMap * map,const char * tagname,const char * format,int prio)577 int android_lookupEventTagNum(EventTagMap* map, const char* tagname, const char* format, int prio) {
578 const char* ep = endOfTag(tagname);
579 size_t len = ep - tagname;
580 if (!len || *ep) {
581 errno = EINVAL;
582 return -1;
583 }
584
585 if ((prio != ANDROID_LOG_UNKNOWN) && (prio < ANDROID_LOG_SILENT) &&
586 !__android_log_is_loggable_len(prio, tagname, len,
587 __android_log_is_debuggable()
588 ? ANDROID_LOG_VERBOSE
589 : ANDROID_LOG_DEBUG)) {
590 errno = EPERM;
591 return -1;
592 }
593
594 if (!format) format = "";
595 ssize_t fmtLen = strlen(format);
596 int ret = map->find(TagFmt(
597 std::make_pair(MapString(tagname, len), MapString(format, fmtLen))));
598 if (ret != -1) return ret;
599
600 // call event tag service to arrange for a new tag
601 char* buf = NULL;
602 // Can not use android::base::StringPrintf, asprintf + free instead.
603 static const char command_template[] = "getEventTag name=%s format=\"%s\"";
604 ret = asprintf(&buf, command_template, tagname, format);
605 if (ret > 0) {
606 // Add some buffer margin for an estimate of the full return content.
607 char* cp;
608 size_t size =
609 ret - strlen(command_template) +
610 strlen("65535\n4294967295\t?\t\t\t?\t# uid=32767\n\n\f?success?");
611 if (size > (size_t)ret) {
612 cp = static_cast<char*>(realloc(buf, size));
613 if (cp) {
614 buf = cp;
615 } else {
616 size = ret;
617 }
618 } else {
619 size = ret;
620 }
621 // Ask event log tag service for an allocation
622 if (__send_log_msg(buf, size) >= 0) {
623 buf[size - 1] = '\0';
624 unsigned long val = strtoul(buf, &cp, 10); // return size
625 if ((buf != cp) && (val > 0) && (*cp == '\n')) { // truncation OK
626 val = strtoul(cp + 1, &cp, 10); // allocated tag number
627 if ((val > 0) && (val < UINT32_MAX) && (*cp == '\t')) {
628 free(buf);
629 ret = val;
630 // cache
631 map->emplaceUnique(ret, TagFmt(std::make_pair(
632 MapString(std::string(tagname, len)),
633 MapString(std::string(format, fmtLen)))));
634 return ret;
635 }
636 }
637 }
638 free(buf);
639 }
640
641 // Hail Mary
642 ret = map->find(MapString(tagname, len));
643 if (ret == -1) errno = ESRCH;
644 return ret;
645 }
646