blob: ca8a68808ca739742f82dfdae85ef2c25247c4cc [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"
Adithya Rba1dcb42023-12-08 05:53:08 +053049#include "system_properties/prop_imitation_hooks.h"
Tom Cherryfd44b9f2017-11-08 14:01:00 -080050
51#define SERIAL_DIRTY(serial) ((serial)&1)
52#define SERIAL_VALUE_LEN(serial) ((serial) >> 24)
53
Tom Cherryfd44b9f2017-11-08 14:01:00 -080054static bool is_dir(const char* pathname) {
55 struct stat info;
56 if (stat(pathname, &info) == -1) {
57 return false;
58 }
59 return S_ISDIR(info.st_mode);
60}
61
Adithya Rba1dcb42023-12-08 05:53:08 +053062static PropImitationHooks pi_hooks;
63
Tom Cherrye275d6d2017-12-11 23:31:33 -080064bool SystemProperties::Init(const char* filename) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -080065 // This is called from __libc_init_common, and should leave errno at 0 (http://b/37248982).
66 ErrnoRestorer errno_restorer;
67
Tom Cherrye275d6d2017-12-11 23:31:33 -080068 if (initialized_) {
Tom Cherryee8e3dd2018-02-21 15:01:22 -080069 contexts_->ResetAccess();
Tom Cherrye275d6d2017-12-11 23:31:33 -080070 return true;
Tom Cherryfd44b9f2017-11-08 14:01:00 -080071 }
Tom Cherrye275d6d2017-12-11 23:31:33 -080072
Ryan Prichardd91285f2018-05-01 18:03:05 -070073 if (strlen(filename) >= PROP_FILENAME_MAX) {
Tom Cherrye275d6d2017-12-11 23:31:33 -080074 return false;
75 }
76 strcpy(property_filename_, filename);
77
78 if (is_dir(property_filename_)) {
Tom Cherry8be995b2017-12-14 01:57:37 +000079 if (access("/dev/__properties__/property_info", R_OK) == 0) {
Tom Cherryee8e3dd2018-02-21 15:01:22 -080080 contexts_ = new (contexts_data_) ContextsSerialized();
81 if (!contexts_->Initialize(false, property_filename_, nullptr)) {
Tom Cherrye275d6d2017-12-11 23:31:33 -080082 return false;
Tom Cherry8be995b2017-12-14 01:57:37 +000083 }
Tom Cherry8be995b2017-12-14 01:57:37 +000084 } else {
Tom Cherryee8e3dd2018-02-21 15:01:22 -080085 contexts_ = new (contexts_data_) ContextsSplit();
86 if (!contexts_->Initialize(false, property_filename_, nullptr)) {
Tom Cherrye275d6d2017-12-11 23:31:33 -080087 return false;
Tom Cherry8be995b2017-12-14 01:57:37 +000088 }
Tom Cherryfd44b9f2017-11-08 14:01:00 -080089 }
Tom Cherryfd44b9f2017-11-08 14:01:00 -080090 } else {
Tom Cherryee8e3dd2018-02-21 15:01:22 -080091 contexts_ = new (contexts_data_) ContextsPreSplit();
92 if (!contexts_->Initialize(false, property_filename_, nullptr)) {
Tom Cherrye275d6d2017-12-11 23:31:33 -080093 return false;
Tom Cherryfd44b9f2017-11-08 14:01:00 -080094 }
Tom Cherryfd44b9f2017-11-08 14:01:00 -080095 }
Tom Cherrye275d6d2017-12-11 23:31:33 -080096 initialized_ = true;
97 return true;
Tom Cherryfd44b9f2017-11-08 14:01:00 -080098}
99
Tom Cherrye275d6d2017-12-11 23:31:33 -0800100bool SystemProperties::AreaInit(const char* filename, bool* fsetxattr_failed) {
Ryan Prichardd91285f2018-05-01 18:03:05 -0700101 if (strlen(filename) >= PROP_FILENAME_MAX) {
Tom Cherrye275d6d2017-12-11 23:31:33 -0800102 return false;
103 }
104 strcpy(property_filename_, filename);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800105
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800106 contexts_ = new (contexts_data_) ContextsSerialized();
107 if (!contexts_->Initialize(true, property_filename_, fsetxattr_failed)) {
Tom Cherrye275d6d2017-12-11 23:31:33 -0800108 return false;
109 }
110 initialized_ = true;
111 return true;
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800112}
113
Tom Cherrye275d6d2017-12-11 23:31:33 -0800114uint32_t SystemProperties::AreaSerial() {
115 if (!initialized_) {
Tom Cherryf76bbf52017-11-08 14:01:00 -0800116 return -1;
117 }
118
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800119 prop_area* pa = contexts_->GetSerialPropArea();
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800120 if (!pa) {
121 return -1;
122 }
Tom Cherryf76bbf52017-11-08 14:01:00 -0800123
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800124 // Make sure this read fulfilled before __system_property_serial
125 return atomic_load_explicit(pa->serial(), memory_order_acquire);
126}
127
Tom Cherrye275d6d2017-12-11 23:31:33 -0800128const prop_info* SystemProperties::Find(const char* name) {
129 if (!initialized_) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800130 return nullptr;
131 }
132
Adithya Rba1dcb42023-12-08 05:53:08 +0530133 pi_hooks.OnFind(&name);
134
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800135 prop_area* pa = contexts_->GetPropAreaForName(name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800136 if (!pa) {
Tom Cherry8f11c5f2021-04-01 15:07:40 -0700137 async_safe_format_log(ANDROID_LOG_WARN, "libc", "Access denied finding property \"%s\"", name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800138 return nullptr;
139 }
140
141 return pa->find(name);
142}
143
144static bool is_read_only(const char* name) {
145 return strncmp(name, "ro.", 3) == 0;
146}
147
Raman Tennetib481a2e2019-11-12 20:41:55 +0000148uint32_t SystemProperties::ReadMutablePropertyValue(const prop_info* pi, char* value) {
149 // We assume the memcpy below gets serialized by the acquire fence.
150 uint32_t new_serial = load_const_atomic(&pi->serial, memory_order_acquire);
151 uint32_t serial;
152 unsigned int len;
153 for (;;) {
154 serial = new_serial;
155 len = SERIAL_VALUE_LEN(serial);
156 if (__predict_false(SERIAL_DIRTY(serial))) {
157 // See the comment in the prop_area constructor.
158 prop_area* pa = contexts_->GetPropAreaForName(pi->name);
159 memcpy(value, pa->dirty_backup_area(), len + 1);
160 } else {
161 memcpy(value, pi->value, len + 1);
162 }
Raman Tennetide39d922019-11-12 18:24:06 +0000163 atomic_thread_fence(memory_order_acquire);
Raman Tennetib481a2e2019-11-12 20:41:55 +0000164 new_serial = load_const_atomic(&pi->serial, memory_order_relaxed);
165 if (__predict_true(serial == new_serial)) {
166 break;
167 }
168 // We need another fence here because we want to ensure that the memcpy in the
169 // next iteration of the loop occurs after the load of new_serial above. We could
170 // get this guarantee by making the load_const_atomic of new_serial
171 // memory_order_acquire instead of memory_order_relaxed, but then we'd pay the
172 // penalty of the memory_order_acquire even in the overwhelmingly common case
173 // that the serial number didn't change.
174 atomic_thread_fence(memory_order_acquire);
175 }
176 return serial;
177}
178
179int SystemProperties::Read(const prop_info* pi, char* name, char* value) {
180 uint32_t serial = ReadMutablePropertyValue(pi, value);
181 if (name != nullptr) {
182 size_t namelen = strlcpy(name, pi->name, PROP_NAME_MAX);
183 if (namelen >= PROP_NAME_MAX) {
184 async_safe_format_log(ANDROID_LOG_ERROR, "libc",
185 "The property name length for \"%s\" is >= %d;"
186 " please use __system_property_read_callback"
187 " to read this property. (the name is truncated to \"%s\")",
188 pi->name, PROP_NAME_MAX - 1, name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800189 }
190 }
Raman Tennetib481a2e2019-11-12 20:41:55 +0000191 if (is_read_only(pi->name) && pi->is_long()) {
192 async_safe_format_log(
193 ANDROID_LOG_ERROR, "libc",
194 "The property \"%s\" has a value with length %zu that is too large for"
195 " __system_property_get()/__system_property_read(); use"
196 " __system_property_read_callback() instead.",
197 pi->name, strlen(pi->long_value()));
198 }
199 return SERIAL_VALUE_LEN(serial);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800200}
201
Tom Cherrye275d6d2017-12-11 23:31:33 -0800202void SystemProperties::ReadCallback(const prop_info* pi,
203 void (*callback)(void* cookie, const char* name,
204 const char* value, uint32_t serial),
205 void* cookie) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800206 // 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 +0000207 // change. We use relaxed memory order on the serial load for the same reason.
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800208 if (is_read_only(pi->name)) {
Raman Tennetib481a2e2019-11-12 20:41:55 +0000209 uint32_t serial = load_const_atomic(&pi->serial, memory_order_relaxed);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800210 if (pi->is_long()) {
211 callback(cookie, pi->name, pi->long_value(), serial);
212 } else {
213 callback(cookie, pi->name, pi->value, serial);
214 }
215 return;
216 }
217
Raman Tennetib481a2e2019-11-12 20:41:55 +0000218 char value_buf[PROP_VALUE_MAX];
219 uint32_t serial = ReadMutablePropertyValue(pi, value_buf);
220 callback(cookie, pi->name, value_buf, serial);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800221}
222
Tom Cherrye275d6d2017-12-11 23:31:33 -0800223int SystemProperties::Get(const char* name, char* value) {
224 const prop_info* pi = Find(name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800225
Yi Kong32bc0fc2018-08-02 17:31:13 -0700226 if (pi != nullptr) {
Tom Cherrye275d6d2017-12-11 23:31:33 -0800227 return Read(pi, nullptr, value);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800228 } else {
229 value[0] = 0;
230 return 0;
231 }
232}
233
Tom Cherrye275d6d2017-12-11 23:31:33 -0800234int SystemProperties::Update(prop_info* pi, const char* value, unsigned int len) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800235 if (len >= PROP_VALUE_MAX) {
236 return -1;
237 }
238
Tom Cherrye275d6d2017-12-11 23:31:33 -0800239 if (!initialized_) {
Tom Cherryf76bbf52017-11-08 14:01:00 -0800240 return -1;
241 }
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800242
Raman Tennetib481a2e2019-11-12 20:41:55 +0000243 prop_area* serial_pa = contexts_->GetSerialPropArea();
244 if (!serial_pa) {
245 return -1;
246 }
247 prop_area* pa = contexts_->GetPropAreaForName(pi->name);
248 if (__predict_false(!pa)) {
249 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Could not find area for \"%s\"", pi->name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800250 return -1;
251 }
252
253 uint32_t serial = atomic_load_explicit(&pi->serial, memory_order_relaxed);
Raman Tennetib481a2e2019-11-12 20:41:55 +0000254 unsigned int old_len = SERIAL_VALUE_LEN(serial);
255
256 // The contract with readers is that whenever the dirty bit is set, an undamaged copy
257 // of the pre-dirty value is available in the dirty backup area. The fence ensures
258 // that we publish our dirty area update before allowing readers to see a
259 // dirty serial.
260 memcpy(pa->dirty_backup_area(), pi->value, old_len + 1);
261 atomic_thread_fence(memory_order_release);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800262 serial |= 1;
263 atomic_store_explicit(&pi->serial, serial, memory_order_relaxed);
Raman Tennetide39d922019-11-12 18:24:06 +0000264 strlcpy(pi->value, value, len + 1);
Raman Tennetib481a2e2019-11-12 20:41:55 +0000265 // Now the primary value property area is up-to-date. Let readers know that they should
266 // look at the property value instead of the backup area.
267 atomic_thread_fence(memory_order_release);
268 atomic_store_explicit(&pi->serial, (len << 24) | ((serial + 1) & 0xffffff), memory_order_relaxed);
269 __futex_wake(&pi->serial, INT32_MAX); // Fence by side effect
270 atomic_store_explicit(serial_pa->serial(),
271 atomic_load_explicit(serial_pa->serial(), memory_order_relaxed) + 1,
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800272 memory_order_release);
Raman Tennetib481a2e2019-11-12 20:41:55 +0000273 __futex_wake(serial_pa->serial(), INT32_MAX);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800274
275 return 0;
276}
277
Tom Cherrye275d6d2017-12-11 23:31:33 -0800278int SystemProperties::Add(const char* name, unsigned int namelen, const char* value,
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800279 unsigned int valuelen) {
280 if (valuelen >= PROP_VALUE_MAX && !is_read_only(name)) {
281 return -1;
282 }
283
284 if (namelen < 1) {
285 return -1;
286 }
287
Tom Cherrye275d6d2017-12-11 23:31:33 -0800288 if (!initialized_) {
Tom Cherryf76bbf52017-11-08 14:01:00 -0800289 return -1;
290 }
291
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800292 prop_area* serial_pa = contexts_->GetSerialPropArea();
Tom Cherryf76bbf52017-11-08 14:01:00 -0800293 if (serial_pa == nullptr) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800294 return -1;
295 }
296
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800297 prop_area* pa = contexts_->GetPropAreaForName(name);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800298 if (!pa) {
299 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Access denied adding property \"%s\"", name);
300 return -1;
301 }
302
303 bool ret = pa->add(name, namelen, value, valuelen);
304 if (!ret) {
305 return -1;
306 }
307
308 // There is only a single mutator, but we want to make sure that
309 // updates are visible to a reader waiting for the update.
Tom Cherryf76bbf52017-11-08 14:01:00 -0800310 atomic_store_explicit(serial_pa->serial(),
311 atomic_load_explicit(serial_pa->serial(), memory_order_relaxed) + 1,
312 memory_order_release);
313 __futex_wake(serial_pa->serial(), INT32_MAX);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800314 return 0;
315}
316
Tom Cherrye275d6d2017-12-11 23:31:33 -0800317uint32_t SystemProperties::WaitAny(uint32_t old_serial) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800318 uint32_t new_serial;
Tom Cherrye275d6d2017-12-11 23:31:33 -0800319 Wait(nullptr, old_serial, &new_serial, nullptr);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800320 return new_serial;
321}
322
Tom Cherrye275d6d2017-12-11 23:31:33 -0800323bool SystemProperties::Wait(const prop_info* pi, uint32_t old_serial, uint32_t* new_serial_ptr,
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800324 const timespec* relative_timeout) {
325 // Are we waiting on the global serial or a specific serial?
326 atomic_uint_least32_t* serial_ptr;
327 if (pi == nullptr) {
Tom Cherrye275d6d2017-12-11 23:31:33 -0800328 if (!initialized_) {
Tom Cherryf76bbf52017-11-08 14:01:00 -0800329 return -1;
330 }
331
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800332 prop_area* serial_pa = contexts_->GetSerialPropArea();
Tom Cherryf76bbf52017-11-08 14:01:00 -0800333 if (serial_pa == nullptr) {
334 return -1;
335 }
336
337 serial_ptr = serial_pa->serial();
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800338 } else {
339 serial_ptr = const_cast<atomic_uint_least32_t*>(&pi->serial);
340 }
341
342 uint32_t new_serial;
343 do {
344 int rc;
345 if ((rc = __futex_wait(serial_ptr, old_serial, relative_timeout)) != 0 && rc == -ETIMEDOUT) {
346 return false;
347 }
348 new_serial = load_const_atomic(serial_ptr, memory_order_acquire);
349 } while (new_serial == old_serial);
350
351 *new_serial_ptr = new_serial;
352 return true;
353}
354
Tom Cherrye275d6d2017-12-11 23:31:33 -0800355const prop_info* SystemProperties::FindNth(unsigned n) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800356 struct find_nth {
357 const uint32_t sought;
358 uint32_t current;
359 const prop_info* result;
360
361 explicit find_nth(uint32_t n) : sought(n), current(0), result(nullptr) {
362 }
363 static void fn(const prop_info* pi, void* ptr) {
364 find_nth* self = reinterpret_cast<find_nth*>(ptr);
365 if (self->current++ == self->sought) self->result = pi;
366 }
367 } state(n);
Tom Cherrye275d6d2017-12-11 23:31:33 -0800368 Foreach(find_nth::fn, &state);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800369 return state.result;
370}
371
Tom Cherrye275d6d2017-12-11 23:31:33 -0800372int SystemProperties::Foreach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) {
373 if (!initialized_) {
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800374 return -1;
375 }
376
Tom Cherryee8e3dd2018-02-21 15:01:22 -0800377 contexts_->ForEach(propfn, cookie);
Tom Cherryfd44b9f2017-11-08 14:01:00 -0800378
379 return 0;
380}