Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fbbf9925 authored by Mark Salyzyn's avatar Mark Salyzyn
Browse files

logd: klogd crash

(cherry pick from commit a146a779)

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
parent 9a882a3e
Loading
Loading
Loading
Loading
+97 −99
Original line number Diff line number Diff line
@@ -630,15 +630,17 @@ 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;
    const char *bt = p;

        bt = p;
        if ((taglen >= 6) && !fast<strncmp>(p, "[INFO]", 6)) {
    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 + 6;
            taglen -= 6;
        bt = p + infoBraceLen;
        taglen -= infoBraceLen;
    }

    const char *et;
    for (et = bt; taglen && *et && (*et != ':') && !isspace(*et); ++et, --taglen) {
       // skip ':' within [ ... ]
       if (*et == '[') {
@@ -646,95 +648,91 @@ int LogKlog::log(const char *buf, size_t len) {
               ++et;
               --taglen;
           }
           if (!taglen) {
               break;
           }
       }
    }
    const char *cp;
    for (cp = et; taglen && isspace(*cp); ++cp, --taglen);
        size_t size;

    // 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)) {
        } 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
                // <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 - 5;
                    taglen -= size - 5;
                    if (*cp == '.') {
                cp += size;
                taglen -= size;
                while (--taglen && !isspace(*++cp) && (*cp != ':'));
                const char *e;
                for (e = cp; taglen && isspace(*cp); ++cp, --taglen);
                        if (*cp == ':') {
                if (taglen && (*cp == ':')) {
                    tag = b;
                    etag = e;
                    p = cp + 1;
                }
                    }
            } else {
                // 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);
                    // Two words
                    if (*cp == ':') {
                        tag = bt;
                        if (taglen && (*cp == ':')) {
                            tag = b;
                            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] == ':') {
                // <PRI>[<TIME>] <tag> <tag> : message
                tag = bt;
                etag = et;
                p = cp + size + 1;
            } else if ((cp[size] == '.') || isdigit(cp[size])) {
                // <PRI>[<TIME>] <tag> '<tag>.<num>' : message
                // <PRI>[<TIME>] <tag> '<tag><num>' : message
                const char *b = cp;
                cp += size;
                taglen -= size;
                while (--taglen && !isspace(*++cp) && (*cp != ':'));
                const char *e = cp;
                while (taglen && isspace(*cp)) {
                    ++cp;
                    --taglen;
                } else {
                    goto twoWord;
                }
                if (*cp == ':') {
                    tag = b;
                    etag = e;
                    p = cp + 1;
            }
        } else {
                while (--taglen && !isspace(*++cp) && (*cp != ':'));
                const char *e = cp;
                while (taglen && isspace(*cp)) {
                    ++cp;
                    --taglen;
                }
            // <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 (*cp == ':') {
            if (taglen && (*cp == ':')) {
                tag = bt;
                etag = e;
                p = cp + 1;
            }
        }
        } /* else no tag */
    } // 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
@@ -742,14 +740,14 @@ int LogKlog::log(const char *buf, size_t len) {
        // 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))) {
            || ((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;