diff options
author | Mark Salyzyn | 2016-08-11 10:02:06 -0500 |
---|---|---|
committer | Mark Salyzyn | 2017-03-27 15:32:57 -0500 |
commit | 0484b3b5757594a43c6b646824b44643d2a007de (patch) | |
tree | 813567ef4a12225062958bd807356789f0159d18 /logd/LogKlog.cpp | |
parent | 784c85178547897f10582bdc688f78fbe7f7e0ca (diff) | |
download | platform-system-core-0484b3b5757594a43c6b646824b44643d2a007de.tar.gz platform-system-core-0484b3b5757594a43c6b646824b44643d2a007de.tar.xz platform-system-core-0484b3b5757594a43c6b646824b44643d2a007de.zip |
logd: ASAN cleansing
A mixture of fixes and cleanup for LogKlog.cpp and friends.
- sscanf calls strlen. Check if the string is missing a nul
terminator, if it is, do not call sscanf.
- replace NULL with nullptr for stronger typechecking.
- pass by reference for simpler code.
- Use ssize_t where possible to check for negative values.
- fix FastCmp to add some validity checking since ASAN reports that
callers are not making sure pre-conditions are met.
- add fasticmp templates for completeness.
- if the buffer is too small to contain a meaningful time, do not
call down to log_time::strptime() because it does not limit its
accesses to the buffer boundaries, instead stopping at a
terminating nul or invalid match.
- move strnstr to LogUtils.h, drop size checking of needle and
clearly report the list of needles used with android::strnstr
- replace 'sizeof(static const char[]) - 1' with strlen.
Test: gTest liblog-unit-test, logd-unit-tests & logcat-unit-tests
Bug: 30792935
Bug: 36536248
Bug: 35468874
Bug: 34949125
Bug: 34606909
Bug: 36075298
Bug: 36608728
Change-Id: I161bf03ba029050e809b31cceef03f729d318866
Diffstat (limited to 'logd/LogKlog.cpp')
-rw-r--r-- | logd/LogKlog.cpp | 329 |
1 files changed, 154 insertions, 175 deletions
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp index 9dfa14ed3..d23254d37 100644 --- a/logd/LogKlog.cpp +++ b/logd/LogKlog.cpp | |||
@@ -37,46 +37,49 @@ | |||
37 | 37 | ||
38 | static const char priority_message[] = { KMSG_PRIORITY(LOG_INFO), '\0' }; | 38 | static const char priority_message[] = { KMSG_PRIORITY(LOG_INFO), '\0' }; |
39 | 39 | ||
40 | // List of the _only_ needles we supply here to android::strnstr | ||
41 | static const char suspendStr[] = "PM: suspend entry "; | ||
42 | static const char resumeStr[] = "PM: suspend exit "; | ||
43 | static const char suspendedStr[] = "Suspended for "; | ||
44 | static const char healthdStr[] = "healthd"; | ||
45 | static const char batteryStr[] = ": battery "; | ||
46 | static const char auditStr[] = " audit("; | ||
47 | static const char klogdStr[] = "logd.klogd: "; | ||
48 | |||
40 | // Parsing is hard | 49 | // Parsing is hard |
41 | 50 | ||
42 | // called if we see a '<', s is the next character, returns pointer after '>' | 51 | // called if we see a '<', s is the next character, returns pointer after '>' |
43 | static char* is_prio(char* s, size_t len) { | 52 | static char* is_prio(char* s, ssize_t len) { |
44 | if (!len || !isdigit(*s++)) { | 53 | if ((len <= 0) || !isdigit(*s++)) return nullptr; |
45 | return NULL; | ||
46 | } | ||
47 | --len; | 54 | --len; |
48 | static const size_t max_prio_len = (len < 4) ? len : 4; | 55 | static const size_t max_prio_len = (len < 4) ? len : 4; |
49 | size_t priolen = 0; | 56 | size_t priolen = 0; |
50 | char c; | 57 | char c; |
51 | while (((c = *s++)) && (++priolen <= max_prio_len)) { | 58 | while (((c = *s++)) && (++priolen <= max_prio_len)) { |
52 | if (!isdigit(c)) { | 59 | if (!isdigit(c)) return ((c == '>') && (*s == '[')) ? s : nullptr; |
53 | return ((c == '>') && (*s == '[')) ? s : NULL; | ||
54 | } | ||
55 | } | 60 | } |
56 | return NULL; | 61 | return nullptr; |
57 | } | 62 | } |
58 | 63 | ||
59 | // called if we see a '[', s is the next character, returns pointer after ']' | 64 | // called if we see a '[', s is the next character, returns pointer after ']' |
60 | static char* is_timestamp(char* s, size_t len) { | 65 | static char* is_timestamp(char* s, ssize_t len) { |
61 | while (len && (*s == ' ')) { | 66 | while ((len > 0) && (*s == ' ')) { |
62 | ++s; | 67 | ++s; |
63 | --len; | 68 | --len; |
64 | } | 69 | } |
65 | if (!len || !isdigit(*s++)) { | 70 | if ((len <= 0) || !isdigit(*s++)) return nullptr; |
66 | return NULL; | ||
67 | } | ||
68 | --len; | 71 | --len; |
69 | bool first_period = true; | 72 | bool first_period = true; |
70 | char c; | 73 | char c; |
71 | while (len && ((c = *s++))) { | 74 | while ((len > 0) && ((c = *s++))) { |
72 | --len; | 75 | --len; |
73 | if ((c == '.') && first_period) { | 76 | if ((c == '.') && first_period) { |
74 | first_period = false; | 77 | first_period = false; |
75 | } else if (!isdigit(c)) { | 78 | } else if (!isdigit(c)) { |
76 | return ((c == ']') && !first_period && (*s == ' ')) ? s : NULL; | 79 | return ((c == ']') && !first_period && (*s == ' ')) ? s : nullptr; |
77 | } | 80 | } |
78 | } | 81 | } |
79 | return NULL; | 82 | return nullptr; |
80 | } | 83 | } |
81 | 84 | ||
82 | // Like strtok_r with "\r\n" except that we look for log signatures (regex) | 85 | // Like strtok_r with "\r\n" except that we look for log signatures (regex) |
@@ -93,96 +96,82 @@ static char* is_timestamp(char* s, size_t len) { | |||
93 | // space is one more than <digit> of 9 | 96 | // space is one more than <digit> of 9 |
94 | #define OPEN_BRACKET_SPACE ((char)(OPEN_BRACKET_SIG | 10)) | 97 | #define OPEN_BRACKET_SPACE ((char)(OPEN_BRACKET_SIG | 10)) |
95 | 98 | ||
96 | char* log_strntok_r(char* s, size_t* len, char** last, size_t* sublen) { | 99 | char* android::log_strntok_r(char* s, ssize_t& len, char*& last, |
97 | *sublen = 0; | 100 | ssize_t& sublen) { |
98 | if (!*len) { | 101 | sublen = 0; |
99 | return NULL; | 102 | if (len <= 0) return nullptr; |
100 | } | ||
101 | if (!s) { | 103 | if (!s) { |
102 | if (!(s = *last)) { | 104 | if (!(s = last)) return nullptr; |
103 | return NULL; | ||
104 | } | ||
105 | // fixup for log signature split <, | 105 | // fixup for log signature split <, |
106 | // LESS_THAN_SIG + <digit> | 106 | // LESS_THAN_SIG + <digit> |
107 | if ((*s & SIGNATURE_MASK) == LESS_THAN_SIG) { | 107 | if ((*s & SIGNATURE_MASK) == LESS_THAN_SIG) { |
108 | *s = (*s & ~SIGNATURE_MASK) + '0'; | 108 | *s = (*s & ~SIGNATURE_MASK) + '0'; |
109 | *--s = '<'; | 109 | *--s = '<'; |
110 | ++*len; | 110 | ++len; |
111 | } | 111 | } |
112 | // fixup for log signature split [, | 112 | // fixup for log signature split [, |
113 | // OPEN_BRACKET_SPACE is space, OPEN_BRACKET_SIG + <digit> | 113 | // OPEN_BRACKET_SPACE is space, OPEN_BRACKET_SIG + <digit> |
114 | if ((*s & SIGNATURE_MASK) == OPEN_BRACKET_SIG) { | 114 | if ((*s & SIGNATURE_MASK) == OPEN_BRACKET_SIG) { |
115 | if (*s == OPEN_BRACKET_SPACE) { | 115 | *s = (*s == OPEN_BRACKET_SPACE) ? ' ' : (*s & ~SIGNATURE_MASK) + '0'; |
116 | *s = ' '; | ||
117 | } else { | ||
118 | *s = (*s & ~SIGNATURE_MASK) + '0'; | ||
119 | } | ||
120 | *--s = '['; | 116 | *--s = '['; |
121 | ++*len; | 117 | ++len; |
122 | } | 118 | } |
123 | } | 119 | } |
124 | 120 | ||
125 | while (*len && ((*s == '\r') || (*s == '\n'))) { | 121 | while ((len > 0) && ((*s == '\r') || (*s == '\n'))) { |
126 | ++s; | 122 | ++s; |
127 | --*len; | 123 | --len; |
128 | } | 124 | } |
129 | 125 | ||
130 | if (!*len) { | 126 | if (len <= 0) return last = nullptr; |
131 | *last = NULL; | ||
132 | return NULL; | ||
133 | } | ||
134 | char *peek, *tok = s; | 127 | char *peek, *tok = s; |
135 | 128 | ||
136 | for (;;) { | 129 | for (;;) { |
137 | if (*len == 0) { | 130 | if (len <= 0) { |
138 | *last = NULL; | 131 | last = nullptr; |
139 | return tok; | 132 | return tok; |
140 | } | 133 | } |
141 | char c = *s++; | 134 | char c = *s++; |
142 | --*len; | 135 | --len; |
143 | size_t adjust; | 136 | ssize_t adjust; |
144 | switch (c) { | 137 | switch (c) { |
145 | case '\r': | 138 | case '\r': |
146 | case '\n': | 139 | case '\n': |
147 | s[-1] = '\0'; | 140 | s[-1] = '\0'; |
148 | *last = s; | 141 | last = s; |
149 | return tok; | 142 | return tok; |
150 | 143 | ||
151 | case '<': | 144 | case '<': |
152 | peek = is_prio(s, *len); | 145 | peek = is_prio(s, len); |
153 | if (!peek) { | 146 | if (!peek) break; |
154 | break; | ||
155 | } | ||
156 | if (s != (tok + 1)) { // not first? | 147 | if (s != (tok + 1)) { // not first? |
157 | s[-1] = '\0'; | 148 | s[-1] = '\0'; |
158 | *s &= ~SIGNATURE_MASK; | 149 | *s &= ~SIGNATURE_MASK; |
159 | *s |= LESS_THAN_SIG; // signature for '<' | 150 | *s |= LESS_THAN_SIG; // signature for '<' |
160 | *last = s; | 151 | last = s; |
161 | return tok; | 152 | return tok; |
162 | } | 153 | } |
163 | adjust = peek - s; | 154 | adjust = peek - s; |
164 | if (adjust > *len) { | 155 | if (adjust > len) { |
165 | adjust = *len; | 156 | adjust = len; |
166 | } | 157 | } |
167 | *sublen += adjust; | 158 | sublen += adjust; |
168 | *len -= adjust; | 159 | len -= adjust; |
169 | s = peek; | 160 | s = peek; |
170 | if ((*s == '[') && ((peek = is_timestamp(s + 1, *len - 1)))) { | 161 | if ((*s == '[') && ((peek = is_timestamp(s + 1, len - 1)))) { |
171 | adjust = peek - s; | 162 | adjust = peek - s; |
172 | if (adjust > *len) { | 163 | if (adjust > len) { |
173 | adjust = *len; | 164 | adjust = len; |
174 | } | 165 | } |
175 | *sublen += adjust; | 166 | sublen += adjust; |
176 | *len -= adjust; | 167 | len -= adjust; |
177 | s = peek; | 168 | s = peek; |
178 | } | 169 | } |
179 | break; | 170 | break; |
180 | 171 | ||
181 | case '[': | 172 | case '[': |
182 | peek = is_timestamp(s, *len); | 173 | peek = is_timestamp(s, len); |
183 | if (!peek) { | 174 | if (!peek) break; |
184 | break; | ||
185 | } | ||
186 | if (s != (tok + 1)) { // not first? | 175 | if (s != (tok + 1)) { // not first? |
187 | s[-1] = '\0'; | 176 | s[-1] = '\0'; |
188 | if (*s == ' ') { | 177 | if (*s == ' ') { |
@@ -191,19 +180,19 @@ char* log_strntok_r(char* s, size_t* len, char** last, size_t* sublen) { | |||
191 | *s &= ~SIGNATURE_MASK; | 180 | *s &= ~SIGNATURE_MASK; |
192 | *s |= OPEN_BRACKET_SIG; // signature for '[' | 181 | *s |= OPEN_BRACKET_SIG; // signature for '[' |
193 | } | 182 | } |
194 | *last = s; | 183 | last = s; |
195 | return tok; | 184 | return tok; |
196 | } | 185 | } |
197 | adjust = peek - s; | 186 | adjust = peek - s; |
198 | if (adjust > *len) { | 187 | if (adjust > len) { |
199 | adjust = *len; | 188 | adjust = len; |
200 | } | 189 | } |
201 | *sublen += adjust; | 190 | sublen += adjust; |
202 | *len -= adjust; | 191 | len -= adjust; |
203 | s = peek; | 192 | s = peek; |
204 | break; | 193 | break; |
205 | } | 194 | } |
206 | ++*sublen; | 195 | ++sublen; |
207 | } | 196 | } |
208 | // NOTREACHED | 197 | // NOTREACHED |
209 | } | 198 | } |
@@ -222,9 +211,10 @@ LogKlog::LogKlog(LogBuffer* buf, LogReader* reader, int fdWrite, int fdRead, | |||
222 | initialized(false), | 211 | initialized(false), |
223 | enableLogging(true), | 212 | enableLogging(true), |
224 | auditd(auditd) { | 213 | auditd(auditd) { |
225 | static const char klogd_message[] = "%slogd.klogd: %" PRIu64 "\n"; | 214 | static const char klogd_message[] = "%s%s%" PRIu64 "\n"; |
226 | char buffer[sizeof(priority_message) + sizeof(klogd_message) + 20 - 4]; | 215 | char buffer[strlen(priority_message) + strlen(klogdStr) + |
227 | snprintf(buffer, sizeof(buffer), klogd_message, priority_message, | 216 | strlen(klogd_message) + 20]; |
217 | snprintf(buffer, sizeof(buffer), klogd_message, priority_message, klogdStr, | ||
228 | signature.nsec()); | 218 | signature.nsec()); |
229 | write(fdWrite, buffer, strlen(buffer)); | 219 | write(fdWrite, buffer, strlen(buffer)); |
230 | } | 220 | } |
@@ -237,15 +227,15 @@ bool LogKlog::onDataAvailable(SocketClient* cli) { | |||
237 | } | 227 | } |
238 | 228 | ||
239 | char buffer[LOGGER_ENTRY_MAX_PAYLOAD]; | 229 | char buffer[LOGGER_ENTRY_MAX_PAYLOAD]; |
240 | size_t len = 0; | 230 | ssize_t len = 0; |
241 | 231 | ||
242 | for (;;) { | 232 | for (;;) { |
243 | ssize_t retval = 0; | 233 | ssize_t retval = 0; |
244 | if ((sizeof(buffer) - 1 - len) > 0) { | 234 | if (len < (ssize_t)(sizeof(buffer) - 1)) { |
245 | retval = | 235 | retval = |
246 | read(cli->getSocket(), buffer + len, sizeof(buffer) - 1 - len); | 236 | read(cli->getSocket(), buffer + len, sizeof(buffer) - 1 - len); |
247 | } | 237 | } |
248 | if ((retval == 0) && (len == 0)) { | 238 | if ((retval == 0) && (len <= 0)) { |
249 | break; | 239 | break; |
250 | } | 240 | } |
251 | if (retval < 0) { | 241 | if (retval < 0) { |
@@ -255,15 +245,16 @@ bool LogKlog::onDataAvailable(SocketClient* cli) { | |||
255 | bool full = len == (sizeof(buffer) - 1); | 245 | bool full = len == (sizeof(buffer) - 1); |
256 | char* ep = buffer + len; | 246 | char* ep = buffer + len; |
257 | *ep = '\0'; | 247 | *ep = '\0'; |
258 | size_t sublen; | 248 | ssize_t sublen; |
259 | for (char *ptr = NULL, *tok = buffer; | 249 | for (char *ptr = nullptr, *tok = buffer; |
260 | ((tok = log_strntok_r(tok, &len, &ptr, &sublen))); tok = NULL) { | 250 | !!(tok = android::log_strntok_r(tok, len, ptr, sublen)); |
251 | tok = nullptr) { | ||
261 | if (((tok + sublen) >= ep) && (retval != 0) && full) { | 252 | if (((tok + sublen) >= ep) && (retval != 0) && full) { |
262 | memmove(buffer, tok, sublen); | 253 | if (sublen > 0) memmove(buffer, tok, sublen); |
263 | len = sublen; | 254 | len = sublen; |
264 | break; | 255 | break; |
265 | } | 256 | } |
266 | if (*tok) { | 257 | if ((sublen > 0) && *tok) { |
267 | log(tok, sublen); | 258 | log(tok, sublen); |
268 | } | 259 | } |
269 | } | 260 | } |
@@ -273,9 +264,12 @@ bool LogKlog::onDataAvailable(SocketClient* cli) { | |||
273 | } | 264 | } |
274 | 265 | ||
275 | void LogKlog::calculateCorrection(const log_time& monotonic, | 266 | void LogKlog::calculateCorrection(const log_time& monotonic, |
276 | const char* real_string, size_t len) { | 267 | const char* real_string, ssize_t len) { |
268 | static const char real_format[] = "%Y-%m-%d %H:%M:%S.%09q UTC"; | ||
269 | if (len < (ssize_t)(strlen(real_format) + 5)) return; | ||
270 | |||
277 | log_time real; | 271 | log_time real; |
278 | const char* ep = real.strptime(real_string, "%Y-%m-%d %H:%M:%S.%09q UTC"); | 272 | const char* ep = real.strptime(real_string, real_format); |
279 | if (!ep || (ep > &real_string[len]) || (real > log_time(CLOCK_REALTIME))) { | 273 | if (!ep || (ep > &real_string[len]) || (real > log_time(CLOCK_REALTIME))) { |
280 | return; | 274 | return; |
281 | } | 275 | } |
@@ -299,73 +293,50 @@ void LogKlog::calculateCorrection(const log_time& monotonic, | |||
299 | } | 293 | } |
300 | } | 294 | } |
301 | 295 | ||
302 | static const char suspendStr[] = "PM: suspend entry "; | 296 | void LogKlog::sniffTime(log_time& now, const char*& buf, ssize_t len, |
303 | static const char resumeStr[] = "PM: suspend exit "; | ||
304 | static const char suspendedStr[] = "Suspended for "; | ||
305 | |||
306 | const char* android::strnstr(const char* s, size_t len, const char* needle) { | ||
307 | char c; | ||
308 | |||
309 | if (!len) return NULL; | ||
310 | if ((c = *needle++) != 0) { | ||
311 | size_t needleLen = strlen(needle); | ||
312 | do { | ||
313 | do { | ||
314 | if (len <= needleLen) return NULL; | ||
315 | --len; | ||
316 | } while (*s++ != c); | ||
317 | } while (fastcmp<memcmp>(s, needle, needleLen)); | ||
318 | s--; | ||
319 | } | ||
320 | return s; | ||
321 | } | ||
322 | |||
323 | void LogKlog::sniffTime(log_time& now, const char** buf, size_t len, | ||
324 | bool reverse) { | 297 | bool reverse) { |
325 | const char* cp = now.strptime(*buf, "[ %s.%q]"); | 298 | if (len <= 0) return; |
326 | if (cp && (cp >= &(*buf)[len])) { | 299 | |
327 | cp = NULL; | 300 | const char* cp = nullptr; |
301 | if ((len > 10) && (*buf == '[')) { | ||
302 | cp = now.strptime(buf, "[ %s.%q]"); // can index beyond buffer bounds | ||
303 | if (cp && (cp > &buf[len - 1])) cp = nullptr; | ||
328 | } | 304 | } |
329 | if (cp) { | 305 | if (cp) { |
330 | static const char healthd[] = "healthd"; | 306 | len -= cp - buf; |
331 | static const char battery[] = ": battery "; | 307 | if ((len > 0) && isspace(*cp)) { |
332 | |||
333 | len -= cp - *buf; | ||
334 | if (len && isspace(*cp)) { | ||
335 | ++cp; | 308 | ++cp; |
336 | --len; | 309 | --len; |
337 | } | 310 | } |
338 | *buf = cp; | 311 | buf = cp; |
339 | 312 | ||
340 | if (isMonotonic()) { | 313 | if (isMonotonic()) return; |
341 | return; | ||
342 | } | ||
343 | 314 | ||
344 | const char* b; | 315 | const char* b; |
345 | if (((b = android::strnstr(cp, len, suspendStr))) && | 316 | if (((b = android::strnstr(cp, len, suspendStr))) && |
346 | ((size_t)((b += sizeof(suspendStr) - 1) - cp) < len)) { | 317 | (((b += strlen(suspendStr)) - cp) < len)) { |
347 | len -= b - cp; | 318 | len -= b - cp; |
348 | calculateCorrection(now, b, len); | 319 | calculateCorrection(now, b, len); |
349 | } else if (((b = android::strnstr(cp, len, resumeStr))) && | 320 | } else if (((b = android::strnstr(cp, len, resumeStr))) && |
350 | ((size_t)((b += sizeof(resumeStr) - 1) - cp) < len)) { | 321 | (((b += strlen(resumeStr)) - cp) < len)) { |
351 | len -= b - cp; | 322 | len -= b - cp; |
352 | calculateCorrection(now, b, len); | 323 | calculateCorrection(now, b, len); |
353 | } else if (((b = android::strnstr(cp, len, healthd))) && | 324 | } else if (((b = android::strnstr(cp, len, healthdStr))) && |
354 | ((size_t)((b += sizeof(healthd) - 1) - cp) < len) && | 325 | (((b += strlen(healthdStr)) - cp) < len) && |
355 | ((b = android::strnstr(b, len -= b - cp, battery))) && | 326 | ((b = android::strnstr(b, len -= b - cp, batteryStr))) && |
356 | ((size_t)((b += sizeof(battery) - 1) - cp) < len)) { | 327 | (((b += strlen(batteryStr)) - cp) < len)) { |
357 | // NB: healthd is roughly 150us late, so we use it instead to | 328 | // NB: healthd is roughly 150us late, so we use it instead to |
358 | // trigger a check for ntp-induced or hardware clock drift. | 329 | // trigger a check for ntp-induced or hardware clock drift. |
359 | log_time real(CLOCK_REALTIME); | 330 | log_time real(CLOCK_REALTIME); |
360 | log_time mono(CLOCK_MONOTONIC); | 331 | log_time mono(CLOCK_MONOTONIC); |
361 | correction = (real < mono) ? log_time::EPOCH : (real - mono); | 332 | correction = (real < mono) ? log_time::EPOCH : (real - mono); |
362 | } else if (((b = android::strnstr(cp, len, suspendedStr))) && | 333 | } else if (((b = android::strnstr(cp, len, suspendedStr))) && |
363 | ((size_t)((b += sizeof(suspendStr) - 1) - cp) < len)) { | 334 | (((b += strlen(suspendStr)) - cp) < len)) { |
364 | len -= b - cp; | 335 | len -= b - cp; |
365 | log_time real; | 336 | log_time real; |
366 | char* endp; | 337 | char* endp; |
367 | real.tv_sec = strtol(b, &endp, 10); | 338 | real.tv_sec = strtol(b, &endp, 10); |
368 | if ((*endp == '.') && ((size_t)(endp - b) < len)) { | 339 | if ((*endp == '.') && ((endp - b) < len)) { |
369 | unsigned long multiplier = NS_PER_SEC; | 340 | unsigned long multiplier = NS_PER_SEC; |
370 | real.tv_nsec = 0; | 341 | real.tv_nsec = 0; |
371 | len -= endp - b; | 342 | len -= endp - b; |
@@ -394,8 +365,15 @@ void LogKlog::sniffTime(log_time& now, const char** buf, size_t len, | |||
394 | } | 365 | } |
395 | } | 366 | } |
396 | 367 | ||
397 | pid_t LogKlog::sniffPid(const char** buf, size_t len) { | 368 | pid_t LogKlog::sniffPid(const char*& buf, ssize_t len) { |
398 | const char* cp = *buf; | 369 | if (len <= 0) return 0; |
370 | |||
371 | const char* cp = buf; | ||
372 | // sscanf does a strlen, let's check if the string is not nul terminated. | ||
373 | // pseudo out-of-bounds access since we always have an extra char on buffer. | ||
374 | if (((ssize_t)strnlen(cp, len) == len) && cp[len]) { | ||
375 | return 0; | ||
376 | } | ||
399 | // HTC kernels with modified printk "c0 1648 " | 377 | // HTC kernels with modified printk "c0 1648 " |
400 | if ((len > 9) && (cp[0] == 'c') && isdigit(cp[1]) && | 378 | if ((len > 9) && (cp[0] == 'c') && isdigit(cp[1]) && |
401 | (isdigit(cp[2]) || (cp[2] == ' ')) && (cp[3] == ' ')) { | 379 | (isdigit(cp[2]) || (cp[2] == ' ')) && (cp[3] == ' ')) { |
@@ -412,7 +390,7 @@ pid_t LogKlog::sniffPid(const char** buf, size_t len) { | |||
412 | int pid = 0; | 390 | int pid = 0; |
413 | char dummy; | 391 | char dummy; |
414 | if (sscanf(cp + 4, "%d%c", &pid, &dummy) == 2) { | 392 | if (sscanf(cp + 4, "%d%c", &pid, &dummy) == 2) { |
415 | *buf = cp + 10; // skip-it-all | 393 | buf = cp + 10; // skip-it-all |
416 | return pid; | 394 | return pid; |
417 | } | 395 | } |
418 | } | 396 | } |
@@ -434,28 +412,28 @@ pid_t LogKlog::sniffPid(const char** buf, size_t len) { | |||
434 | } | 412 | } |
435 | 413 | ||
436 | // kernel log prefix, convert to a kernel log priority number | 414 | // kernel log prefix, convert to a kernel log priority number |
437 | static int parseKernelPrio(const char** buf, size_t len) { | 415 | static int parseKernelPrio(const char*& buf, ssize_t len) { |
438 | int pri = LOG_USER | LOG_INFO; | 416 | int pri = LOG_USER | LOG_INFO; |
439 | const char* cp = *buf; | 417 | const char* cp = buf; |
440 | if (len && (*cp == '<')) { | 418 | if ((len > 0) && (*cp == '<')) { |
441 | pri = 0; | 419 | pri = 0; |
442 | while (--len && isdigit(*++cp)) { | 420 | while (--len && isdigit(*++cp)) { |
443 | pri = (pri * 10) + *cp - '0'; | 421 | pri = (pri * 10) + *cp - '0'; |
444 | } | 422 | } |
445 | if (len && (*cp == '>')) { | 423 | if ((len > 0) && (*cp == '>')) { |
446 | ++cp; | 424 | ++cp; |
447 | } else { | 425 | } else { |
448 | cp = *buf; | 426 | cp = buf; |
449 | pri = LOG_USER | LOG_INFO; | 427 | pri = LOG_USER | LOG_INFO; |
450 | } | 428 | } |
451 | *buf = cp; | 429 | buf = cp; |
452 | } | 430 | } |
453 | return pri; | 431 | return pri; |
454 | } | 432 | } |
455 | 433 | ||
456 | // Passed the entire SYSLOG_ACTION_READ_ALL buffer and interpret a | 434 | // Passed the entire SYSLOG_ACTION_READ_ALL buffer and interpret a |
457 | // compensated start time. | 435 | // compensated start time. |
458 | void LogKlog::synchronize(const char* buf, size_t len) { | 436 | void LogKlog::synchronize(const char* buf, ssize_t len) { |
459 | const char* cp = android::strnstr(buf, len, suspendStr); | 437 | const char* cp = android::strnstr(buf, len, suspendStr); |
460 | if (!cp) { | 438 | if (!cp) { |
461 | cp = android::strnstr(buf, len, resumeStr); | 439 | cp = android::strnstr(buf, len, resumeStr); |
@@ -471,10 +449,10 @@ void LogKlog::synchronize(const char* buf, size_t len) { | |||
471 | if (*cp == '\n') { | 449 | if (*cp == '\n') { |
472 | ++cp; | 450 | ++cp; |
473 | } | 451 | } |
474 | parseKernelPrio(&cp, len - (cp - buf)); | 452 | parseKernelPrio(cp, len - (cp - buf)); |
475 | 453 | ||
476 | log_time now; | 454 | log_time now; |
477 | sniffTime(now, &cp, len - (cp - buf), true); | 455 | sniffTime(now, cp, len - (cp - buf), true); |
478 | 456 | ||
479 | const char* suspended = android::strnstr(buf, len, suspendedStr); | 457 | const char* suspended = android::strnstr(buf, len, suspendedStr); |
480 | if (!suspended || (suspended > cp)) { | 458 | if (!suspended || (suspended > cp)) { |
@@ -488,9 +466,9 @@ void LogKlog::synchronize(const char* buf, size_t len) { | |||
488 | if (*cp == '\n') { | 466 | if (*cp == '\n') { |
489 | ++cp; | 467 | ++cp; |
490 | } | 468 | } |
491 | parseKernelPrio(&cp, len - (cp - buf)); | 469 | parseKernelPrio(cp, len - (cp - buf)); |
492 | 470 | ||
493 | sniffTime(now, &cp, len - (cp - buf), true); | 471 | sniffTime(now, cp, len - (cp - buf), true); |
494 | } | 472 | } |
495 | 473 | ||
496 | // Convert kernel log priority number into an Android Logger priority number | 474 | // Convert kernel log priority number into an Android Logger priority number |
@@ -523,9 +501,9 @@ static int convertKernelPrioToAndroidPrio(int pri) { | |||
523 | return ANDROID_LOG_INFO; | 501 | return ANDROID_LOG_INFO; |
524 | } | 502 | } |
525 | 503 | ||
526 | static const char* strnrchr(const char* s, size_t len, char c) { | 504 | static const char* strnrchr(const char* s, ssize_t len, char c) { |
527 | const char* save = NULL; | 505 | const char* save = nullptr; |
528 | for (; len; ++s, len--) { | 506 | for (; len > 0; ++s, len--) { |
529 | if (*s == c) { | 507 | if (*s == c) { |
530 | save = s; | 508 | save = s; |
531 | } | 509 | } |
@@ -566,22 +544,21 @@ static const char* strnrchr(const char* s, size_t len, char c) { | |||
566 | // logd.klogd: | 544 | // logd.klogd: |
567 | // return -1 if message logd.klogd: <signature> | 545 | // return -1 if message logd.klogd: <signature> |
568 | // | 546 | // |
569 | int LogKlog::log(const char* buf, size_t len) { | 547 | int LogKlog::log(const char* buf, ssize_t len) { |
570 | if (auditd && android::strnstr(buf, len, " audit(")) { | 548 | if (auditd && android::strnstr(buf, len, auditStr)) { |
571 | return 0; | 549 | return 0; |
572 | } | 550 | } |
573 | 551 | ||
574 | const char* p = buf; | 552 | const char* p = buf; |
575 | int pri = parseKernelPrio(&p, len); | 553 | int pri = parseKernelPrio(p, len); |
576 | 554 | ||
577 | log_time now; | 555 | log_time now; |
578 | sniffTime(now, &p, len - (p - buf), false); | 556 | sniffTime(now, p, len - (p - buf), false); |
579 | 557 | ||
580 | // sniff for start marker | 558 | // sniff for start marker |
581 | const char klogd_message[] = "logd.klogd: "; | 559 | const char* start = android::strnstr(p, len - (p - buf), klogdStr); |
582 | const char* start = android::strnstr(p, len - (p - buf), klogd_message); | ||
583 | if (start) { | 560 | if (start) { |
584 | uint64_t sig = strtoll(start + sizeof(klogd_message) - 1, NULL, 10); | 561 | uint64_t sig = strtoll(start + strlen(klogdStr), nullptr, 10); |
585 | if (sig == signature.nsec()) { | 562 | if (sig == signature.nsec()) { |
586 | if (initialized) { | 563 | if (initialized) { |
587 | enableLogging = true; | 564 | enableLogging = true; |
@@ -598,7 +575,7 @@ int LogKlog::log(const char* buf, size_t len) { | |||
598 | } | 575 | } |
599 | 576 | ||
600 | // Parse pid, tid and uid | 577 | // Parse pid, tid and uid |
601 | const pid_t pid = sniffPid(&p, len - (p - buf)); | 578 | const pid_t pid = sniffPid(p, len - (p - buf)); |
602 | const pid_t tid = pid; | 579 | const pid_t tid = pid; |
603 | uid_t uid = AID_ROOT; | 580 | uid_t uid = AID_ROOT; |
604 | if (pid) { | 581 | if (pid) { |
@@ -620,11 +597,11 @@ int LogKlog::log(const char* buf, size_t len) { | |||
620 | start = p; | 597 | start = p; |
621 | const char* tag = ""; | 598 | const char* tag = ""; |
622 | const char* etag = tag; | 599 | const char* etag = tag; |
623 | size_t taglen = len - (p - buf); | 600 | ssize_t taglen = len - (p - buf); |
624 | const char* bt = p; | 601 | const char* bt = p; |
625 | 602 | ||
626 | static const char infoBrace[] = "[INFO]"; | 603 | static const char infoBrace[] = "[INFO]"; |
627 | static const size_t infoBraceLen = strlen(infoBrace); | 604 | static const ssize_t infoBraceLen = strlen(infoBrace); |
628 | if ((taglen >= infoBraceLen) && | 605 | if ((taglen >= infoBraceLen) && |
629 | !fastcmp<strncmp>(p, infoBrace, infoBraceLen)) { | 606 | !fastcmp<strncmp>(p, infoBrace, infoBraceLen)) { |
630 | // <PRI>[<TIME>] "[INFO]"<tag> ":" message | 607 | // <PRI>[<TIME>] "[INFO]"<tag> ":" message |
@@ -633,26 +610,26 @@ int LogKlog::log(const char* buf, size_t len) { | |||
633 | } | 610 | } |
634 | 611 | ||
635 | const char* et; | 612 | const char* et; |
636 | for (et = bt; taglen && *et && (*et != ':') && !isspace(*et); | 613 | for (et = bt; (taglen > 0) && *et && (*et != ':') && !isspace(*et); |
637 | ++et, --taglen) { | 614 | ++et, --taglen) { |
638 | // skip ':' within [ ... ] | 615 | // skip ':' within [ ... ] |
639 | if (*et == '[') { | 616 | if (*et == '[') { |
640 | while (taglen && *et && *et != ']') { | 617 | while ((taglen > 0) && *et && *et != ']') { |
641 | ++et; | 618 | ++et; |
642 | --taglen; | 619 | --taglen; |
643 | } | 620 | } |
644 | if (!taglen) { | 621 | if (taglen <= 0) { |
645 | break; | 622 | break; |
646 | } | 623 | } |
647 | } | 624 | } |
648 | } | 625 | } |
649 | const char* cp; | 626 | const char* cp; |
650 | for (cp = et; taglen && isspace(*cp); ++cp, --taglen) { | 627 | for (cp = et; (taglen > 0) && isspace(*cp); ++cp, --taglen) { |
651 | } | 628 | } |
652 | 629 | ||
653 | // Validate tag | 630 | // Validate tag |
654 | size_t size = et - bt; | 631 | ssize_t size = et - bt; |
655 | if (taglen && size) { | 632 | if ((taglen > 0) && (size > 0)) { |
656 | if (*cp == ':') { | 633 | if (*cp == ':') { |
657 | // ToDo: handle case insensitive colon separated logging stutter: | 634 | // ToDo: handle case insensitive colon separated logging stutter: |
658 | // <tag> : <tag>: ... | 635 | // <tag> : <tag>: ... |
@@ -672,12 +649,12 @@ int LogKlog::log(const char* buf, size_t len) { | |||
672 | const char* b = cp; | 649 | const char* b = cp; |
673 | cp += size; | 650 | cp += size; |
674 | taglen -= size; | 651 | taglen -= size; |
675 | while (--taglen && !isspace(*++cp) && (*cp != ':')) { | 652 | while ((--taglen > 0) && !isspace(*++cp) && (*cp != ':')) { |
676 | } | 653 | } |
677 | const char* e; | 654 | const char* e; |
678 | for (e = cp; taglen && isspace(*cp); ++cp, --taglen) { | 655 | for (e = cp; (taglen > 0) && isspace(*cp); ++cp, --taglen) { |
679 | } | 656 | } |
680 | if (taglen && (*cp == ':')) { | 657 | if ((taglen > 0) && (*cp == ':')) { |
681 | tag = b; | 658 | tag = b; |
682 | etag = e; | 659 | etag = e; |
683 | p = cp + 1; | 660 | p = cp + 1; |
@@ -685,7 +662,7 @@ int LogKlog::log(const char* buf, size_t len) { | |||
685 | } else { | 662 | } else { |
686 | // what about <PRI>[<TIME>] <tag>_host '<tag><stuff>' : message | 663 | // what about <PRI>[<TIME>] <tag>_host '<tag><stuff>' : message |
687 | static const char host[] = "_host"; | 664 | static const char host[] = "_host"; |
688 | static const size_t hostlen = strlen(host); | 665 | static const ssize_t hostlen = strlen(host); |
689 | if ((size > hostlen) && | 666 | if ((size > hostlen) && |
690 | !fastcmp<strncmp>(bt + size - hostlen, host, hostlen) && | 667 | !fastcmp<strncmp>(bt + size - hostlen, host, hostlen) && |
691 | !fastcmp<strncmp>(bt + 1, cp + 1, size - hostlen - 1)) { | 668 | !fastcmp<strncmp>(bt + 1, cp + 1, size - hostlen - 1)) { |
@@ -693,12 +670,14 @@ int LogKlog::log(const char* buf, size_t len) { | |||
693 | cp += size - hostlen; | 670 | cp += size - hostlen; |
694 | taglen -= size - hostlen; | 671 | taglen -= size - hostlen; |
695 | if (*cp == '.') { | 672 | if (*cp == '.') { |
696 | while (--taglen && !isspace(*++cp) && (*cp != ':')) { | 673 | while ((--taglen > 0) && !isspace(*++cp) && |
674 | (*cp != ':')) { | ||
697 | } | 675 | } |
698 | const char* e; | 676 | const char* e; |
699 | for (e = cp; taglen && isspace(*cp); ++cp, --taglen) { | 677 | for (e = cp; (taglen > 0) && isspace(*cp); |
678 | ++cp, --taglen) { | ||
700 | } | 679 | } |
701 | if (taglen && (*cp == ':')) { | 680 | if ((taglen > 0) && (*cp == ':')) { |
702 | tag = b; | 681 | tag = b; |
703 | etag = e; | 682 | etag = e; |
704 | p = cp + 1; | 683 | p = cp + 1; |
@@ -711,13 +690,13 @@ int LogKlog::log(const char* buf, size_t len) { | |||
711 | } else { | 690 | } else { |
712 | // <PRI>[<TIME>] <tag> <stuff>' : message | 691 | // <PRI>[<TIME>] <tag> <stuff>' : message |
713 | twoWord: | 692 | twoWord: |
714 | while (--taglen && !isspace(*++cp) && (*cp != ':')) { | 693 | while ((--taglen > 0) && !isspace(*++cp) && (*cp != ':')) { |
715 | } | 694 | } |
716 | const char* e; | 695 | const char* e; |
717 | for (e = cp; taglen && isspace(*cp); ++cp, --taglen) { | 696 | for (e = cp; (taglen > 0) && isspace(*cp); ++cp, --taglen) { |
718 | } | 697 | } |
719 | // Two words | 698 | // Two words |
720 | if (taglen && (*cp == ':')) { | 699 | if ((taglen > 0) && (*cp == ':')) { |
721 | tag = bt; | 700 | tag = bt; |
722 | etag = e; | 701 | etag = e; |
723 | p = cp + 1; | 702 | p = cp + 1; |
@@ -726,13 +705,13 @@ int LogKlog::log(const char* buf, size_t len) { | |||
726 | } // else no tag | 705 | } // else no tag |
727 | 706 | ||
728 | static const char cpu[] = "CPU"; | 707 | static const char cpu[] = "CPU"; |
729 | static const size_t cpuLen = strlen(cpu); | 708 | static const ssize_t cpuLen = strlen(cpu); |
730 | static const char warning[] = "WARNING"; | 709 | static const char warning[] = "WARNING"; |
731 | static const size_t warningLen = strlen(warning); | 710 | static const ssize_t warningLen = strlen(warning); |
732 | static const char error[] = "ERROR"; | 711 | static const char error[] = "ERROR"; |
733 | static const size_t errorLen = strlen(error); | 712 | static const ssize_t errorLen = strlen(error); |
734 | static const char info[] = "INFO"; | 713 | static const char info[] = "INFO"; |
735 | static const size_t infoLen = strlen(info); | 714 | static const ssize_t infoLen = strlen(info); |
736 | 715 | ||
737 | size = etag - tag; | 716 | size = etag - tag; |
738 | if ((size <= 1) || | 717 | if ((size <= 1) || |
@@ -756,13 +735,13 @@ int LogKlog::log(const char* buf, size_t len) { | |||
756 | // Mediatek-special printk induced stutter | 735 | // Mediatek-special printk induced stutter |
757 | const char* mp = strnrchr(tag, taglen, ']'); | 736 | const char* mp = strnrchr(tag, taglen, ']'); |
758 | if (mp && (++mp < etag)) { | 737 | if (mp && (++mp < etag)) { |
759 | size_t s = etag - mp; | 738 | ssize_t s = etag - mp; |
760 | if (((s + s) < taglen) && !fastcmp<memcmp>(mp, mp - 1 - s, s)) { | 739 | if (((s + s) < taglen) && !fastcmp<memcmp>(mp, mp - 1 - s, s)) { |
761 | taglen = mp - tag; | 740 | taglen = mp - tag; |
762 | } | 741 | } |
763 | } | 742 | } |
764 | // Deal with sloppy and simplistic harmless p = cp + 1 etc above. | 743 | // Deal with sloppy and simplistic harmless p = cp + 1 etc above. |
765 | if (len < (size_t)(p - buf)) { | 744 | if (len < (p - buf)) { |
766 | p = &buf[len]; | 745 | p = &buf[len]; |
767 | } | 746 | } |
768 | // skip leading space | 747 | // skip leading space |
@@ -770,12 +749,12 @@ int LogKlog::log(const char* buf, size_t len) { | |||
770 | ++p; | 749 | ++p; |
771 | } | 750 | } |
772 | // truncate trailing space or nuls | 751 | // truncate trailing space or nuls |
773 | size_t b = len - (p - buf); | 752 | ssize_t b = len - (p - buf); |
774 | while (b && (isspace(p[b - 1]) || !p[b - 1])) { | 753 | while ((b > 0) && (isspace(p[b - 1]) || !p[b - 1])) { |
775 | --b; | 754 | --b; |
776 | } | 755 | } |
777 | // trick ... allow tag with empty content to be logged. log() drops empty | 756 | // trick ... allow tag with empty content to be logged. log() drops empty |
778 | if (!b && taglen) { | 757 | if ((b <= 0) && (taglen > 0)) { |
779 | p = " "; | 758 | p = " "; |
780 | b = 1; | 759 | b = 1; |
781 | } | 760 | } |
@@ -787,9 +766,9 @@ int LogKlog::log(const char* buf, size_t len) { | |||
787 | taglen = LOGGER_ENTRY_MAX_PAYLOAD; | 766 | taglen = LOGGER_ENTRY_MAX_PAYLOAD; |
788 | } | 767 | } |
789 | // calculate buffer copy requirements | 768 | // calculate buffer copy requirements |
790 | size_t n = 1 + taglen + 1 + b + 1; | 769 | ssize_t n = 1 + taglen + 1 + b + 1; |
791 | // paranoid sanity check, first two just can not happen ... | 770 | // paranoid sanity check, first two just can not happen ... |
792 | if ((taglen > n) || (b > n) || (n > USHRT_MAX)) { | 771 | if ((taglen > n) || (b > n) || (n > (ssize_t)USHRT_MAX) || (n <= 0)) { |
793 | return -EINVAL; | 772 | return -EINVAL; |
794 | } | 773 | } |
795 | 774 | ||