1 /*
2 ** Copyright 2014, 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 <log/log_properties.h>
18 
19 #include <ctype.h>
20 #include <pthread.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 
25 #include <algorithm>
26 
27 #include <android-base/macros.h>
28 
29 #include <private/android_logger.h>
30 
31 #include "logger_write.h"
32 
33 #ifdef __ANDROID__
34 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
35 #include <sys/_system_properties.h>
36 
37 static pthread_mutex_t lock_loggable = PTHREAD_MUTEX_INITIALIZER;
38 
trylock()39 static bool trylock() {
40   /*
41    * If we trigger a signal handler in the middle of locked activity and the
42    * signal handler logs a message, we could get into a deadlock state.
43    */
44   /*
45    *  Any contention, and we can turn around and use the non-cached method
46    * in less time than the system call associated with a mutex to deal with
47    * the contention.
48    */
49   return pthread_mutex_trylock(&lock_loggable) == 0;
50 }
51 
unlock()52 static void unlock() {
53   pthread_mutex_unlock(&lock_loggable);
54 }
55 
56 struct cache {
57   const prop_info* pinfo;
58   uint32_t serial;
59 };
60 
61 struct cache_char {
62   struct cache cache;
63   unsigned char c;
64 };
65 
check_cache(struct cache * cache)66 static int check_cache(struct cache* cache) {
67   return cache->pinfo && __system_property_serial(cache->pinfo) != cache->serial;
68 }
69 
70 #define BOOLEAN_TRUE 0xFF
71 #define BOOLEAN_FALSE 0xFE
72 
refresh_cache(struct cache_char * cache,const char * key)73 static void refresh_cache(struct cache_char* cache, const char* key) {
74   char buf[PROP_VALUE_MAX];
75 
76   if (!cache->cache.pinfo) {
77     cache->cache.pinfo = __system_property_find(key);
78     if (!cache->cache.pinfo) {
79       return;
80     }
81   }
82   cache->cache.serial = __system_property_serial(cache->cache.pinfo);
83   __system_property_read(cache->cache.pinfo, 0, buf);
84   switch (buf[0]) {
85     case 't':
86     case 'T':
87       cache->c = strcasecmp(buf + 1, "rue") ? buf[0] : BOOLEAN_TRUE;
88       break;
89     case 'f':
90     case 'F':
91       cache->c = strcasecmp(buf + 1, "alse") ? buf[0] : BOOLEAN_FALSE;
92       break;
93     default:
94       cache->c = buf[0];
95   }
96 }
97 
__android_log_level(const char * tag,size_t tag_len)98 static int __android_log_level(const char* tag, size_t tag_len) {
99   if (tag == nullptr || tag_len == 0) {
100     auto& tag_string = GetDefaultTag();
101     tag = tag_string.c_str();
102     tag_len = tag_string.size();
103   }
104 
105   /*
106    * Single layer cache of four properties. Priorities are:
107    *    log.tag.<tag>
108    *    persist.log.tag.<tag>
109    *    log.tag
110    *    persist.log.tag
111    * Where the missing tag matches all tags and becomes the
112    * system global default. We do not support ro.log.tag* .
113    */
114   static std::string* last_tag = new std::string;
115   static uint32_t global_serial;
116   uint32_t current_global_serial;
117   static cache_char tag_cache[2];
118   static cache_char global_cache[2];
119 
120   static const char* log_namespace = "persist.log.tag.";
121   char key[strlen(log_namespace) + tag_len + 1];
122   strcpy(key, log_namespace);
123 
124   bool locked = trylock();
125   bool change_detected, global_change_detected;
126   global_change_detected = change_detected = !locked;
127 
128   char c = 0;
129   if (locked) {
130     // Check all known serial numbers for changes.
131     for (size_t i = 0; i < arraysize(tag_cache); ++i) {
132       if (check_cache(&tag_cache[i].cache)) {
133         change_detected = true;
134       }
135     }
136     for (size_t i = 0; i < arraysize(global_cache); ++i) {
137       if (check_cache(&global_cache[i].cache)) {
138         global_change_detected = true;
139       }
140     }
141 
142     current_global_serial = __system_property_area_serial();
143     if (current_global_serial != global_serial) {
144       global_change_detected = change_detected = true;
145     }
146   }
147 
148   if (tag_len != 0) {
149     bool local_change_detected = change_detected;
150     if (locked) {
151       // compare() rather than == because tag isn't guaranteed 0-terminated.
152       if (last_tag->compare(0, last_tag->size(), tag, tag_len) != 0) {
153         // Invalidate log.tag.<tag> cache.
154         for (size_t i = 0; i < arraysize(tag_cache); ++i) {
155           tag_cache[i].cache.pinfo = NULL;
156           tag_cache[i].c = '\0';
157         }
158         last_tag->assign(tag, tag_len);
159         local_change_detected = true;
160       }
161     }
162     *stpncpy(key + strlen(log_namespace), tag, tag_len) = '\0';
163 
164     for (size_t i = 0; i < arraysize(tag_cache); ++i) {
165       cache_char* cache = &tag_cache[i];
166       cache_char temp_cache;
167 
168       if (!locked) {
169         temp_cache.cache.pinfo = NULL;
170         temp_cache.c = '\0';
171         cache = &temp_cache;
172       }
173       if (local_change_detected) {
174         refresh_cache(cache, i == 0 ? key : key + strlen("persist."));
175       }
176 
177       if (cache->c) {
178         c = cache->c;
179         break;
180       }
181     }
182   }
183 
184   switch (toupper(c)) { /* if invalid, resort to global */
185     case 'V':
186     case 'D':
187     case 'I':
188     case 'W':
189     case 'E':
190     case 'F': /* Not officially supported */
191     case 'A':
192     case 'S':
193     case BOOLEAN_FALSE: /* Not officially supported */
194       break;
195     default:
196       /* clear '.' after log.tag */
197       key[strlen(log_namespace) - 1] = '\0';
198 
199       for (size_t i = 0; i < arraysize(global_cache); ++i) {
200         cache_char* cache = &global_cache[i];
201         cache_char temp_cache;
202 
203         if (!locked) {
204           temp_cache = *cache;
205           if (temp_cache.cache.pinfo != cache->cache.pinfo) {  // check atomic
206             temp_cache.cache.pinfo = NULL;
207             temp_cache.c = '\0';
208           }
209           cache = &temp_cache;
210         }
211         if (global_change_detected) {
212           refresh_cache(cache, i == 0 ? key : key + strlen("persist."));
213         }
214 
215         if (cache->c) {
216           c = cache->c;
217           break;
218         }
219       }
220       break;
221   }
222 
223   if (locked) {
224     global_serial = current_global_serial;
225     unlock();
226   }
227 
228   switch (toupper(c)) {
229     /* clang-format off */
230     case 'V': return ANDROID_LOG_VERBOSE;
231     case 'D': return ANDROID_LOG_DEBUG;
232     case 'I': return ANDROID_LOG_INFO;
233     case 'W': return ANDROID_LOG_WARN;
234     case 'E': return ANDROID_LOG_ERROR;
235     case 'F': /* FALLTHRU */ /* Not officially supported */
236     case 'A': return ANDROID_LOG_FATAL;
237     case BOOLEAN_FALSE: /* FALLTHRU */ /* Not Officially supported */
238     case 'S': return ANDROID_LOG_SILENT;
239       /* clang-format on */
240   }
241   return -1;
242 }
243 
__android_log_is_loggable_len(int prio,const char * tag,size_t len,int default_prio)244 int __android_log_is_loggable_len(int prio, const char* tag, size_t len, int default_prio) {
245   int minimum_log_priority = __android_log_get_minimum_priority();
246   int property_log_level = __android_log_level(tag, len);
247 
248   if (property_log_level >= 0 && minimum_log_priority != ANDROID_LOG_DEFAULT) {
249     return prio >= std::min(property_log_level, minimum_log_priority);
250   } else if (property_log_level >= 0) {
251     return prio >= property_log_level;
252   } else if (minimum_log_priority != ANDROID_LOG_DEFAULT) {
253     return prio >= minimum_log_priority;
254   } else {
255     return prio >= default_prio;
256   }
257 }
258 
__android_log_is_loggable(int prio,const char * tag,int default_prio)259 int __android_log_is_loggable(int prio, const char* tag, int default_prio) {
260   auto len = tag ? strlen(tag) : 0;
261   return __android_log_is_loggable_len(prio, tag, len, default_prio);
262 }
263 
__android_log_is_debuggable()264 int __android_log_is_debuggable() {
265   static int is_debuggable = [] {
266     char value[PROP_VALUE_MAX] = {};
267     return __system_property_get("ro.debuggable", value) > 0 && !strcmp(value, "1");
268   }();
269 
270   return is_debuggable;
271 }
272 
273 /*
274  * For properties that are read often, but generally remain constant.
275  * Since a change is rare, we will accept a trylock failure gracefully.
276  * Use a separate lock from is_loggable to keep contention down b/25563384.
277  */
278 struct cache2_char {
279   pthread_mutex_t lock;
280   uint32_t serial;
281   const char* key_persist;
282   struct cache_char cache_persist;
283   const char* key_ro;
284   struct cache_char cache_ro;
285   unsigned char (*const evaluate)(const struct cache2_char* self);
286 };
287 
do_cache2_char(struct cache2_char * self)288 static inline unsigned char do_cache2_char(struct cache2_char* self) {
289   uint32_t current_serial;
290   int change_detected;
291   unsigned char c;
292 
293   if (pthread_mutex_trylock(&self->lock)) {
294     /* We are willing to accept some race in this context */
295     return self->evaluate(self);
296   }
297 
298   change_detected = check_cache(&self->cache_persist.cache) || check_cache(&self->cache_ro.cache);
299   current_serial = __system_property_area_serial();
300   if (current_serial != self->serial) {
301     change_detected = 1;
302   }
303   if (change_detected) {
304     refresh_cache(&self->cache_persist, self->key_persist);
305     refresh_cache(&self->cache_ro, self->key_ro);
306     self->serial = current_serial;
307   }
308   c = self->evaluate(self);
309 
310   pthread_mutex_unlock(&self->lock);
311 
312   return c;
313 }
314 
315 /*
316  * Security state generally remains constant, but the DO must be able
317  * to turn off logging should it become spammy after an attack is detected.
318  */
evaluate_security(const struct cache2_char * self)319 static unsigned char evaluate_security(const struct cache2_char* self) {
320   unsigned char c = self->cache_ro.c;
321 
322   return (c != BOOLEAN_FALSE) && c && (self->cache_persist.c == BOOLEAN_TRUE);
323 }
324 
__android_log_security()325 int __android_log_security() {
326   static struct cache2_char security = {
327       PTHREAD_MUTEX_INITIALIZER, 0,
328       "persist.logd.security",   {{NULL, 0xFFFFFFFF}, BOOLEAN_FALSE},
329       "ro.organization_owned",   {{NULL, 0xFFFFFFFF}, BOOLEAN_FALSE},
330       evaluate_security};
331 
332   return do_cache2_char(&security);
333 }
334 
335 #else
336 
__android_log_is_loggable(int prio,const char *,int)337 int __android_log_is_loggable(int prio, const char*, int) {
338   int minimum_priority = __android_log_get_minimum_priority();
339   if (minimum_priority == ANDROID_LOG_DEFAULT) {
340     minimum_priority = ANDROID_LOG_INFO;
341   }
342   return prio >= minimum_priority;
343 }
344 
__android_log_is_loggable_len(int prio,const char *,size_t,int def)345 int __android_log_is_loggable_len(int prio, const char*, size_t, int def) {
346   return __android_log_is_loggable(prio, nullptr, def);
347 }
348 
__android_log_is_debuggable()349 int __android_log_is_debuggable() {
350   return 1;
351 }
352 
353 #endif
354