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 <stdatomic.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/stat.h>
36 #include <sys/types.h>
37 #include <unistd.h>
38 
39 #include <new>
40 
41 #include <async_safe/log.h>
42 
43 #include "private/ErrnoRestorer.h"
44 #include "private/bionic_futex.h"
45 
46 #include "system_properties/context_node.h"
47 #include "system_properties/prop_area.h"
48 #include "system_properties/prop_info.h"
49 
50 #define SERIAL_DIRTY(serial) ((serial)&1)
51 #define SERIAL_VALUE_LEN(serial) ((serial) >> 24)
52 
is_dir(const char * pathname)53 static bool is_dir(const char* pathname) {
54   struct stat info;
55   if (stat(pathname, &info) == -1) {
56     return false;
57   }
58   return S_ISDIR(info.st_mode);
59 }
60 
Init(const char * filename)61 bool SystemProperties::Init(const char* filename) {
62   // This is called from __libc_init_common, and should leave errno at 0 (http://b/37248982).
63   ErrnoRestorer errno_restorer;
64 
65   if (initialized_) {
66     contexts_->ResetAccess();
67     return true;
68   }
69 
70   if (strlen(filename) >= PROP_FILENAME_MAX) {
71     return false;
72   }
73   strcpy(property_filename_, filename);
74 
75   if (is_dir(property_filename_)) {
76     if (access("/dev/__properties__/property_info", R_OK) == 0) {
77       contexts_ = new (contexts_data_) ContextsSerialized();
78       if (!contexts_->Initialize(false, property_filename_, nullptr)) {
79         return false;
80       }
81     } else {
82       contexts_ = new (contexts_data_) ContextsSplit();
83       if (!contexts_->Initialize(false, property_filename_, nullptr)) {
84         return false;
85       }
86     }
87   } else {
88     contexts_ = new (contexts_data_) ContextsPreSplit();
89     if (!contexts_->Initialize(false, property_filename_, nullptr)) {
90       return false;
91     }
92   }
93   initialized_ = true;
94   return true;
95 }
96 
AreaInit(const char * filename,bool * fsetxattr_failed)97 bool SystemProperties::AreaInit(const char* filename, bool* fsetxattr_failed) {
98   if (strlen(filename) >= PROP_FILENAME_MAX) {
99     return false;
100   }
101   strcpy(property_filename_, filename);
102 
103   contexts_ = new (contexts_data_) ContextsSerialized();
104   if (!contexts_->Initialize(true, property_filename_, fsetxattr_failed)) {
105     return false;
106   }
107   initialized_ = true;
108   return true;
109 }
110 
AreaSerial()111 uint32_t SystemProperties::AreaSerial() {
112   if (!initialized_) {
113     return -1;
114   }
115 
116   prop_area* pa = contexts_->GetSerialPropArea();
117   if (!pa) {
118     return -1;
119   }
120 
121   // Make sure this read fulfilled before __system_property_serial
122   return atomic_load_explicit(pa->serial(), memory_order_acquire);
123 }
124 
Find(const char * name)125 const prop_info* SystemProperties::Find(const char* name) {
126   if (!initialized_) {
127     return nullptr;
128   }
129 
130   prop_area* pa = contexts_->GetPropAreaForName(name);
131   if (!pa) {
132     async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Access denied finding property \"%s\"", name);
133     return nullptr;
134   }
135 
136   return pa->find(name);
137 }
138 
is_read_only(const char * name)139 static bool is_read_only(const char* name) {
140   return strncmp(name, "ro.", 3) == 0;
141 }
142 
ReadMutablePropertyValue(const prop_info * pi,char * value)143 uint32_t SystemProperties::ReadMutablePropertyValue(const prop_info* pi, char* value) {
144   // We assume the memcpy below gets serialized by the acquire fence.
145   uint32_t new_serial = load_const_atomic(&pi->serial, memory_order_acquire);
146   uint32_t serial;
147   unsigned int len;
148   for (;;) {
149     serial = new_serial;
150     len = SERIAL_VALUE_LEN(serial);
151     if (__predict_false(SERIAL_DIRTY(serial))) {
152       // See the comment in the prop_area constructor.
153       prop_area* pa = contexts_->GetPropAreaForName(pi->name);
154       memcpy(value, pa->dirty_backup_area(), len + 1);
155     } else {
156       memcpy(value, pi->value, len + 1);
157     }
158     atomic_thread_fence(memory_order_acquire);
159     new_serial = load_const_atomic(&pi->serial, memory_order_relaxed);
160     if (__predict_true(serial == new_serial)) {
161       break;
162     }
163     // We need another fence here because we want to ensure that the memcpy in the
164     // next iteration of the loop occurs after the load of new_serial above. We could
165     // get this guarantee by making the load_const_atomic of new_serial
166     // memory_order_acquire instead of memory_order_relaxed, but then we'd pay the
167     // penalty of the memory_order_acquire even in the overwhelmingly common case
168     // that the serial number didn't change.
169     atomic_thread_fence(memory_order_acquire);
170   }
171   return serial;
172 }
173 
Read(const prop_info * pi,char * name,char * value)174 int SystemProperties::Read(const prop_info* pi, char* name, char* value) {
175   uint32_t serial = ReadMutablePropertyValue(pi, value);
176   if (name != nullptr) {
177     size_t namelen = strlcpy(name, pi->name, PROP_NAME_MAX);
178     if (namelen >= PROP_NAME_MAX) {
179       async_safe_format_log(ANDROID_LOG_ERROR, "libc",
180                             "The property name length for \"%s\" is >= %d;"
181                             " please use __system_property_read_callback"
182                             " to read this property. (the name is truncated to \"%s\")",
183                             pi->name, PROP_NAME_MAX - 1, name);
184     }
185   }
186   if (is_read_only(pi->name) && pi->is_long()) {
187     async_safe_format_log(
188         ANDROID_LOG_ERROR, "libc",
189         "The property \"%s\" has a value with length %zu that is too large for"
190         " __system_property_get()/__system_property_read(); use"
191         " __system_property_read_callback() instead.",
192         pi->name, strlen(pi->long_value()));
193   }
194   return SERIAL_VALUE_LEN(serial);
195 }
196 
ReadCallback(const prop_info * pi,void (* callback)(void * cookie,const char * name,const char * value,uint32_t serial),void * cookie)197 void SystemProperties::ReadCallback(const prop_info* pi,
198                                     void (*callback)(void* cookie, const char* name,
199                                                      const char* value, uint32_t serial),
200                                     void* cookie) {
201   // Read only properties don't need to copy the value to a temporary buffer, since it can never
202   // change.  We use relaxed memory order on the serial load for the same reason.
203   if (is_read_only(pi->name)) {
204     uint32_t serial = load_const_atomic(&pi->serial, memory_order_relaxed);
205     if (pi->is_long()) {
206       callback(cookie, pi->name, pi->long_value(), serial);
207     } else {
208       callback(cookie, pi->name, pi->value, serial);
209     }
210     return;
211   }
212 
213   char value_buf[PROP_VALUE_MAX];
214   uint32_t serial = ReadMutablePropertyValue(pi, value_buf);
215   callback(cookie, pi->name, value_buf, serial);
216 }
217 
Get(const char * name,char * value)218 int SystemProperties::Get(const char* name, char* value) {
219   const prop_info* pi = Find(name);
220 
221   if (pi != nullptr) {
222     return Read(pi, nullptr, value);
223   } else {
224     value[0] = 0;
225     return 0;
226   }
227 }
228 
Update(prop_info * pi,const char * value,unsigned int len)229 int SystemProperties::Update(prop_info* pi, const char* value, unsigned int len) {
230   if (len >= PROP_VALUE_MAX) {
231     return -1;
232   }
233 
234   if (!initialized_) {
235     return -1;
236   }
237 
238   prop_area* serial_pa = contexts_->GetSerialPropArea();
239   if (!serial_pa) {
240     return -1;
241   }
242   prop_area* pa = contexts_->GetPropAreaForName(pi->name);
243   if (__predict_false(!pa)) {
244     async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Could not find area for \"%s\"", pi->name);
245     return -1;
246   }
247 
248   uint32_t serial = atomic_load_explicit(&pi->serial, memory_order_relaxed);
249   unsigned int old_len = SERIAL_VALUE_LEN(serial);
250 
251   // The contract with readers is that whenever the dirty bit is set, an undamaged copy
252   // of the pre-dirty value is available in the dirty backup area. The fence ensures
253   // that we publish our dirty area update before allowing readers to see a
254   // dirty serial.
255   memcpy(pa->dirty_backup_area(), pi->value, old_len + 1);
256   atomic_thread_fence(memory_order_release);
257   serial |= 1;
258   atomic_store_explicit(&pi->serial, serial, memory_order_relaxed);
259   strlcpy(pi->value, value, len + 1);
260   // Now the primary value property area is up-to-date. Let readers know that they should
261   // look at the property value instead of the backup area.
262   atomic_thread_fence(memory_order_release);
263   atomic_store_explicit(&pi->serial, (len << 24) | ((serial + 1) & 0xffffff), memory_order_relaxed);
264   __futex_wake(&pi->serial, INT32_MAX);  // Fence by side effect
265   atomic_store_explicit(serial_pa->serial(),
266                         atomic_load_explicit(serial_pa->serial(), memory_order_relaxed) + 1,
267                         memory_order_release);
268   __futex_wake(serial_pa->serial(), INT32_MAX);
269 
270   return 0;
271 }
272 
Add(const char * name,unsigned int namelen,const char * value,unsigned int valuelen)273 int SystemProperties::Add(const char* name, unsigned int namelen, const char* value,
274                           unsigned int valuelen) {
275   if (valuelen >= PROP_VALUE_MAX && !is_read_only(name)) {
276     return -1;
277   }
278 
279   if (namelen < 1) {
280     return -1;
281   }
282 
283   if (!initialized_) {
284     return -1;
285   }
286 
287   prop_area* serial_pa = contexts_->GetSerialPropArea();
288   if (serial_pa == nullptr) {
289     return -1;
290   }
291 
292   prop_area* pa = contexts_->GetPropAreaForName(name);
293   if (!pa) {
294     async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Access denied adding property \"%s\"", name);
295     return -1;
296   }
297 
298   bool ret = pa->add(name, namelen, value, valuelen);
299   if (!ret) {
300     return -1;
301   }
302 
303   // There is only a single mutator, but we want to make sure that
304   // updates are visible to a reader waiting for the update.
305   atomic_store_explicit(serial_pa->serial(),
306                         atomic_load_explicit(serial_pa->serial(), memory_order_relaxed) + 1,
307                         memory_order_release);
308   __futex_wake(serial_pa->serial(), INT32_MAX);
309   return 0;
310 }
311 
WaitAny(uint32_t old_serial)312 uint32_t SystemProperties::WaitAny(uint32_t old_serial) {
313   uint32_t new_serial;
314   Wait(nullptr, old_serial, &new_serial, nullptr);
315   return new_serial;
316 }
317 
Wait(const prop_info * pi,uint32_t old_serial,uint32_t * new_serial_ptr,const timespec * relative_timeout)318 bool SystemProperties::Wait(const prop_info* pi, uint32_t old_serial, uint32_t* new_serial_ptr,
319                             const timespec* relative_timeout) {
320   // Are we waiting on the global serial or a specific serial?
321   atomic_uint_least32_t* serial_ptr;
322   if (pi == nullptr) {
323     if (!initialized_) {
324       return -1;
325     }
326 
327     prop_area* serial_pa = contexts_->GetSerialPropArea();
328     if (serial_pa == nullptr) {
329       return -1;
330     }
331 
332     serial_ptr = serial_pa->serial();
333   } else {
334     serial_ptr = const_cast<atomic_uint_least32_t*>(&pi->serial);
335   }
336 
337   uint32_t new_serial;
338   do {
339     int rc;
340     if ((rc = __futex_wait(serial_ptr, old_serial, relative_timeout)) != 0 && rc == -ETIMEDOUT) {
341       return false;
342     }
343     new_serial = load_const_atomic(serial_ptr, memory_order_acquire);
344   } while (new_serial == old_serial);
345 
346   *new_serial_ptr = new_serial;
347   return true;
348 }
349 
FindNth(unsigned n)350 const prop_info* SystemProperties::FindNth(unsigned n) {
351   struct find_nth {
352     const uint32_t sought;
353     uint32_t current;
354     const prop_info* result;
355 
356     explicit find_nth(uint32_t n) : sought(n), current(0), result(nullptr) {
357     }
358     static void fn(const prop_info* pi, void* ptr) {
359       find_nth* self = reinterpret_cast<find_nth*>(ptr);
360       if (self->current++ == self->sought) self->result = pi;
361     }
362   } state(n);
363   Foreach(find_nth::fn, &state);
364   return state.result;
365 }
366 
Foreach(void (* propfn)(const prop_info * pi,void * cookie),void * cookie)367 int SystemProperties::Foreach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) {
368   if (!initialized_) {
369     return -1;
370   }
371 
372   contexts_->ForEach(propfn, cookie);
373 
374   return 0;
375 }
376