• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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