• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *  * Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  *  * Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in
12  *    the documentation and/or other materials provided with the
13  *    distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <../private/libc_logging.h> // Relative path so we can #include this .cpp file for testing.
30 #include <../private/ScopedPthreadMutexLocker.h>
31 
32 #include <assert.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <pthread.h>
36 #include <stdarg.h>
37 #include <stddef.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <sys/mman.h>
41 #include <sys/uio.h>
42 #include <unistd.h>
43 
44 static pthread_mutex_t gAbortMsgLock = PTHREAD_MUTEX_INITIALIZER;
45 static pthread_mutex_t gLogInitializationLock = PTHREAD_MUTEX_INITIALIZER;
46 
47 __LIBC_HIDDEN__ abort_msg_t** __abort_message_ptr; // Accessible to __libc_init_common.
48 
49 // Must be kept in sync with frameworks/base/core/java/android/util/EventLog.java.
50 enum AndroidEventLogType {
51   EVENT_TYPE_INT      = 0,
52   EVENT_TYPE_LONG     = 1,
53   EVENT_TYPE_STRING   = 2,
54   EVENT_TYPE_LIST     = 3,
55 };
56 
57 struct BufferOutputStream {
58  public:
BufferOutputStreamBufferOutputStream59   BufferOutputStream(char* buffer, size_t size) : total(0) {
60     buffer_ = buffer;
61     end_ = buffer + size - 1;
62     pos_ = buffer_;
63     pos_[0] = '\0';
64   }
65 
~BufferOutputStreamBufferOutputStream66   ~BufferOutputStream() {
67   }
68 
SendBufferOutputStream69   void Send(const char* data, int len) {
70     if (len < 0) {
71       len = strlen(data);
72     }
73 
74     while (len > 0) {
75       int avail = end_ - pos_;
76       if (avail == 0) {
77         break;
78       }
79       if (avail > len) {
80         avail = len;
81       }
82       memcpy(pos_, data, avail);
83       pos_ += avail;
84       pos_[0] = '\0';
85       len -= avail;
86       total += avail;
87     }
88   }
89 
90   int total;
91 
92  private:
93   char* buffer_;
94   char* pos_;
95   char* end_;
96 };
97 
98 struct FdOutputStream {
99  public:
FdOutputStreamFdOutputStream100   FdOutputStream(int fd) : total(0), fd_(fd) {
101   }
102 
SendFdOutputStream103   void Send(const char* data, int len) {
104     if (len < 0) {
105       len = strlen(data);
106     }
107 
108     while (len > 0) {
109       int rc = TEMP_FAILURE_RETRY(write(fd_, data, len));
110       if (rc == -1) {
111         break;
112       }
113       data += rc;
114       len -= rc;
115       total += rc;
116     }
117   }
118 
119   int total;
120 
121  private:
122   int fd_;
123 };
124 
125 /*** formatted output implementation
126  ***/
127 
128 /* Parse a decimal string from 'format + *ppos',
129  * return the value, and writes the new position past
130  * the decimal string in '*ppos' on exit.
131  *
132  * NOTE: Does *not* handle a sign prefix.
133  */
parse_decimal(const char * format,int * ppos)134 static unsigned parse_decimal(const char *format, int *ppos) {
135     const char* p = format + *ppos;
136     unsigned result = 0;
137 
138     for (;;) {
139         int ch = *p;
140         unsigned d = (unsigned)(ch - '0');
141 
142         if (d >= 10U) {
143             break;
144         }
145 
146         result = result*10 + d;
147         p++;
148     }
149     *ppos = p - format;
150     return result;
151 }
152 
153 // Writes number 'value' in base 'base' into buffer 'buf' of size 'buf_size' bytes.
154 // Assumes that buf_size > 0.
format_unsigned(char * buf,size_t buf_size,uint64_t value,int base,bool caps)155 static void format_unsigned(char* buf, size_t buf_size, uint64_t value, int base, bool caps) {
156   char* p = buf;
157   char* end = buf + buf_size - 1;
158 
159   // Generate digit string in reverse order.
160   while (value) {
161     unsigned d = value % base;
162     value /= base;
163     if (p != end) {
164       char ch;
165       if (d < 10) {
166         ch = '0' + d;
167       } else {
168         ch = (caps ? 'A' : 'a') + (d - 10);
169       }
170       *p++ = ch;
171     }
172   }
173 
174   // Special case for 0.
175   if (p == buf) {
176     if (p != end) {
177       *p++ = '0';
178     }
179   }
180   *p = '\0';
181 
182   // Reverse digit string in-place.
183   size_t length = p - buf;
184   for (size_t i = 0, j = length - 1; i < j; ++i, --j) {
185     char ch = buf[i];
186     buf[i] = buf[j];
187     buf[j] = ch;
188   }
189 }
190 
format_integer(char * buf,size_t buf_size,uint64_t value,char conversion)191 static void format_integer(char* buf, size_t buf_size, uint64_t value, char conversion) {
192   // Decode the conversion specifier.
193   int is_signed = (conversion == 'd' || conversion == 'i' || conversion == 'o');
194   int base = 10;
195   if (conversion == 'x' || conversion == 'X') {
196     base = 16;
197   } else if (conversion == 'o') {
198     base = 8;
199   }
200   bool caps = (conversion == 'X');
201 
202   if (is_signed && static_cast<int64_t>(value) < 0) {
203     buf[0] = '-';
204     buf += 1;
205     buf_size -= 1;
206     value = static_cast<uint64_t>(-static_cast<int64_t>(value));
207   }
208   format_unsigned(buf, buf_size, value, base, caps);
209 }
210 
211 template <typename Out>
SendRepeat(Out & o,char ch,int count)212 static void SendRepeat(Out& o, char ch, int count) {
213   char pad[8];
214   memset(pad, ch, sizeof(pad));
215 
216   const int pad_size = static_cast<int>(sizeof(pad));
217   while (count > 0) {
218     int avail = count;
219     if (avail > pad_size) {
220       avail = pad_size;
221     }
222     o.Send(pad, avail);
223     count -= avail;
224   }
225 }
226 
227 /* Perform formatted output to an output target 'o' */
228 template <typename Out>
out_vformat(Out & o,const char * format,va_list args)229 static void out_vformat(Out& o, const char* format, va_list args) {
230     int nn = 0;
231 
232     for (;;) {
233         int mm;
234         int padZero = 0;
235         int padLeft = 0;
236         char sign = '\0';
237         int width = -1;
238         int prec  = -1;
239         size_t bytelen = sizeof(int);
240         int slen;
241         char buffer[32];  /* temporary buffer used to format numbers */
242 
243         char  c;
244 
245         /* first, find all characters that are not 0 or '%' */
246         /* then send them to the output directly */
247         mm = nn;
248         do {
249             c = format[mm];
250             if (c == '\0' || c == '%')
251                 break;
252             mm++;
253         } while (1);
254 
255         if (mm > nn) {
256             o.Send(format+nn, mm-nn);
257             nn = mm;
258         }
259 
260         /* is this it ? then exit */
261         if (c == '\0')
262             break;
263 
264         /* nope, we are at a '%' modifier */
265         nn++;  // skip it
266 
267         /* parse flags */
268         for (;;) {
269             c = format[nn++];
270             if (c == '\0') {  /* single trailing '%' ? */
271                 c = '%';
272                 o.Send(&c, 1);
273                 return;
274             }
275             else if (c == '0') {
276                 padZero = 1;
277                 continue;
278             }
279             else if (c == '-') {
280                 padLeft = 1;
281                 continue;
282             }
283             else if (c == ' ' || c == '+') {
284                 sign = c;
285                 continue;
286             }
287             break;
288         }
289 
290         /* parse field width */
291         if ((c >= '0' && c <= '9')) {
292             nn --;
293             width = (int)parse_decimal(format, &nn);
294             c = format[nn++];
295         }
296 
297         /* parse precision */
298         if (c == '.') {
299             prec = (int)parse_decimal(format, &nn);
300             c = format[nn++];
301         }
302 
303         /* length modifier */
304         switch (c) {
305         case 'h':
306             bytelen = sizeof(short);
307             if (format[nn] == 'h') {
308                 bytelen = sizeof(char);
309                 nn += 1;
310             }
311             c = format[nn++];
312             break;
313         case 'l':
314             bytelen = sizeof(long);
315             if (format[nn] == 'l') {
316                 bytelen = sizeof(long long);
317                 nn += 1;
318             }
319             c = format[nn++];
320             break;
321         case 'z':
322             bytelen = sizeof(size_t);
323             c = format[nn++];
324             break;
325         case 't':
326             bytelen = sizeof(ptrdiff_t);
327             c = format[nn++];
328             break;
329         default:
330             ;
331         }
332 
333         /* conversion specifier */
334         const char* str = buffer;
335         if (c == 's') {
336             /* string */
337             str = va_arg(args, const char*);
338             if (str == NULL) {
339                 str = "(null)";
340             }
341         } else if (c == 'c') {
342             /* character */
343             /* NOTE: char is promoted to int when passed through the stack */
344             buffer[0] = (char) va_arg(args, int);
345             buffer[1] = '\0';
346         } else if (c == 'p') {
347             uint64_t  value = (uintptr_t) va_arg(args, void*);
348             buffer[0] = '0';
349             buffer[1] = 'x';
350             format_integer(buffer + 2, sizeof(buffer) - 2, value, 'x');
351         } else if (c == 'd' || c == 'i' || c == 'o' || c == 'x' || c == 'X') {
352             /* integers - first read value from stack */
353             uint64_t value;
354             int is_signed = (c == 'd' || c == 'i' || c == 'o');
355 
356             /* NOTE: int8_t and int16_t are promoted to int when passed
357              *       through the stack
358              */
359             switch (bytelen) {
360             case 1: value = (uint8_t)  va_arg(args, int); break;
361             case 2: value = (uint16_t) va_arg(args, int); break;
362             case 4: value = va_arg(args, uint32_t); break;
363             case 8: value = va_arg(args, uint64_t); break;
364             default: return;  /* should not happen */
365             }
366 
367             /* sign extension, if needed */
368             if (is_signed) {
369                 int shift = 64 - 8*bytelen;
370                 value = (uint64_t)(((int64_t)(value << shift)) >> shift);
371             }
372 
373             /* format the number properly into our buffer */
374             format_integer(buffer, sizeof(buffer), value, c);
375         } else if (c == '%') {
376             buffer[0] = '%';
377             buffer[1] = '\0';
378         } else {
379             __assert(__FILE__, __LINE__, "conversion specifier unsupported");
380         }
381 
382         /* if we are here, 'str' points to the content that must be
383          * outputted. handle padding and alignment now */
384 
385         slen = strlen(str);
386 
387         if (sign != '\0' || prec != -1) {
388             __assert(__FILE__, __LINE__, "sign/precision unsupported");
389         }
390 
391         if (slen < width && !padLeft) {
392             char padChar = padZero ? '0' : ' ';
393             SendRepeat(o, padChar, width - slen);
394         }
395 
396         o.Send(str, slen);
397 
398         if (slen < width && padLeft) {
399             char padChar = padZero ? '0' : ' ';
400             SendRepeat(o, padChar, width - slen);
401         }
402     }
403 }
404 
__libc_format_buffer(char * buffer,size_t buffer_size,const char * format,...)405 int __libc_format_buffer(char* buffer, size_t buffer_size, const char* format, ...) {
406   BufferOutputStream os(buffer, buffer_size);
407   va_list args;
408   va_start(args, format);
409   out_vformat(os, format, args);
410   va_end(args);
411   return os.total;
412 }
413 
__libc_format_fd(int fd,const char * format,...)414 int __libc_format_fd(int fd, const char* format, ...) {
415   FdOutputStream os(fd);
416   va_list args;
417   va_start(args, format);
418   out_vformat(os, format, args);
419   va_end(args);
420   return os.total;
421 }
422 
__libc_write_log(int priority,const char * tag,const char * msg)423 static int __libc_write_log(int priority, const char* tag, const char* msg) {
424   static int main_log_fd = -1;
425   if (main_log_fd == -1) {
426     ScopedPthreadMutexLocker locker(&gLogInitializationLock);
427     main_log_fd = TEMP_FAILURE_RETRY(open("/dev/log/main", O_CLOEXEC | O_WRONLY));
428     if (main_log_fd == -1) {
429       return -1;
430     }
431   }
432 
433   iovec vec[3];
434   vec[0].iov_base = &priority;
435   vec[0].iov_len = 1;
436   vec[1].iov_base = const_cast<char*>(tag);
437   vec[1].iov_len = strlen(tag) + 1;
438   vec[2].iov_base = const_cast<char*>(msg);
439   vec[2].iov_len = strlen(msg) + 1;
440 
441   return TEMP_FAILURE_RETRY(writev(main_log_fd, vec, 3));
442 }
443 
__libc_format_log_va_list(int priority,const char * tag,const char * format,va_list args)444 int __libc_format_log_va_list(int priority, const char* tag, const char* format, va_list args) {
445   char buffer[1024];
446   BufferOutputStream os(buffer, sizeof(buffer));
447   out_vformat(os, format, args);
448   return __libc_write_log(priority, tag, buffer);
449 }
450 
__libc_format_log(int priority,const char * tag,const char * format,...)451 int __libc_format_log(int priority, const char* tag, const char* format, ...) {
452   va_list args;
453   va_start(args, format);
454   int result = __libc_format_log_va_list(priority, tag, format, args);
455   va_end(args);
456   return result;
457 }
458 
__libc_android_log_event(int32_t tag,char type,const void * payload,size_t len)459 static int __libc_android_log_event(int32_t tag, char type, const void* payload, size_t len) {
460   iovec vec[3];
461   vec[0].iov_base = &tag;
462   vec[0].iov_len = sizeof(tag);
463   vec[1].iov_base = &type;
464   vec[1].iov_len = sizeof(type);
465   vec[2].iov_base = const_cast<void*>(payload);
466   vec[2].iov_len = len;
467 
468   static int event_log_fd = -1;
469   if (event_log_fd == -1) {
470     ScopedPthreadMutexLocker locker(&gLogInitializationLock);
471     event_log_fd = TEMP_FAILURE_RETRY(open("/dev/log/events", O_CLOEXEC | O_WRONLY));
472   }
473   return TEMP_FAILURE_RETRY(writev(event_log_fd, vec, 3));
474 }
475 
__libc_android_log_event_int(int32_t tag,int value)476 void __libc_android_log_event_int(int32_t tag, int value) {
477   __libc_android_log_event(tag, EVENT_TYPE_INT, &value, sizeof(value));
478 }
479 
__libc_android_log_event_uid(int32_t tag)480 void __libc_android_log_event_uid(int32_t tag) {
481   __libc_android_log_event_int(tag, getuid());
482 }
483 
__fortify_chk_fail(const char * msg,uint32_t tag)484 void __fortify_chk_fail(const char *msg, uint32_t tag) {
485   if (tag != 0) {
486     __libc_android_log_event_uid(tag);
487   }
488   __libc_fatal("FORTIFY_SOURCE: %s. Calling abort().", msg);
489 }
490 
__libc_fatal(const char * format,...)491 void __libc_fatal(const char* format, ...) {
492   char msg[1024];
493   BufferOutputStream os(msg, sizeof(msg));
494   va_list args;
495   va_start(args, format);
496   out_vformat(os, format, args);
497   va_end(args);
498 
499   // TODO: log to stderr for the benefit of "adb shell" users.
500 
501   // Log to the log for the benefit of regular app developers (whose stdout and stderr are closed).
502   __libc_write_log(ANDROID_LOG_FATAL, "libc", msg);
503 
504   __libc_set_abort_message(msg);
505 
506   abort();
507 }
508 
__libc_set_abort_message(const char * msg)509 void __libc_set_abort_message(const char* msg) {
510   size_t size = sizeof(abort_msg_t) + strlen(msg) + 1;
511   void* map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
512   if (map == MAP_FAILED) {
513     return;
514   }
515 
516   if (__abort_message_ptr != NULL) {
517     ScopedPthreadMutexLocker locker(&gAbortMsgLock);
518     if (*__abort_message_ptr != NULL) {
519       munmap(*__abort_message_ptr, (*__abort_message_ptr)->size);
520     }
521     abort_msg_t* new_abort_message = reinterpret_cast<abort_msg_t*>(map);
522     new_abort_message->size = size;
523     strcpy(new_abort_message->msg, msg);
524     *__abort_message_ptr = new_abort_message;
525   }
526 }
527