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