blob: 1cb15c3df5240d252ceb49d7a9212f1f634b279e [file] [log] [blame]
Tom Cherryfd44b9f2017-11-08 14:01:00 -08001/*
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
Tom Cherrye275d6d2017-12-11 23:31:33 -080029#include "system_properties/system_properties.h"
30
Tom Cherryfd44b9f2017-11-08 14:01:00 -080031#include <errno.h>
Tom Cherryfd44b9f2017-11-08 14:01:00 -080032#include <stdatomic.h>
Tom Cherryfd44b9f2017-11-08 14:01:00 -080033#include <stdlib.h>
34#include <string.h>
Tom Cherryfd44b9f2017-11-08 14:01:00 -080035#include <sys/stat.h>
36#include <sys/types.h>
Tom Cherryfd44b9f2017-11-08 14:01:00 -080037#include <unistd.h>
38
Tom Cherry8d366a82017-11-30 15:41:32 -080039#include <new>
40
Tom Cherryfd44b9f2017-11-08 14:01:00 -080041#include <async_safe/log.h>
42
43#include "private/ErrnoRestorer.h"
Tom Cherryfd44b9f2017-11-08 14:01:00 -080044#include "private/bionic_futex.h"
Tom Cherryfd44b9f2017-11-08 14:01:00 -080045
Tom Cherrye275d6d2017-12-11 23:31:33 -080046#include "system_properties/context_node.h"
47#include "system_properties/prop_area.h"
48#include "system_properties/prop_info.h"
Tom Cherryfd44b9f2017-11-08 14:01:00 -080049
50#define SERIAL_DIRTY(serial) ((serial)&1)
51#define SERIAL_VALUE_LEN(serial) ((serial) >> 24)
52
Tom Cherryfd44b9f2017-11-08 14:01:00 -080053static 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
Tom Cherrye275d6d2017-12-11 23:31:33 -080061bool SystemProperties::Init(const char* filename) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -080062 // This is called from __libc_init_common, and should leave errno at 0 (http://b/37248982).
63 ErrnoRestorer errno_restorer;
64
Tom Cherrye275d6d2017-12-11 23:31:33 -080065 if (initialized_) {
Tom Cherryee8e3dd2018-02-21 15:01:22 -080066 contexts_->ResetAccess();
Tom Cherrye275d6d2017-12-11 23:31:33 -080067 return true;
Tom Cherryfd44b9f2017-11-08 14:01:00 -080068 }
Tom Cherrye275d6d2017-12-11 23:31:33 -080069
Ryan Prichardd91285f2018-05-01 18:03:05 -070070 if (strlen(filename) >= PROP_FILENAME_MAX) {
Tom Cherrye275d6d2017-12-11 23:31:33 -080071 return false;
72 }
73 strcpy(property_filename_, filename);
74
75 if (is_dir(property_filename_)) {
Tom Cherry8be995b2017-12-14 01:57:37 +000076 if (access("/dev/__properties__/property_info", R_OK) == 0) {
Tom Cherryee8e3dd2018-02-21 15:01:22 -080077 contexts_ = new (contexts_data_) ContextsSerialized();
78 if (!contexts_->Initialize(false, property_filename_, nullptr)) {
Tom Cherrye275d6d2017-12-11 23:31:33 -080079 return false;
Tom Cherry8be995b2017-12-14 01:57:37 +000080 }
Tom Cherry8be995b2017-12-14 01:57:37 +000081 } else {
Tom Cherryee8e3dd2018-02-21 15:01:22 -080082 contexts_ = new (contexts_data_) ContextsSplit();
83 if (!contexts_->Initialize(false, property_filename_, nullptr)) {
Tom Cherrye275d6d2017-12-11 23:31:33 -080084 return false;
Tom Cherry8be995b2017-12-14 01:57:37 +000085 }
Tom Cherryfd44b9f2017-11-08 14:01:00 -080086 }
Tom Cherryfd44b9f2017-11-08 14:01:00 -080087 } else {
Tom Cherryee8e3dd2018-02-21 15:01:22 -080088 contexts_ = new (contexts_data_) ContextsPreSplit();
89 if (!contexts_->Initialize(false, property_filename_, nullptr)) {
Tom Cherrye275d6d2017-12-11 23:31:33 -080090 return false;
Tom Cherryfd44b9f2017-11-08 14:01:00 -080091 }
Tom Cherryfd44b9f2017-11-08 14:01:00 -080092 }
Tom Cherrye275d6d2017-12-11 23:31:33 -080093 initialized_ = true;
94 return true;
Tom Cherryfd44b9f2017-11-08 14:01:00 -080095}
96
Tom Cherrye275d6d2017-12-11 23:31:33 -080097bool SystemProperties::AreaInit(const char* filename, bool* fsetxattr_failed) {
Ryan Prichardd91285f2018-05-01 18:03:05 -070098 if (strlen(filename) >= PROP_FILENAME_MAX) {
Tom Cherrye275d6d2017-12-11 23:31:33 -080099 return false;
100 }
101 strcpy(property_filename_, filename);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800102
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800103 contexts_ = new (contexts_data_) ContextsSerialized();
104 if (!contexts_->Initialize(true, property_filename_, fsetxattr_failed)) {
Tom Cherrye275d6d2017-12-11 23:31:33 -0800105 return false;
106 }
107 initialized_ = true;
108 return true;
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800109}
110
Tom Cherrye275d6d2017-12-11 23:31:33 -0800111uint32_t SystemProperties::AreaSerial() {
112 if (!initialized_) {
Tom Cherryf76bbf52017-11-08 14:01:00 -0800113 return -1;
114 }
115
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800116 prop_area* pa = contexts_->GetSerialPropArea();
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800117 if (!pa) {
118 return -1;
119 }
Tom Cherryf76bbf52017-11-08 14:01:00 -0800120
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800121 // Make sure this read fulfilled before __system_property_serial
122 return atomic_load_explicit(pa->serial(), memory_order_acquire);
123}
124
Tom Cherrye275d6d2017-12-11 23:31:33 -0800125const prop_info* SystemProperties::Find(const char* name) {
126 if (!initialized_) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800127 return nullptr;
128 }
129
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800130 prop_area* pa = contexts_->GetPropAreaForName(name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800131 if (!pa) {
Tom Cherry8f11c5f2021-04-01 15:07:40 -0700132 async_safe_format_log(ANDROID_LOG_WARN, "libc", "Access denied finding property \"%s\"", name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800133 return nullptr;
134 }
135
136 return pa->find(name);
137}
138
139static bool is_read_only(const char* name) {
140 return strncmp(name, "ro.", 3) == 0;
141}
142
Raman Tennetib481a2e2019-11-12 20:41:55 +0000143uint32_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 }
Raman Tennetide39d922019-11-12 18:24:06 +0000158 atomic_thread_fence(memory_order_acquire);
Raman Tennetib481a2e2019-11-12 20:41:55 +0000159 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
174int 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);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800184 }
185 }
Raman Tennetib481a2e2019-11-12 20:41:55 +0000186 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);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800195}
196
Tom Cherrye275d6d2017-12-11 23:31:33 -0800197void SystemProperties::ReadCallback(const prop_info* pi,
198 void (*callback)(void* cookie, const char* name,
199 const char* value, uint32_t serial),
200 void* cookie) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800201 // Read only properties don't need to copy the value to a temporary buffer, since it can never
Raman Tennetib481a2e2019-11-12 20:41:55 +0000202 // change. We use relaxed memory order on the serial load for the same reason.
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800203 if (is_read_only(pi->name)) {
Raman Tennetib481a2e2019-11-12 20:41:55 +0000204 uint32_t serial = load_const_atomic(&pi->serial, memory_order_relaxed);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800205 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
Raman Tennetib481a2e2019-11-12 20:41:55 +0000213 char value_buf[PROP_VALUE_MAX];
214 uint32_t serial = ReadMutablePropertyValue(pi, value_buf);
215 callback(cookie, pi->name, value_buf, serial);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800216}
217
Tom Cherrye275d6d2017-12-11 23:31:33 -0800218int SystemProperties::Get(const char* name, char* value) {
219 const prop_info* pi = Find(name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800220
Yi Kong32bc0fc2018-08-02 17:31:13 -0700221 if (pi != nullptr) {
Tom Cherrye275d6d2017-12-11 23:31:33 -0800222 return Read(pi, nullptr, value);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800223 } else {
224 value[0] = 0;
225 return 0;
226 }
227}
228
Tom Cherrye275d6d2017-12-11 23:31:33 -0800229int SystemProperties::Update(prop_info* pi, const char* value, unsigned int len) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800230 if (len >= PROP_VALUE_MAX) {
231 return -1;
232 }
233
Tom Cherrye275d6d2017-12-11 23:31:33 -0800234 if (!initialized_) {
Tom Cherryf76bbf52017-11-08 14:01:00 -0800235 return -1;
236 }
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800237
Raman Tennetib481a2e2019-11-12 20:41:55 +0000238 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);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800245 return -1;
246 }
247
248 uint32_t serial = atomic_load_explicit(&pi->serial, memory_order_relaxed);
Raman Tennetib481a2e2019-11-12 20:41:55 +0000249 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);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800257 serial |= 1;
258 atomic_store_explicit(&pi->serial, serial, memory_order_relaxed);
Raman Tennetide39d922019-11-12 18:24:06 +0000259 strlcpy(pi->value, value, len + 1);
Raman Tennetib481a2e2019-11-12 20:41:55 +0000260 // 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,
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800267 memory_order_release);
Raman Tennetib481a2e2019-11-12 20:41:55 +0000268 __futex_wake(serial_pa->serial(), INT32_MAX);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800269
270 return 0;
271}
272
Tom Cherrye275d6d2017-12-11 23:31:33 -0800273int SystemProperties::Add(const char* name, unsigned int namelen, const char* value,
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800274 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
Tom Cherrye275d6d2017-12-11 23:31:33 -0800283 if (!initialized_) {
Tom Cherryf76bbf52017-11-08 14:01:00 -0800284 return -1;
285 }
286
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800287 prop_area* serial_pa = contexts_->GetSerialPropArea();
Tom Cherryf76bbf52017-11-08 14:01:00 -0800288 if (serial_pa == nullptr) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800289 return -1;
290 }
291
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800292 prop_area* pa = contexts_->GetPropAreaForName(name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800293 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.
Tom Cherryf76bbf52017-11-08 14:01:00 -0800305 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);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800309 return 0;
310}
311
Tom Cherrye275d6d2017-12-11 23:31:33 -0800312uint32_t SystemProperties::WaitAny(uint32_t old_serial) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800313 uint32_t new_serial;
Tom Cherrye275d6d2017-12-11 23:31:33 -0800314 Wait(nullptr, old_serial, &new_serial, nullptr);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800315 return new_serial;
316}
317
Tom Cherrye275d6d2017-12-11 23:31:33 -0800318bool SystemProperties::Wait(const prop_info* pi, uint32_t old_serial, uint32_t* new_serial_ptr,
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800319 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) {
Tom Cherrye275d6d2017-12-11 23:31:33 -0800323 if (!initialized_) {
Tom Cherryf76bbf52017-11-08 14:01:00 -0800324 return -1;
325 }
326
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800327 prop_area* serial_pa = contexts_->GetSerialPropArea();
Tom Cherryf76bbf52017-11-08 14:01:00 -0800328 if (serial_pa == nullptr) {
329 return -1;
330 }
331
332 serial_ptr = serial_pa->serial();
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800333 } 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
Tom Cherrye275d6d2017-12-11 23:31:33 -0800350const prop_info* SystemProperties::FindNth(unsigned n) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800351 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);
Tom Cherrye275d6d2017-12-11 23:31:33 -0800363 Foreach(find_nth::fn, &state);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800364 return state.result;
365}
366
Tom Cherrye275d6d2017-12-11 23:31:33 -0800367int SystemProperties::Foreach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) {
368 if (!initialized_) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800369 return -1;
370 }
371
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800372 contexts_->ForEach(propfn, cookie);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800373
374 return 0;
375}