diff options
author | Mark Salyzyn <salyzyn@google.com> | 2016-08-05 08:16:37 -0700 |
---|---|---|
committer | Mark Salyzyn <salyzyn@google.com> | 2016-08-08 09:58:28 -0700 |
commit | a146a779e2154c51c87b140e06c456d010af1197 (patch) | |
tree | 1c576d5639a315cd13c5e64b5dd9cfe1e8554faa /logd/LogKlog.cpp | |
parent | 9cd828b8589a64e79cbd6aa7dc324fcdba75dd73 (diff) | |
download | system_core-a146a779e2154c51c87b140e06c456d010af1197.tar.gz system_core-a146a779e2154c51c87b140e06c456d010af1197.tar.bz2 system_core-a146a779e2154c51c87b140e06c456d010af1197.zip |
logd: klogd crash
dmesg parser could wrap taglen limit resulting in out of bound
accesses. Can lead to crash or data corruption.
Fixed an issue with two-word tag parsing. Switched to case
insensitive tag content matching. Added a few extra limit
checks that could also wrap, simplified the parsing, then added
means to stop using hard coded constants.
Bug: 30688716
Bug: 30050636
Bug: 30614675
Bug: 25620123
Change-Id: Iae4f664f63ef7b842d82eaa1638b6d7a0d28fd18
Diffstat (limited to 'logd/LogKlog.cpp')
-rw-r--r-- | logd/LogKlog.cpp | 196 |
1 files changed, 97 insertions, 99 deletions
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp index ac2b12895..0495463dc 100644 --- a/logd/LogKlog.cpp +++ b/logd/LogKlog.cpp @@ -605,126 +605,124 @@ int LogKlog::log(const char *buf, size_t len) { const char *tag = ""; const char *etag = tag; size_t taglen = len - (p - buf); - if (!isspace(*p) && *p) { - const char *bt, *et, *cp; - - bt = p; - if ((taglen >= 6) && !fast<strncmp>(p, "[INFO]", 6)) { - // <PRI>[<TIME>] "[INFO]"<tag> ":" message - bt = p + 6; - taglen -= 6; - } - for(et = bt; taglen && *et && (*et != ':') && !isspace(*et); ++et, --taglen) { - // skip ':' within [ ... ] - if (*et == '[') { - while (taglen && *et && *et != ']') { - ++et; - --taglen; - } - } - } - for(cp = et; taglen && isspace(*cp); ++cp, --taglen); - size_t size; - + const char *bt = p; + + static const char infoBrace[] = "[INFO]"; + static const size_t infoBraceLen = strlen(infoBrace); + if ((taglen >= infoBraceLen) && !fast<strncmp>(p, infoBrace, infoBraceLen)) { + // <PRI>[<TIME>] "[INFO]"<tag> ":" message + bt = p + infoBraceLen; + taglen -= infoBraceLen; + } + + const char *et; + for (et = bt; taglen && *et && (*et != ':') && !isspace(*et); ++et, --taglen) { + // skip ':' within [ ... ] + if (*et == '[') { + while (taglen && *et && *et != ']') { + ++et; + --taglen; + } + if (!taglen) { + break; + } + } + } + const char *cp; + for (cp = et; taglen && isspace(*cp); ++cp, --taglen); + + // Validate tag + size_t size = et - bt; + if (taglen && size) { if (*cp == ':') { + // ToDo: handle case insensitive colon separated logging stutter: + // <tag> : <tag>: ... + // One Word tag = bt; etag = et; p = cp + 1; - } else if (taglen) { - size = et - bt; - if ((taglen > size) && // enough space for match plus trailing : - (*bt == *cp) && // ubber fast<strncmp> pair - fast<strncmp>(bt + 1, cp + 1, size - 1)) { - // <PRI>[<TIME>] <tag>_host '<tag>.<num>' : message - if (!fast<strncmp>(bt + size - 5, "_host", 5) - && !fast<strncmp>(bt + 1, cp + 1, size - 6)) { - const char *b = cp; - cp += size - 5; - taglen -= size - 5; - if (*cp == '.') { - while (--taglen && !isspace(*++cp) && (*cp != ':')); - const char *e; - for(e = cp; taglen && isspace(*cp); ++cp, --taglen); - if (*cp == ':') { - tag = b; - etag = e; - p = cp + 1; - } - } - } else { - while (--taglen && !isspace(*++cp) && (*cp != ':')); - const char *e; - for(e = cp; taglen && isspace(*cp); ++cp, --taglen); - // Two words - if (*cp == ':') { - tag = bt; - etag = e; - p = cp + 1; - } - } - } else if (isspace(cp[size])) { - cp += size; - taglen -= size; - while (--taglen && isspace(*++cp)); - // <PRI>[<TIME>] <tag> <tag> : message - if (*cp == ':') { - tag = bt; - etag = et; - p = cp + 1; - } - } else if (cp[size] == ':') { + } else if ((taglen > size) && (tolower(*bt) == tolower(*cp))) { + // clean up any tag stutter + if (!fast<strncasecmp>(bt + 1, cp + 1, size - 1)) { // no match // <PRI>[<TIME>] <tag> <tag> : message - tag = bt; - etag = et; - p = cp + size + 1; - } else if ((cp[size] == '.') || isdigit(cp[size])) { + // <PRI>[<TIME>] <tag> <tag>: message // <PRI>[<TIME>] <tag> '<tag>.<num>' : message // <PRI>[<TIME>] <tag> '<tag><num>' : message + // <PRI>[<TIME>] <tag> '<tag><stuff>' : message const char *b = cp; cp += size; taglen -= size; while (--taglen && !isspace(*++cp) && (*cp != ':')); - const char *e = cp; - while (taglen && isspace(*cp)) { - ++cp; - --taglen; - } - if (*cp == ':') { + const char *e; + for (e = cp; taglen && isspace(*cp); ++cp, --taglen); + if (taglen && (*cp == ':')) { tag = b; etag = e; p = cp + 1; } } else { - while (--taglen && !isspace(*++cp) && (*cp != ':')); - const char *e = cp; - while (taglen && isspace(*cp)) { - ++cp; - --taglen; - } - // Two words - if (*cp == ':') { - tag = bt; - etag = e; - p = cp + 1; + // what about <PRI>[<TIME>] <tag>_host '<tag><stuff>' : message + static const char host[] = "_host"; + static const size_t hostlen = strlen(host); + if ((size > hostlen) && + !fast<strncmp>(bt + size - hostlen, host, hostlen) && + !fast<strncmp>(bt + 1, cp + 1, size - hostlen - 1)) { + const char *b = cp; + cp += size - hostlen; + taglen -= size - hostlen; + if (*cp == '.') { + while (--taglen && !isspace(*++cp) && (*cp != ':')); + const char *e; + for (e = cp; taglen && isspace(*cp); ++cp, --taglen); + if (taglen && (*cp == ':')) { + tag = b; + etag = e; + p = cp + 1; + } + } + } else { + goto twoWord; } } - } /* else no tag */ - size = etag - tag; - if ((size <= 1) - // register names like x9 - || ((size == 2) && (isdigit(tag[0]) || isdigit(tag[1]))) - // register names like x18 but not driver names like en0 - || ((size == 3) && (isdigit(tag[1]) && isdigit(tag[2]))) - // blacklist - || ((size == 3) && !fast<strncmp>(tag, "CPU", 3)) - || ((size == 7) && !fast<strncasecmp>(tag, "WARNING", 7)) - || ((size == 5) && !fast<strncasecmp>(tag, "ERROR", 5)) - || ((size == 4) && !fast<strncasecmp>(tag, "INFO", 4))) { - p = start; - etag = tag = ""; + } else { + // <PRI>[<TIME>] <tag> <stuff>' : message +twoWord: while (--taglen && !isspace(*++cp) && (*cp != ':')); + const char *e; + for (e = cp; taglen && isspace(*cp); ++cp, --taglen); + // Two words + if (taglen && (*cp == ':')) { + tag = bt; + etag = e; + p = cp + 1; + } } + } // else no tag + + static const char cpu[] = "CPU"; + static const size_t cpuLen = strlen(cpu); + static const char warning[] = "WARNING"; + static const size_t warningLen = strlen(warning); + static const char error[] = "ERROR"; + static const size_t errorLen = strlen(error); + static const char info[] = "INFO"; + static const size_t infoLen = strlen(info); + + size = etag - tag; + if ((size <= 1) + // register names like x9 + || ((size == 2) && (isdigit(tag[0]) || isdigit(tag[1]))) + // register names like x18 but not driver names like en0 + || ((size == 3) && (isdigit(tag[1]) && isdigit(tag[2]))) + // blacklist + || ((size == cpuLen) && !fast<strncmp>(tag, cpu, cpuLen)) + || ((size == warningLen) && !fast<strncasecmp>(tag, warning, warningLen)) + || ((size == errorLen) && !fast<strncasecmp>(tag, error, errorLen)) + || ((size == infoLen) && !fast<strncasecmp>(tag, info, infoLen))) { + p = start; + etag = tag = ""; } + // Suppress additional stutter in tag: // eg: [143:healthd]healthd -> [143:healthd] taglen = etag - tag; |