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