1 /*
2 * Copyright (C) 2008 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 "system_properties/system_properties.h"
30
31 #include <errno.h>
32 #include <private/android_filesystem_config.h>
33 #include <stdatomic.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 #include <unistd.h>
39
40 #include <new>
41
42 #include <async_safe/CHECK.h>
43 #include <async_safe/log.h>
44
45 #include "private/ErrnoRestorer.h"
46 #include "private/bionic_futex.h"
47
48 #include "system_properties/context_node.h"
49 #include "system_properties/prop_area.h"
50 #include "system_properties/prop_info.h"
51
52 #define SERIAL_DIRTY(serial) ((serial)&1)
53 #define SERIAL_VALUE_LEN(serial) ((serial) >> 24)
54 #define APPCOMPAT_PREFIX "ro.appcompat_override."
55
is_dir(const char * pathname)56 static bool is_dir(const char* pathname) {
57 struct stat info;
58 if (stat(pathname, &info) == -1) {
59 return false;
60 }
61 return S_ISDIR(info.st_mode);
62 }
63
Init(const char * filename)64 bool SystemProperties::Init(const char* filename) {
65 // This is called from __libc_init_common, and should leave errno at 0 (http://b/37248982).
66 ErrnoRestorer errno_restorer;
67
68 if (initialized_) {
69 contexts_->ResetAccess();
70 return true;
71 }
72
73 properties_filename_ = filename;
74
75 if (!InitContexts(false)) {
76 return false;
77 }
78
79 initialized_ = true;
80 return true;
81 }
82
InitContexts(bool load_default_path)83 bool SystemProperties::InitContexts(bool load_default_path) {
84 if (is_dir(properties_filename_.c_str())) {
85 if (access(PROP_TREE_FILE, R_OK) == 0) {
86 auto serial_contexts = new (contexts_data_) ContextsSerialized();
87 contexts_ = serial_contexts;
88 if (!serial_contexts->Initialize(false, properties_filename_.c_str(), nullptr,
89 load_default_path)) {
90 return false;
91 }
92 } else {
93 contexts_ = new (contexts_data_) ContextsSplit();
94 if (!contexts_->Initialize(false, properties_filename_.c_str(), nullptr)) {
95 return false;
96 }
97 }
98 } else {
99 contexts_ = new (contexts_data_) ContextsPreSplit();
100 if (!contexts_->Initialize(false, properties_filename_.c_str(), nullptr)) {
101 return false;
102 }
103 }
104 return true;
105 }
106
AreaInit(const char * filename,bool * fsetxattr_failed)107 bool SystemProperties::AreaInit(const char* filename, bool* fsetxattr_failed) {
108 return AreaInit(filename, fsetxattr_failed, false);
109 }
110
111 // Note: load_default_path is only used for testing, as it will cause properties to be loaded from
112 // one file (specified by PropertyInfoAreaFile.LoadDefaultPath), but be written to "filename".
AreaInit(const char * filename,bool * fsetxattr_failed,bool load_default_path)113 bool SystemProperties::AreaInit(const char* filename, bool* fsetxattr_failed,
114 bool load_default_path) {
115 properties_filename_ = filename;
116 auto serial_contexts = new (contexts_data_) ContextsSerialized();
117 contexts_ = serial_contexts;
118 if (!serial_contexts->Initialize(true, properties_filename_.c_str(), fsetxattr_failed,
119 load_default_path)) {
120 return false;
121 }
122
123 appcompat_filename_ = PropertiesFilename(properties_filename_.c_str(), "appcompat_override");
124 appcompat_override_contexts_ = nullptr;
125 if (access(appcompat_filename_.c_str(), F_OK) != -1) {
126 auto* appcompat_contexts = new (appcompat_override_contexts_data_) ContextsSerialized();
127 if (!appcompat_contexts->Initialize(true, appcompat_filename_.c_str(), fsetxattr_failed,
128 load_default_path)) {
129 // The appcompat folder exists, but initializing it failed
130 return false;
131 } else {
132 appcompat_override_contexts_ = appcompat_contexts;
133 }
134 }
135
136 initialized_ = true;
137 return true;
138 }
139
Reload(bool load_default_path)140 bool SystemProperties::Reload(bool load_default_path) {
141 if (!initialized_) {
142 return true;
143 }
144
145 return InitContexts(load_default_path);
146 }
147
AreaSerial()148 uint32_t SystemProperties::AreaSerial() {
149 if (!initialized_) {
150 return -1;
151 }
152
153 prop_area* pa = contexts_->GetSerialPropArea();
154 if (!pa) {
155 return -1;
156 }
157
158 // Make sure this read fulfilled before __system_property_serial
159 return atomic_load_explicit(pa->serial(), memory_order_acquire);
160 }
161
Find(const char * name)162 const prop_info* SystemProperties::Find(const char* name) {
163 if (!initialized_) {
164 return nullptr;
165 }
166
167 prop_area* pa = contexts_->GetPropAreaForName(name);
168 if (!pa) {
169 async_safe_format_log(ANDROID_LOG_WARN, "libc", "Access denied finding property \"%s\"", name);
170 return nullptr;
171 }
172
173 return pa->find(name);
174 }
175
is_appcompat_override(const char * name)176 static bool is_appcompat_override(const char* name) {
177 return strncmp(name, APPCOMPAT_PREFIX, strlen(APPCOMPAT_PREFIX)) == 0;
178 }
179
is_read_only(const char * name)180 static bool is_read_only(const char* name) {
181 return strncmp(name, "ro.", 3) == 0;
182 }
183
ReadMutablePropertyValue(const prop_info * pi,char * value)184 uint32_t SystemProperties::ReadMutablePropertyValue(const prop_info* pi, char* value) {
185 // We assume the memcpy below gets serialized by the acquire fence.
186 uint32_t new_serial = load_const_atomic(&pi->serial, memory_order_acquire);
187 uint32_t serial;
188 unsigned int len;
189 for (;;) {
190 serial = new_serial;
191 len = SERIAL_VALUE_LEN(serial);
192 if (__predict_false(SERIAL_DIRTY(serial))) {
193 // See the comment in the prop_area constructor.
194 prop_area* pa = contexts_->GetPropAreaForName(pi->name);
195 memcpy(value, pa->dirty_backup_area(), len + 1);
196 } else {
197 memcpy(value, pi->value, len + 1);
198 }
199 atomic_thread_fence(memory_order_acquire);
200 new_serial = load_const_atomic(&pi->serial, memory_order_relaxed);
201 if (__predict_true(serial == new_serial)) {
202 break;
203 }
204 // We need another fence here because we want to ensure that the memcpy in the
205 // next iteration of the loop occurs after the load of new_serial above. We could
206 // get this guarantee by making the load_const_atomic of new_serial
207 // memory_order_acquire instead of memory_order_relaxed, but then we'd pay the
208 // penalty of the memory_order_acquire even in the overwhelmingly common case
209 // that the serial number didn't change.
210 atomic_thread_fence(memory_order_acquire);
211 }
212 return serial;
213 }
214
Read(const prop_info * pi,char * name,char * value)215 int SystemProperties::Read(const prop_info* pi, char* name, char* value) {
216 uint32_t serial = ReadMutablePropertyValue(pi, value);
217 if (name != nullptr) {
218 size_t namelen = strlcpy(name, pi->name, PROP_NAME_MAX);
219 if (namelen >= PROP_NAME_MAX) {
220 async_safe_format_log(ANDROID_LOG_ERROR, "libc",
221 "The property name length for \"%s\" is >= %d;"
222 " please use __system_property_read_callback"
223 " to read this property. (the name is truncated to \"%s\")",
224 pi->name, PROP_NAME_MAX - 1, name);
225 }
226 }
227 if (is_read_only(pi->name) && pi->is_long()) {
228 async_safe_format_log(
229 ANDROID_LOG_ERROR, "libc",
230 "The property \"%s\" has a value with length %zu that is too large for"
231 " __system_property_get()/__system_property_read(); use"
232 " __system_property_read_callback() instead.",
233 pi->name, strlen(pi->long_value()));
234 }
235 return SERIAL_VALUE_LEN(serial);
236 }
237
ReadCallback(const prop_info * pi,void (* callback)(void * cookie,const char * name,const char * value,uint32_t serial),void * cookie)238 void SystemProperties::ReadCallback(const prop_info* pi,
239 void (*callback)(void* cookie, const char* name,
240 const char* value, uint32_t serial),
241 void* cookie) {
242 // Read only properties don't need to copy the value to a temporary buffer, since it can never
243 // change. We use relaxed memory order on the serial load for the same reason.
244 if (is_read_only(pi->name)) {
245 uint32_t serial = load_const_atomic(&pi->serial, memory_order_relaxed);
246 if (pi->is_long()) {
247 callback(cookie, pi->name, pi->long_value(), serial);
248 } else {
249 callback(cookie, pi->name, pi->value, serial);
250 }
251 return;
252 }
253
254 char value_buf[PROP_VALUE_MAX];
255 uint32_t serial = ReadMutablePropertyValue(pi, value_buf);
256 callback(cookie, pi->name, value_buf, serial);
257 }
258
Get(const char * name,char * value)259 int SystemProperties::Get(const char* name, char* value) {
260 const prop_info* pi = Find(name);
261
262 if (pi != nullptr) {
263 return Read(pi, nullptr, value);
264 } else {
265 value[0] = 0;
266 return 0;
267 }
268 }
269
Update(prop_info * pi,const char * value,unsigned int len)270 int SystemProperties::Update(prop_info* pi, const char* value, unsigned int len) {
271 if (len >= PROP_VALUE_MAX) {
272 return -1;
273 }
274
275 if (!initialized_) {
276 return -1;
277 }
278 bool have_override = appcompat_override_contexts_ != nullptr;
279
280 prop_area* serial_pa = contexts_->GetSerialPropArea();
281 prop_area* override_serial_pa =
282 have_override ? appcompat_override_contexts_->GetSerialPropArea() : nullptr;
283 if (!serial_pa) {
284 return -1;
285 }
286 prop_area* pa = contexts_->GetPropAreaForName(pi->name);
287 prop_area* override_pa =
288 have_override ? appcompat_override_contexts_->GetPropAreaForName(pi->name) : nullptr;
289 if (__predict_false(!pa)) {
290 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Could not find area for \"%s\"", pi->name);
291 return -1;
292 }
293 CHECK(!have_override || (override_pa && override_serial_pa));
294
295 auto* override_pi = const_cast<prop_info*>(have_override ? override_pa->find(pi->name) : nullptr);
296
297 uint32_t serial = atomic_load_explicit(&pi->serial, memory_order_relaxed);
298 unsigned int old_len = SERIAL_VALUE_LEN(serial);
299
300 // The contract with readers is that whenever the dirty bit is set, an undamaged copy
301 // of the pre-dirty value is available in the dirty backup area. The fence ensures
302 // that we publish our dirty area update before allowing readers to see a
303 // dirty serial.
304 memcpy(pa->dirty_backup_area(), pi->value, old_len + 1);
305 if (have_override) {
306 memcpy(override_pa->dirty_backup_area(), override_pi->value, old_len + 1);
307 }
308 atomic_thread_fence(memory_order_release);
309 serial |= 1;
310 atomic_store_explicit(&pi->serial, serial, memory_order_relaxed);
311 strlcpy(pi->value, value, len + 1);
312 if (have_override) {
313 atomic_store_explicit(&override_pi->serial, serial, memory_order_relaxed);
314 strlcpy(override_pi->value, value, len + 1);
315 }
316 // Now the primary value property area is up-to-date. Let readers know that they should
317 // look at the property value instead of the backup area.
318 atomic_thread_fence(memory_order_release);
319 int new_serial = (len << 24) | ((serial + 1) & 0xffffff);
320 atomic_store_explicit(&pi->serial, new_serial, memory_order_relaxed);
321 if (have_override) {
322 atomic_store_explicit(&override_pi->serial, new_serial, memory_order_relaxed);
323 }
324 __futex_wake(&pi->serial, INT32_MAX); // Fence by side effect
325 atomic_store_explicit(serial_pa->serial(),
326 atomic_load_explicit(serial_pa->serial(), memory_order_relaxed) + 1,
327 memory_order_release);
328 if (have_override) {
329 atomic_store_explicit(override_serial_pa->serial(),
330 atomic_load_explicit(serial_pa->serial(), memory_order_relaxed) + 1,
331 memory_order_release);
332 }
333 __futex_wake(serial_pa->serial(), INT32_MAX);
334
335 return 0;
336 }
337
Add(const char * name,unsigned int namelen,const char * value,unsigned int valuelen)338 int SystemProperties::Add(const char* name, unsigned int namelen, const char* value,
339 unsigned int valuelen) {
340 if (namelen < 1) {
341 async_safe_format_log(ANDROID_LOG_ERROR, "libc",
342 "__system_property_add failed: name length 0");
343 return -1;
344 }
345
346 if (valuelen >= PROP_VALUE_MAX && !is_read_only(name)) {
347 async_safe_format_log(ANDROID_LOG_ERROR, "libc",
348 "__system_property_add failed: \"%s\" value too long: %d >= PROP_VALUE_MAX",
349 name, valuelen);
350 return -1;
351 }
352
353 if (!initialized_) {
354 async_safe_format_log(ANDROID_LOG_ERROR, "libc",
355 "__system_property_add failed: properties not initialized");
356 return -1;
357 }
358
359 prop_area* serial_pa = contexts_->GetSerialPropArea();
360 if (serial_pa == nullptr) {
361 async_safe_format_log(ANDROID_LOG_ERROR, "libc",
362 "__system_property_add failed: property area not found");
363 return -1;
364 }
365
366 prop_area* pa = contexts_->GetPropAreaForName(name);
367 if (!pa) {
368 async_safe_format_log(ANDROID_LOG_ERROR, "libc",
369 "__system_property_add failed: access denied for \"%s\"", name);
370 return -1;
371 }
372
373 if (!pa->add(name, namelen, value, valuelen)) {
374 async_safe_format_log(ANDROID_LOG_ERROR, "libc",
375 "__system_property_add failed: add failed for \"%s\"", name);
376 return -1;
377 }
378
379 if (appcompat_override_contexts_ != nullptr) {
380 bool is_override = is_appcompat_override(name);
381 const char* override_name = name;
382 if (is_override) override_name += strlen(APPCOMPAT_PREFIX);
383 prop_area* other_pa = appcompat_override_contexts_->GetPropAreaForName(override_name);
384 prop_area* other_serial_pa = appcompat_override_contexts_->GetSerialPropArea();
385 CHECK(other_pa && other_serial_pa);
386 // We may write a property twice to overrides, once for the ro.*, and again for the
387 // ro.appcompat_override.ro.* property. If we've already written, then we should essentially
388 // perform an Update, not an Add.
389 auto other_pi = const_cast<prop_info*>(other_pa->find(override_name));
390 if (!other_pi) {
391 if (other_pa->add(override_name, strlen(override_name), value, valuelen)) {
392 atomic_store_explicit(
393 other_serial_pa->serial(),
394 atomic_load_explicit(other_serial_pa->serial(), memory_order_relaxed) + 1,
395 memory_order_release);
396 }
397 } else if (is_override) {
398 // We already wrote the ro.*, but appcompat_override.ro.* should override that. We don't
399 // need to do the usual dirty bit setting, as this only happens during the init process,
400 // before any readers are started. Check that only init or root can write appcompat props.
401 CHECK(getpid() == 1 || getuid() == 0);
402 atomic_thread_fence(memory_order_release);
403 strlcpy(other_pi->value, value, valuelen + 1);
404 }
405 }
406
407 // There is only a single mutator, but we want to make sure that
408 // updates are visible to a reader waiting for the update.
409 atomic_store_explicit(serial_pa->serial(),
410 atomic_load_explicit(serial_pa->serial(), memory_order_relaxed) + 1,
411 memory_order_release);
412 __futex_wake(serial_pa->serial(), INT32_MAX);
413 return 0;
414 }
415
WaitAny(uint32_t old_serial)416 uint32_t SystemProperties::WaitAny(uint32_t old_serial) {
417 uint32_t new_serial;
418 Wait(nullptr, old_serial, &new_serial, nullptr);
419 return new_serial;
420 }
421
Wait(const prop_info * pi,uint32_t old_serial,uint32_t * new_serial_ptr,const timespec * relative_timeout)422 bool SystemProperties::Wait(const prop_info* pi, uint32_t old_serial, uint32_t* new_serial_ptr,
423 const timespec* relative_timeout) {
424 // Are we waiting on the global serial or a specific serial?
425 atomic_uint_least32_t* serial_ptr;
426 if (pi == nullptr) {
427 if (!initialized_) {
428 return -1;
429 }
430
431 prop_area* serial_pa = contexts_->GetSerialPropArea();
432 if (serial_pa == nullptr) {
433 return -1;
434 }
435
436 serial_ptr = serial_pa->serial();
437 } else {
438 serial_ptr = const_cast<atomic_uint_least32_t*>(&pi->serial);
439 }
440
441 uint32_t new_serial;
442 do {
443 int rc;
444 if ((rc = __futex_wait(serial_ptr, old_serial, relative_timeout)) != 0 && rc == -ETIMEDOUT) {
445 return false;
446 }
447 new_serial = load_const_atomic(serial_ptr, memory_order_acquire);
448 } while (new_serial == old_serial);
449
450 *new_serial_ptr = new_serial;
451 return true;
452 }
453
FindNth(unsigned n)454 const prop_info* SystemProperties::FindNth(unsigned n) {
455 struct find_nth {
456 const uint32_t sought;
457 uint32_t current;
458 const prop_info* result;
459
460 explicit find_nth(uint32_t n) : sought(n), current(0), result(nullptr) {
461 }
462 static void fn(const prop_info* pi, void* ptr) {
463 find_nth* self = reinterpret_cast<find_nth*>(ptr);
464 if (self->current++ == self->sought) self->result = pi;
465 }
466 } state(n);
467 Foreach(find_nth::fn, &state);
468 return state.result;
469 }
470
Foreach(void (* propfn)(const prop_info * pi,void * cookie),void * cookie)471 int SystemProperties::Foreach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) {
472 if (!initialized_) {
473 return -1;
474 }
475
476 contexts_->ForEach(propfn, cookie);
477
478 return 0;
479 }
480