diff --git a/include/log/log.h b/include/log/log.h index 086d7427b..619bf230c 100644 --- a/include/log/log.h +++ b/include/log/log.h @@ -620,6 +620,8 @@ typedef enum log_id { */ int __android_log_is_loggable(int prio, const char *tag, int default_prio); +int __android_log_security(); /* Device Owner is present */ + int __android_log_error_write(int tag, const char *subTag, int32_t uid, const char *data, uint32_t dataLen); diff --git a/liblog/log_is_loggable.c b/liblog/log_is_loggable.c index 7fc01d9ab..854ecfabc 100644 --- a/liblog/log_is_loggable.c +++ b/liblog/log_is_loggable.c @@ -45,6 +45,9 @@ struct cache { char c; }; +#define BOOLEAN_TRUE 0xFF +#define BOOLEAN_FALSE 0xFE + static void refresh_cache(struct cache *cache, const char *key) { uint32_t serial; @@ -62,7 +65,16 @@ static void refresh_cache(struct cache *cache, const char *key) } cache->serial = serial; __system_property_read(cache->pinfo, 0, buf); - cache->c = buf[0]; + switch(buf[0]) { + case 't': case 'T': + cache->c = strcasecmp(buf + 1, "rue") ? buf[0] : BOOLEAN_TRUE; + break; + case 'f': case 'F': + cache->c = strcasecmp(buf + 1, "alse") ? buf[0] : BOOLEAN_FALSE; + break; + default: + cache->c = buf[0]; + } } static int __android_log_level(const char *tag, int default_prio) @@ -147,6 +159,7 @@ static int __android_log_level(const char *tag, int default_prio) case 'F': /* Not officially supported */ case 'A': case 'S': + case BOOLEAN_FALSE: /* Not officially supported */ break; default: /* clear '.' after log.tag */ @@ -180,6 +193,7 @@ static int __android_log_level(const char *tag, int default_prio) case 'E': return ANDROID_LOG_ERROR; case 'F': /* FALLTHRU */ /* Not officially supported */ case 'A': return ANDROID_LOG_FATAL; + case BOOLEAN_FALSE: /* FALLTHRU */ /* Not Officially supported */ case 'S': return -1; /* ANDROID_LOG_SUPPRESS */ } return default_prio; @@ -226,3 +240,36 @@ clockid_t android_log_clockid() return (tolower(c) == 'm') ? CLOCK_MONOTONIC : CLOCK_REALTIME; } + +/* + * security state generally remains constant, since a change is + * rare, we can accept a trylock failure gracefully. + */ +static pthread_mutex_t lock_security = PTHREAD_MUTEX_INITIALIZER; + +int __android_log_security() +{ + static struct cache r_do_cache = { NULL, -1, BOOLEAN_FALSE }; + static struct cache p_security_cache = { NULL, -1, BOOLEAN_FALSE }; + int retval; + + if (pthread_mutex_trylock(&lock_security)) { + /* We are willing to accept some race in this context */ + retval = (r_do_cache.c != BOOLEAN_FALSE) && r_do_cache.c && + (p_security_cache.c == BOOLEAN_TRUE); + } else { + static uint32_t serial; + uint32_t current_serial = __system_property_area_serial(); + if (current_serial != serial) { + refresh_cache(&r_do_cache, "ro.device_owner"); + refresh_cache(&p_security_cache, "persist.logd.security"); + serial = current_serial; + } + retval = (r_do_cache.c != BOOLEAN_FALSE) && r_do_cache.c && + (p_security_cache.c == BOOLEAN_TRUE); + + pthread_mutex_unlock(&lock_security); + } + + return retval; +} diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp index 110f1eb77..597d8f694 100644 --- a/liblog/tests/liblog_test.cpp +++ b/liblog/tests/liblog_test.cpp @@ -164,6 +164,43 @@ TEST(liblog, __android_log_btwrite__android_logger_list_read) { android_logger_list_close(logger_list); } +TEST(liblog, __security) { + static const char persist_key[] = "persist.logd.security"; + static const char readonly_key[] = "ro.device_owner"; + static const char nothing_val[] = "_NOTHING_TO_SEE_HERE_"; + char persist[PROP_VALUE_MAX]; + char readonly[PROP_VALUE_MAX]; + + property_get(persist_key, persist, ""); + property_get(readonly_key, readonly, nothing_val); + + if (!strcmp(readonly, nothing_val)) { + EXPECT_FALSE(__android_log_security()); + fprintf(stderr, "Warning, setting ro.device_owner to a domain\n"); + property_set(readonly_key, "com.google.android.SecOps.DeviceOwner"); + } else if (!strcasecmp(readonly, "false") || !readonly[0]) { + EXPECT_FALSE(__android_log_security()); + return; + } + + if (!strcasecmp(persist, "true")) { + EXPECT_TRUE(__android_log_security()); + } else { + EXPECT_FALSE(__android_log_security()); + } + property_set(persist_key, "TRUE"); + EXPECT_TRUE(__android_log_security()); + property_set(persist_key, "FALSE"); + EXPECT_FALSE(__android_log_security()); + property_set(persist_key, "true"); + EXPECT_TRUE(__android_log_security()); + property_set(persist_key, "false"); + EXPECT_FALSE(__android_log_security()); + property_set(persist_key, ""); + EXPECT_FALSE(__android_log_security()); + property_set(persist_key, persist); +} + static unsigned signaled; log_time signal_time;