blob: 27204553dedf35f945414f4a0de80ed99ab2afa9 [file] [log] [blame]
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001/*
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 */
Tom Cherry49a309f2015-09-23 16:09:47 -070028#include <ctype.h>
Narayan Kamathc9ae21a2014-02-19 17:59:05 +000029#include <errno.h>
Narayan Kamathc9ae21a2014-02-19 17:59:05 +000030#include <fcntl.h>
Tom Cherry49a309f2015-09-23 16:09:47 -070031#include <poll.h>
32#include <stdatomic.h>
Narayan Kamathc9ae21a2014-02-19 17:59:05 +000033#include <stdbool.h>
Tom Cherry49a309f2015-09-23 16:09:47 -070034#include <stddef.h>
35#include <stdint.h>
36#include <stdio.h>
37#include <stdlib.h>
Narayan Kamathc9ae21a2014-02-19 17:59:05 +000038#include <string.h>
Tom Cherry49a309f2015-09-23 16:09:47 -070039#include <unistd.h>
40#include <new>
Narayan Kamathc9ae21a2014-02-19 17:59:05 +000041
Tom Cherry49a309f2015-09-23 16:09:47 -070042#include <linux/xattr.h>
43#include <netinet/in.h>
Narayan Kamathc9ae21a2014-02-19 17:59:05 +000044#include <sys/mman.h>
Narayan Kamathc9ae21a2014-02-19 17:59:05 +000045#include <sys/select.h>
Tom Cherry49a309f2015-09-23 16:09:47 -070046#include <sys/socket.h>
Narayan Kamathc9ae21a2014-02-19 17:59:05 +000047#include <sys/stat.h>
48#include <sys/types.h>
Tom Cherry49a309f2015-09-23 16:09:47 -070049#include <sys/un.h>
50#include <sys/xattr.h>
Narayan Kamathc9ae21a2014-02-19 17:59:05 +000051
52#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
53#include <sys/_system_properties.h>
54#include <sys/system_properties.h>
55
Elliott Hughesd5ed63a2014-05-21 18:27:40 -070056#include "private/bionic_futex.h"
Tom Cherry49a309f2015-09-23 16:09:47 -070057#include "private/bionic_lock.h"
Elliott Hughes8eac9af2014-05-09 19:12:08 -070058#include "private/bionic_macros.h"
Tom Cherry49a309f2015-09-23 16:09:47 -070059#include "private/libc_logging.h"
Narayan Kamathc9ae21a2014-02-19 17:59:05 +000060
Narayan Kamathc9ae21a2014-02-19 17:59:05 +000061static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME;
62
63
64/*
65 * Properties are stored in a hybrid trie/binary tree structure.
66 * Each property's name is delimited at '.' characters, and the tokens are put
67 * into a trie structure. Siblings at each level of the trie are stored in a
68 * binary tree. For instance, "ro.secure"="1" could be stored as follows:
69 *
70 * +-----+ children +----+ children +--------+
71 * | |-------------->| ro |-------------->| secure |
72 * +-----+ +----+ +--------+
73 * / \ / |
74 * left / \ right left / | prop +===========+
75 * v v v +-------->| ro.secure |
76 * +-----+ +-----+ +-----+ +-----------+
77 * | net | | sys | | com | | 1 |
78 * +-----+ +-----+ +-----+ +===========+
79 */
80
81// Represents a node in the trie.
82struct prop_bt {
83 uint8_t namelen;
84 uint8_t reserved[3];
85
Yabin Cuib8ce4742015-02-10 21:35:56 -080086 // The property trie is updated only by the init process (single threaded) which provides
87 // property service. And it can be read by multiple threads at the same time.
88 // As the property trie is not protected by locks, we use atomic_uint_least32_t types for the
89 // left, right, children "pointers" in the trie node. To make sure readers who see the
90 // change of "pointers" can also notice the change of prop_bt structure contents pointed by
91 // the "pointers", we always use release-consume ordering pair when accessing these "pointers".
92
93 // prop "points" to prop_info structure if there is a propery associated with the trie node.
94 // Its situation is similar to the left, right, children "pointers". So we use
95 // atomic_uint_least32_t and release-consume ordering to protect it as well.
96
Hans Boehm30214b92014-07-31 15:53:22 -070097 // We should also avoid rereading these fields redundantly, since not
98 // all processor implementations ensure that multiple loads from the
99 // same field are carried out in the right order.
Yabin Cuib8ce4742015-02-10 21:35:56 -0800100 atomic_uint_least32_t prop;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000101
Yabin Cuib8ce4742015-02-10 21:35:56 -0800102 atomic_uint_least32_t left;
103 atomic_uint_least32_t right;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000104
Yabin Cuib8ce4742015-02-10 21:35:56 -0800105 atomic_uint_least32_t children;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000106
107 char name[0];
108
109 prop_bt(const char *name, const uint8_t name_length) {
110 this->namelen = name_length;
111 memcpy(this->name, name, name_length);
112 this->name[name_length] = '\0';
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000113 }
114
115private:
Elliott Hughes8eac9af2014-05-09 19:12:08 -0700116 DISALLOW_COPY_AND_ASSIGN(prop_bt);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000117};
118
Tom Cherry926ebe12015-09-23 15:34:40 -0700119class prop_area {
120public:
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000121
122 prop_area(const uint32_t magic, const uint32_t version) :
Tom Cherry926ebe12015-09-23 15:34:40 -0700123 magic_(magic), version_(version) {
124 atomic_init(&serial_, 0);
125 memset(reserved_, 0, sizeof(reserved_));
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000126 // Allocate enough space for the root node.
Tom Cherry926ebe12015-09-23 15:34:40 -0700127 bytes_used_ = sizeof(prop_bt);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000128 }
129
Tom Cherry926ebe12015-09-23 15:34:40 -0700130 const prop_info *find(const char *name);
131 bool add(const char *name, unsigned int namelen,
132 const char *value, unsigned int valuelen);
133
134 bool foreach(void (*propfn)(const prop_info *pi, void *cookie), void *cookie);
135
136 atomic_uint_least32_t *serial() { return &serial_; }
137 uint32_t magic() const { return magic_; }
138 uint32_t version() const { return version_; }
139
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000140private:
Tom Cherry926ebe12015-09-23 15:34:40 -0700141 void *allocate_obj(const size_t size, uint_least32_t *const off);
142 prop_bt *new_prop_bt(const char *name, uint8_t namelen, uint_least32_t *const off);
143 prop_info *new_prop_info(const char *name, uint8_t namelen,
144 const char *value, uint8_t valuelen,
145 uint_least32_t *const off);
146 void *to_prop_obj(uint_least32_t off);
147 prop_bt *to_prop_bt(atomic_uint_least32_t *off_p);
148 prop_info *to_prop_info(atomic_uint_least32_t *off_p);
149
150 prop_bt *root_node();
151
152 prop_bt *find_prop_bt(prop_bt *const bt, const char *name,
153 uint8_t namelen, bool alloc_if_needed);
154
155 const prop_info *find_property(prop_bt *const trie, const char *name,
156 uint8_t namelen, const char *value,
157 uint8_t valuelen, bool alloc_if_needed);
158
159 bool foreach_property(prop_bt *const trie,
160 void (*propfn)(const prop_info *pi, void *cookie),
161 void *cookie);
162
163 uint32_t bytes_used_;
164 atomic_uint_least32_t serial_;
165 uint32_t magic_;
166 uint32_t version_;
167 uint32_t reserved_[28];
168 char data_[0];
169
Elliott Hughes8eac9af2014-05-09 19:12:08 -0700170 DISALLOW_COPY_AND_ASSIGN(prop_area);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000171};
172
173struct prop_info {
Hans Boehm30214b92014-07-31 15:53:22 -0700174 atomic_uint_least32_t serial;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000175 char value[PROP_VALUE_MAX];
176 char name[0];
177
178 prop_info(const char *name, const uint8_t namelen, const char *value,
179 const uint8_t valuelen) {
180 memcpy(this->name, name, namelen);
181 this->name[namelen] = '\0';
Hans Boehm30214b92014-07-31 15:53:22 -0700182 atomic_init(&this->serial, valuelen << 24);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000183 memcpy(this->value, value, valuelen);
184 this->value[valuelen] = '\0';
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000185 }
186private:
Elliott Hughes8eac9af2014-05-09 19:12:08 -0700187 DISALLOW_COPY_AND_ASSIGN(prop_info);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000188};
189
190struct find_nth_cookie {
191 uint32_t count;
192 const uint32_t n;
193 const prop_info *pi;
194
195 find_nth_cookie(uint32_t n) : count(0), n(n), pi(NULL) {
196 }
197};
198
Tom Cherry49a309f2015-09-23 16:09:47 -0700199static char property_filename[PROP_FILENAME_MAX] = PROP_FILENAME;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000200static bool compat_mode = false;
201static size_t pa_data_size;
202static size_t pa_size;
Tom Cherryb4171692015-12-09 15:48:15 -0800203static bool initialized = false;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000204
205// NOTE: This isn't static because system_properties_compat.c
206// requires it.
207prop_area *__system_property_area__ = NULL;
208
209static int get_fd_from_env(void)
210{
211 // This environment variable consistes of two decimal integer
212 // values separated by a ",". The first value is a file descriptor
213 // and the second is the size of the system properties area. The
214 // size is currently unused.
215 char *env = getenv("ANDROID_PROPERTY_WORKSPACE");
216
217 if (!env) {
218 return -1;
219 }
220
221 return atoi(env);
222}
223
Tom Cherry49a309f2015-09-23 16:09:47 -0700224static prop_area* map_prop_area_rw(const char* filename, const char* context,
225 bool* fsetxattr_failed) {
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000226 /* dev is a tmpfs that we can use to carve a shared workspace
227 * out of, so let's do that...
228 */
Tom Cherry49a309f2015-09-23 16:09:47 -0700229 const int fd = open(filename, O_RDWR | O_CREAT | O_NOFOLLOW | O_CLOEXEC | O_EXCL, 0444);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000230
231 if (fd < 0) {
232 if (errno == EACCES) {
233 /* for consistency with the case where the process has already
234 * mapped the page in and segfaults when trying to write to it
235 */
236 abort();
237 }
Tom Cherry49a309f2015-09-23 16:09:47 -0700238 return nullptr;
239 }
240
241 if (context) {
242 if (fsetxattr(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1, 0) != 0) {
243 __libc_format_log(ANDROID_LOG_ERROR, "libc",
244 "fsetxattr failed to set context (%s) for \"%s\"", context, filename);
245 /*
246 * fsetxattr() will fail during system properties tests due to selinux policy.
247 * We do not want to create a custom policy for the tester, so we will continue in
248 * this function but set a flag that an error has occurred.
249 * Init, which is the only daemon that should ever call this function will abort
250 * when this error occurs.
251 * Otherwise, the tester will ignore it and continue, albeit without any selinux
252 * property separation.
253 */
254 if (fsetxattr_failed) {
255 *fsetxattr_failed = true;
256 }
257 }
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000258 }
259
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000260 if (ftruncate(fd, PA_SIZE) < 0) {
261 close(fd);
Tom Cherry49a309f2015-09-23 16:09:47 -0700262 return nullptr;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000263 }
264
265 pa_size = PA_SIZE;
266 pa_data_size = pa_size - sizeof(prop_area);
267 compat_mode = false;
268
269 void *const memory_area = mmap(NULL, pa_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
270 if (memory_area == MAP_FAILED) {
271 close(fd);
Tom Cherry49a309f2015-09-23 16:09:47 -0700272 return nullptr;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000273 }
274
275 prop_area *pa = new(memory_area) prop_area(PROP_AREA_MAGIC, PROP_AREA_VERSION);
276
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000277 close(fd);
Tom Cherry49a309f2015-09-23 16:09:47 -0700278 return pa;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000279}
280
Tom Cherry49a309f2015-09-23 16:09:47 -0700281static prop_area* map_fd_ro(const int fd) {
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000282 struct stat fd_stat;
283 if (fstat(fd, &fd_stat) < 0) {
Tom Cherry49a309f2015-09-23 16:09:47 -0700284 return nullptr;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000285 }
286
287 if ((fd_stat.st_uid != 0)
288 || (fd_stat.st_gid != 0)
289 || ((fd_stat.st_mode & (S_IWGRP | S_IWOTH)) != 0)
Narayan Kamath37e95702014-02-24 11:05:02 +0000290 || (fd_stat.st_size < static_cast<off_t>(sizeof(prop_area))) ) {
Tom Cherry49a309f2015-09-23 16:09:47 -0700291 return nullptr;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000292 }
293
294 pa_size = fd_stat.st_size;
295 pa_data_size = pa_size - sizeof(prop_area);
296
297 void* const map_result = mmap(NULL, pa_size, PROT_READ, MAP_SHARED, fd, 0);
298 if (map_result == MAP_FAILED) {
Tom Cherry49a309f2015-09-23 16:09:47 -0700299 return nullptr;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000300 }
301
302 prop_area* pa = reinterpret_cast<prop_area*>(map_result);
Tom Cherry926ebe12015-09-23 15:34:40 -0700303 if ((pa->magic() != PROP_AREA_MAGIC) ||
304 (pa->version() != PROP_AREA_VERSION &&
305 pa->version() != PROP_AREA_VERSION_COMPAT)) {
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000306 munmap(pa, pa_size);
Tom Cherry49a309f2015-09-23 16:09:47 -0700307 return nullptr;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000308 }
309
Tom Cherry926ebe12015-09-23 15:34:40 -0700310 if (pa->version() == PROP_AREA_VERSION_COMPAT) {
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000311 compat_mode = true;
312 }
313
Tom Cherry49a309f2015-09-23 16:09:47 -0700314 return pa;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000315}
316
Tom Cherry49a309f2015-09-23 16:09:47 -0700317static prop_area* map_prop_area(const char* filename, bool is_legacy) {
318 int fd = open(filename, O_CLOEXEC | O_NOFOLLOW | O_RDONLY);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000319 bool close_fd = true;
Tom Cherry49a309f2015-09-23 16:09:47 -0700320 if (fd == -1 && errno == ENOENT && is_legacy) {
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000321 /*
322 * For backwards compatibility, if the file doesn't
323 * exist, we use the environment to get the file descriptor.
324 * For security reasons, we only use this backup if the kernel
325 * returns ENOENT. We don't want to use the backup if the kernel
326 * returns other errors such as ENOMEM or ENFILE, since it
327 * might be possible for an external program to trigger this
328 * condition.
Tom Cherry49a309f2015-09-23 16:09:47 -0700329 * Only do this for the legacy prop file, secured prop files
330 * do not have a backup
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000331 */
332 fd = get_fd_from_env();
333 close_fd = false;
334 }
335
336 if (fd < 0) {
Tom Cherry49a309f2015-09-23 16:09:47 -0700337 return nullptr;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000338 }
339
Tom Cherry49a309f2015-09-23 16:09:47 -0700340 prop_area* map_result = map_fd_ro(fd);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000341 if (close_fd) {
342 close(fd);
343 }
344
345 return map_result;
346}
347
Tom Cherry926ebe12015-09-23 15:34:40 -0700348void *prop_area::allocate_obj(const size_t size, uint_least32_t *const off)
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000349{
Yabin Cuib8ce4742015-02-10 21:35:56 -0800350 const size_t aligned = BIONIC_ALIGN(size, sizeof(uint_least32_t));
Tom Cherry926ebe12015-09-23 15:34:40 -0700351 if (bytes_used_ + aligned > pa_data_size) {
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000352 return NULL;
353 }
354
Tom Cherry926ebe12015-09-23 15:34:40 -0700355 *off = bytes_used_;
356 bytes_used_ += aligned;
357 return data_ + *off;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000358}
359
Tom Cherry926ebe12015-09-23 15:34:40 -0700360prop_bt *prop_area::new_prop_bt(const char *name, uint8_t namelen, uint_least32_t *const off)
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000361{
Yabin Cuib8ce4742015-02-10 21:35:56 -0800362 uint_least32_t new_offset;
363 void *const p = allocate_obj(sizeof(prop_bt) + namelen + 1, &new_offset);
364 if (p != NULL) {
365 prop_bt* bt = new(p) prop_bt(name, namelen);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000366 *off = new_offset;
367 return bt;
368 }
369
370 return NULL;
371}
372
Tom Cherry926ebe12015-09-23 15:34:40 -0700373prop_info *prop_area::new_prop_info(const char *name, uint8_t namelen,
Yabin Cuib8ce4742015-02-10 21:35:56 -0800374 const char *value, uint8_t valuelen, uint_least32_t *const off)
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000375{
Yabin Cuib8ce4742015-02-10 21:35:56 -0800376 uint_least32_t new_offset;
377 void* const p = allocate_obj(sizeof(prop_info) + namelen + 1, &new_offset);
378 if (p != NULL) {
379 prop_info* info = new(p) prop_info(name, namelen, value, valuelen);
380 *off = new_offset;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000381 return info;
382 }
383
384 return NULL;
385}
386
Tom Cherry926ebe12015-09-23 15:34:40 -0700387void *prop_area::to_prop_obj(uint_least32_t off)
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000388{
389 if (off > pa_data_size)
390 return NULL;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000391
Tom Cherry926ebe12015-09-23 15:34:40 -0700392 return (data_ + off);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000393}
394
Tom Cherry926ebe12015-09-23 15:34:40 -0700395inline prop_bt *prop_area::to_prop_bt(atomic_uint_least32_t* off_p) {
Yabin Cuib8ce4742015-02-10 21:35:56 -0800396 uint_least32_t off = atomic_load_explicit(off_p, memory_order_consume);
397 return reinterpret_cast<prop_bt*>(to_prop_obj(off));
398}
399
Tom Cherry926ebe12015-09-23 15:34:40 -0700400inline prop_info *prop_area::to_prop_info(atomic_uint_least32_t* off_p) {
Yabin Cuib8ce4742015-02-10 21:35:56 -0800401 uint_least32_t off = atomic_load_explicit(off_p, memory_order_consume);
402 return reinterpret_cast<prop_info*>(to_prop_obj(off));
403}
404
Tom Cherry926ebe12015-09-23 15:34:40 -0700405inline prop_bt *prop_area::root_node()
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000406{
407 return reinterpret_cast<prop_bt*>(to_prop_obj(0));
408}
409
410static int cmp_prop_name(const char *one, uint8_t one_len, const char *two,
411 uint8_t two_len)
412{
413 if (one_len < two_len)
414 return -1;
415 else if (one_len > two_len)
416 return 1;
417 else
418 return strncmp(one, two, one_len);
419}
420
Tom Cherry926ebe12015-09-23 15:34:40 -0700421prop_bt *prop_area::find_prop_bt(prop_bt *const bt, const char *name,
422 uint8_t namelen, bool alloc_if_needed)
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000423{
424
425 prop_bt* current = bt;
426 while (true) {
427 if (!current) {
428 return NULL;
429 }
430
431 const int ret = cmp_prop_name(name, namelen, current->name, current->namelen);
432 if (ret == 0) {
433 return current;
434 }
435
436 if (ret < 0) {
Yabin Cuib8ce4742015-02-10 21:35:56 -0800437 uint_least32_t left_offset = atomic_load_explicit(&current->left, memory_order_relaxed);
438 if (left_offset != 0) {
439 current = to_prop_bt(&current->left);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000440 } else {
441 if (!alloc_if_needed) {
442 return NULL;
443 }
444
Yabin Cuib8ce4742015-02-10 21:35:56 -0800445 uint_least32_t new_offset;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000446 prop_bt* new_bt = new_prop_bt(name, namelen, &new_offset);
447 if (new_bt) {
Yabin Cuib8ce4742015-02-10 21:35:56 -0800448 atomic_store_explicit(&current->left, new_offset, memory_order_release);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000449 }
450 return new_bt;
451 }
452 } else {
Yabin Cuib8ce4742015-02-10 21:35:56 -0800453 uint_least32_t right_offset = atomic_load_explicit(&current->right, memory_order_relaxed);
454 if (right_offset != 0) {
455 current = to_prop_bt(&current->right);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000456 } else {
457 if (!alloc_if_needed) {
458 return NULL;
459 }
460
Yabin Cuib8ce4742015-02-10 21:35:56 -0800461 uint_least32_t new_offset;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000462 prop_bt* new_bt = new_prop_bt(name, namelen, &new_offset);
463 if (new_bt) {
Yabin Cuib8ce4742015-02-10 21:35:56 -0800464 atomic_store_explicit(&current->right, new_offset, memory_order_release);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000465 }
466 return new_bt;
467 }
468 }
469 }
470}
471
Tom Cherry926ebe12015-09-23 15:34:40 -0700472const prop_info *prop_area::find_property(prop_bt *const trie, const char *name,
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000473 uint8_t namelen, const char *value, uint8_t valuelen,
474 bool alloc_if_needed)
475{
476 if (!trie) return NULL;
477
478 const char *remaining_name = name;
479 prop_bt* current = trie;
480 while (true) {
481 const char *sep = strchr(remaining_name, '.');
482 const bool want_subtree = (sep != NULL);
483 const uint8_t substr_size = (want_subtree) ?
484 sep - remaining_name : strlen(remaining_name);
485
486 if (!substr_size) {
487 return NULL;
488 }
489
490 prop_bt* root = NULL;
Yabin Cuib8ce4742015-02-10 21:35:56 -0800491 uint_least32_t children_offset = atomic_load_explicit(&current->children, memory_order_relaxed);
492 if (children_offset != 0) {
493 root = to_prop_bt(&current->children);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000494 } else if (alloc_if_needed) {
Yabin Cuib8ce4742015-02-10 21:35:56 -0800495 uint_least32_t new_offset;
496 root = new_prop_bt(remaining_name, substr_size, &new_offset);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000497 if (root) {
Yabin Cuib8ce4742015-02-10 21:35:56 -0800498 atomic_store_explicit(&current->children, new_offset, memory_order_release);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000499 }
500 }
501
502 if (!root) {
503 return NULL;
504 }
505
506 current = find_prop_bt(root, remaining_name, substr_size, alloc_if_needed);
507 if (!current) {
508 return NULL;
509 }
510
511 if (!want_subtree)
512 break;
513
514 remaining_name = sep + 1;
515 }
516
Yabin Cuib8ce4742015-02-10 21:35:56 -0800517 uint_least32_t prop_offset = atomic_load_explicit(&current->prop, memory_order_relaxed);
518 if (prop_offset != 0) {
519 return to_prop_info(&current->prop);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000520 } else if (alloc_if_needed) {
Yabin Cuib8ce4742015-02-10 21:35:56 -0800521 uint_least32_t new_offset;
522 prop_info* new_info = new_prop_info(name, namelen, value, valuelen, &new_offset);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000523 if (new_info) {
Yabin Cuib8ce4742015-02-10 21:35:56 -0800524 atomic_store_explicit(&current->prop, new_offset, memory_order_release);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000525 }
526
527 return new_info;
528 } else {
529 return NULL;
530 }
531}
532
533static int send_prop_msg(const prop_msg *msg)
534{
Elliott Hughes0dc39f92014-09-22 17:43:09 -0700535 const int fd = socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
536 if (fd == -1) {
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000537 return -1;
538 }
539
540 const size_t namelen = strlen(property_service_socket);
541
542 sockaddr_un addr;
543 memset(&addr, 0, sizeof(addr));
544 strlcpy(addr.sun_path, property_service_socket, sizeof(addr.sun_path));
545 addr.sun_family = AF_LOCAL;
546 socklen_t alen = namelen + offsetof(sockaddr_un, sun_path) + 1;
547 if (TEMP_FAILURE_RETRY(connect(fd, reinterpret_cast<sockaddr*>(&addr), alen)) < 0) {
548 close(fd);
549 return -1;
550 }
551
552 const int num_bytes = TEMP_FAILURE_RETRY(send(fd, msg, sizeof(prop_msg), 0));
553
554 int result = -1;
555 if (num_bytes == sizeof(prop_msg)) {
556 // We successfully wrote to the property server but now we
557 // wait for the property server to finish its work. It
558 // acknowledges its completion by closing the socket so we
559 // poll here (on nothing), waiting for the socket to close.
560 // If you 'adb shell setprop foo bar' you'll see the POLLHUP
561 // once the socket closes. Out of paranoia we cap our poll
562 // at 250 ms.
563 pollfd pollfds[1];
564 pollfds[0].fd = fd;
565 pollfds[0].events = 0;
566 const int poll_result = TEMP_FAILURE_RETRY(poll(pollfds, 1, 250 /* ms */));
567 if (poll_result == 1 && (pollfds[0].revents & POLLHUP) != 0) {
568 result = 0;
569 } else {
570 // Ignore the timeout and treat it like a success anyway.
571 // The init process is single-threaded and its property
572 // service is sometimes slow to respond (perhaps it's off
573 // starting a child process or something) and thus this
574 // times out and the caller thinks it failed, even though
575 // it's still getting around to it. So we fake it here,
576 // mostly for ctl.* properties, but we do try and wait 250
577 // ms so callers who do read-after-write can reliably see
578 // what they've written. Most of the time.
579 // TODO: fix the system properties design.
580 result = 0;
581 }
582 }
583
584 close(fd);
585 return result;
586}
587
588static void find_nth_fn(const prop_info *pi, void *ptr)
589{
590 find_nth_cookie *cookie = reinterpret_cast<find_nth_cookie*>(ptr);
591
592 if (cookie->n == cookie->count)
593 cookie->pi = pi;
594
595 cookie->count++;
596}
597
Tom Cherry926ebe12015-09-23 15:34:40 -0700598bool prop_area::foreach_property(prop_bt *const trie,
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000599 void (*propfn)(const prop_info *pi, void *cookie), void *cookie)
600{
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000601 if (!trie)
Tom Cherry926ebe12015-09-23 15:34:40 -0700602 return false;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000603
Yabin Cuib8ce4742015-02-10 21:35:56 -0800604 uint_least32_t left_offset = atomic_load_explicit(&trie->left, memory_order_relaxed);
605 if (left_offset != 0) {
606 const int err = foreach_property(to_prop_bt(&trie->left), propfn, cookie);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000607 if (err < 0)
Tom Cherry926ebe12015-09-23 15:34:40 -0700608 return false;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000609 }
Yabin Cuib8ce4742015-02-10 21:35:56 -0800610 uint_least32_t prop_offset = atomic_load_explicit(&trie->prop, memory_order_relaxed);
611 if (prop_offset != 0) {
612 prop_info *info = to_prop_info(&trie->prop);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000613 if (!info)
Tom Cherry926ebe12015-09-23 15:34:40 -0700614 return false;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000615 propfn(info, cookie);
616 }
Yabin Cuib8ce4742015-02-10 21:35:56 -0800617 uint_least32_t children_offset = atomic_load_explicit(&trie->children, memory_order_relaxed);
618 if (children_offset != 0) {
619 const int err = foreach_property(to_prop_bt(&trie->children), propfn, cookie);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000620 if (err < 0)
Tom Cherry926ebe12015-09-23 15:34:40 -0700621 return false;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000622 }
Yabin Cuib8ce4742015-02-10 21:35:56 -0800623 uint_least32_t right_offset = atomic_load_explicit(&trie->right, memory_order_relaxed);
624 if (right_offset != 0) {
625 const int err = foreach_property(to_prop_bt(&trie->right), propfn, cookie);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000626 if (err < 0)
Tom Cherry926ebe12015-09-23 15:34:40 -0700627 return false;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000628 }
629
Tom Cherry926ebe12015-09-23 15:34:40 -0700630 return true;
631}
632
633const prop_info *prop_area::find(const char *name) {
634 return find_property(root_node(), name, strlen(name), nullptr, 0, false);
635}
636
637bool prop_area::add(const char *name, unsigned int namelen,
638 const char *value, unsigned int valuelen) {
639 return find_property(root_node(), name, namelen, value, valuelen, true);
640}
641
642bool prop_area::foreach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) {
643 return foreach_property(root_node(), propfn, cookie);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +0000644}
645
Tom Cherryb4171692015-12-09 15:48:15 -0800646class context_node {
647public:
648 context_node(context_node* next, const char* context, prop_area* pa)
649 : next(next), context_(strdup(context)), pa_(pa), no_access_(false) {
650 lock_.init(false);
Tom Cherry49a309f2015-09-23 16:09:47 -0700651 }
652 ~context_node() {
Tom Cherryb4171692015-12-09 15:48:15 -0800653 unmap();
654 free(context_);
Tom Cherry49a309f2015-09-23 16:09:47 -0700655 }
Tom Cherryb4171692015-12-09 15:48:15 -0800656 bool open(bool access_rw, bool* fsetxattr_failed);
657 bool check_access_and_open();
658 void reset_access();
659
660 const char* context() const { return context_; }
661 prop_area* pa() { return pa_; }
662
663 context_node* next;
664
665private:
666 bool check_access();
667 void unmap();
668
669 Lock lock_;
670 char* context_;
671 prop_area* pa_;
672 bool no_access_;
Tom Cherry49a309f2015-09-23 16:09:47 -0700673};
674
675struct prefix_node {
676 prefix_node(struct prefix_node* next, const char* prefix, context_node* context)
677 : prefix(strdup(prefix)), prefix_len(strlen(prefix)), context(context), next(next) {
678 }
679 ~prefix_node() {
680 free(prefix);
681 }
682 char* prefix;
683 const size_t prefix_len;
684 context_node* context;
685 struct prefix_node* next;
686};
687
688template <typename List, typename... Args>
689static inline void list_add(List** list, Args... args) {
690 *list = new List(*list, args...);
691}
692
693static void list_add_after_len(prefix_node** list, const char* prefix, context_node* context) {
694 size_t prefix_len = strlen(prefix);
695
696 auto next_list = list;
697
698 while (*next_list) {
699 if ((*next_list)->prefix_len < prefix_len || (*next_list)->prefix[0] == '*') {
700 list_add(next_list, prefix, context);
701 return;
702 }
703 next_list = &(*next_list)->next;
704 }
705 list_add(next_list, prefix, context);
706}
707
708template <typename List, typename Func>
709static void list_foreach(List* list, Func func) {
710 while (list) {
711 func(list);
712 list = list->next;
713 }
714}
715
716template <typename List, typename Func>
717static List* list_find(List* list, Func func) {
718 while (list) {
719 if (func(list)) {
720 return list;
721 }
722 list = list->next;
723 }
724 return nullptr;
725}
726
727template <typename List>
728static void list_free(List** list) {
729 while (*list) {
730 auto old_list = *list;
731 *list = old_list->next;
732 delete old_list;
733 }
734}
735
736static prefix_node* prefixes = nullptr;
737static context_node* contexts = nullptr;
738
739/*
740 * pthread_mutex_lock() calls into system_properties in the case of contention.
741 * This creates a risk of dead lock if any system_properties functions
742 * use pthread locks after system_property initialization.
743 *
744 * For this reason, the below three functions use a bionic Lock and static
745 * allocation of memory for each filename.
746 */
747
Tom Cherryb4171692015-12-09 15:48:15 -0800748bool context_node::open(bool access_rw, bool* fsetxattr_failed) {
749 lock_.lock();
750 if (pa_) {
751 lock_.unlock();
Tom Cherry49a309f2015-09-23 16:09:47 -0700752 return true;
753 }
754
755 char filename[PROP_FILENAME_MAX];
Tom Cherryb4171692015-12-09 15:48:15 -0800756 int len = snprintf(filename, sizeof(filename), "%s/%s", property_filename, context_);
Tom Cherry49a309f2015-09-23 16:09:47 -0700757 if (len < 0 || len > PROP_FILENAME_MAX) {
Tom Cherryb4171692015-12-09 15:48:15 -0800758 lock_.unlock();
Tom Cherry49a309f2015-09-23 16:09:47 -0700759 return false;
760 }
761
762 if (access_rw) {
Tom Cherryb4171692015-12-09 15:48:15 -0800763 pa_ = map_prop_area_rw(filename, context_, fsetxattr_failed);
Tom Cherry49a309f2015-09-23 16:09:47 -0700764 } else {
Tom Cherryb4171692015-12-09 15:48:15 -0800765 pa_ = map_prop_area(filename, false);
Tom Cherry49a309f2015-09-23 16:09:47 -0700766 }
Tom Cherryb4171692015-12-09 15:48:15 -0800767 lock_.unlock();
768 return pa_;
Tom Cherry49a309f2015-09-23 16:09:47 -0700769}
770
Tom Cherryb4171692015-12-09 15:48:15 -0800771bool context_node::check_access_and_open() {
772 if (!pa_ && !no_access_) {
773 if (!check_access() || !open(false, nullptr)) {
774 no_access_ = true;
775 }
776 }
777 return pa_;
778}
779
780void context_node::reset_access() {
781 if (!check_access()) {
782 unmap();
783 no_access_ = true;
784 } else {
785 no_access_ = false;
786 }
787}
788
789bool context_node::check_access() {
Tom Cherry49a309f2015-09-23 16:09:47 -0700790 char filename[PROP_FILENAME_MAX];
Tom Cherryb4171692015-12-09 15:48:15 -0800791 int len = snprintf(filename, sizeof(filename), "%s/%s", property_filename, context_);
Tom Cherry49a309f2015-09-23 16:09:47 -0700792 if (len < 0 || len > PROP_FILENAME_MAX) {
793 return false;
794 }
795
796 return access(filename, R_OK) == 0;
797}
798
Tom Cherryb4171692015-12-09 15:48:15 -0800799void context_node::unmap() {
800 if (!pa_) {
801 return;
802 }
803
804 munmap(pa_, pa_size);
805 if (pa_ == __system_property_area__) {
806 __system_property_area__ = nullptr;
807 }
808 pa_ = nullptr;
809}
810
Tom Cherry49a309f2015-09-23 16:09:47 -0700811static bool map_system_property_area(bool access_rw, bool* fsetxattr_failed) {
812 char filename[PROP_FILENAME_MAX];
813 int len = snprintf(filename, sizeof(filename), "%s/properties_serial", property_filename);
814 if (len < 0 || len > PROP_FILENAME_MAX) {
815 __system_property_area__ = nullptr;
816 return false;
817 }
818
819 if (access_rw) {
820 __system_property_area__ =
821 map_prop_area_rw(filename, "u:object_r:properties_serial:s0", fsetxattr_failed);
822 } else {
823 __system_property_area__ = map_prop_area(filename, false);
824 }
825 return __system_property_area__;
826}
827
828static prop_area* get_prop_area_for_name(const char* name) {
Tom Cherry845e24a2015-12-03 15:38:52 -0800829 auto entry = list_find(prefixes, [name](prefix_node* l) {
Tom Cherry49a309f2015-09-23 16:09:47 -0700830 return l->prefix[0] == '*' || !strncmp(l->prefix, name, l->prefix_len);
831 });
832 if (!entry) {
833 return nullptr;
834 }
835
836 auto cnode = entry->context;
Tom Cherryb4171692015-12-09 15:48:15 -0800837 if (!cnode->pa()) {
838 /*
839 * We explicitly do not check no_access_ in this case because unlike the
840 * case of foreach(), we want to generate an selinux audit for each
841 * non-permitted property access in this function.
842 */
843 cnode->open(false, nullptr);
Tom Cherry49a309f2015-09-23 16:09:47 -0700844 }
Tom Cherryb4171692015-12-09 15:48:15 -0800845 return cnode->pa();
Tom Cherry49a309f2015-09-23 16:09:47 -0700846}
847
848/*
849 * The below two functions are duplicated from label_support.c in libselinux.
850 * TODO: Find a location suitable for these functions such that both libc and
851 * libselinux can share a common source file.
852 */
853
854/*
855 * The read_spec_entries and read_spec_entry functions may be used to
856 * replace sscanf to read entries from spec files. The file and
857 * property services now use these.
858 */
859
860/* Read an entry from a spec file (e.g. file_contexts) */
861static inline int read_spec_entry(char **entry, char **ptr, int *len)
862{
863 *entry = NULL;
864 char *tmp_buf = NULL;
865
866 while (isspace(**ptr) && **ptr != '\0')
867 (*ptr)++;
868
869 tmp_buf = *ptr;
870 *len = 0;
871
872 while (!isspace(**ptr) && **ptr != '\0') {
873 (*ptr)++;
874 (*len)++;
875 }
876
877 if (*len) {
878 *entry = strndup(tmp_buf, *len);
879 if (!*entry)
880 return -1;
881 }
882
883 return 0;
884}
885
886/*
887 * line_buf - Buffer containing the spec entries .
888 * num_args - The number of spec parameter entries to process.
889 * ... - A 'char **spec_entry' for each parameter.
890 * returns - The number of items processed.
891 *
892 * This function calls read_spec_entry() to do the actual string processing.
893 */
894static int read_spec_entries(char *line_buf, int num_args, ...)
895{
896 char **spec_entry, *buf_p;
897 int len, rc, items, entry_len = 0;
898 va_list ap;
899
900 len = strlen(line_buf);
901 if (line_buf[len - 1] == '\n')
902 line_buf[len - 1] = '\0';
903 else
904 /* Handle case if line not \n terminated by bumping
905 * the len for the check below (as the line is NUL
906 * terminated by getline(3)) */
907 len++;
908
909 buf_p = line_buf;
910 while (isspace(*buf_p))
911 buf_p++;
912
913 /* Skip comment lines and empty lines. */
914 if (*buf_p == '#' || *buf_p == '\0')
915 return 0;
916
917 /* Process the spec file entries */
918 va_start(ap, num_args);
919
920 items = 0;
921 while (items < num_args) {
922 spec_entry = va_arg(ap, char **);
923
924 if (len - 1 == buf_p - line_buf) {
925 va_end(ap);
926 return items;
927 }
928
929 rc = read_spec_entry(spec_entry, &buf_p, &entry_len);
930 if (rc < 0) {
931 va_end(ap);
932 return rc;
933 }
934 if (entry_len)
935 items++;
936 }
937 va_end(ap);
938 return items;
939}
940
941static bool initialize_properties() {
Tom Cherry49a309f2015-09-23 16:09:47 -0700942 FILE* file = fopen("/property_contexts", "re");
943
944 if (!file) {
945 return false;
946 }
947
948 char* buffer = nullptr;
949 size_t line_len;
950 char* prop_prefix = nullptr;
951 char* context = nullptr;
952
953 while (getline(&buffer, &line_len, file) > 0) {
954 int items = read_spec_entries(buffer, 2, &prop_prefix, &context);
955 if (items <= 0) {
956 continue;
957 }
958 if (items == 1) {
959 free(prop_prefix);
960 continue;
961 }
Tom Cherry21eadee2015-12-04 15:53:25 -0800962 /*
963 * init uses ctl.* properties as an IPC mechanism and does not write them
964 * to a property file, therefore we do not need to create property files
965 * to store them.
966 */
967 if (!strncmp(prop_prefix, "ctl.", 4)) {
968 free(prop_prefix);
969 free(context);
970 continue;
971 }
Tom Cherry49a309f2015-09-23 16:09:47 -0700972
Tom Cherry845e24a2015-12-03 15:38:52 -0800973 auto old_context = list_find(
Tom Cherryb4171692015-12-09 15:48:15 -0800974 contexts, [context](context_node* l) { return !strcmp(l->context(), context); });
Tom Cherry49a309f2015-09-23 16:09:47 -0700975 if (old_context) {
976 list_add_after_len(&prefixes, prop_prefix, old_context);
977 } else {
978 list_add(&contexts, context, nullptr);
979 list_add_after_len(&prefixes, prop_prefix, contexts);
980 }
981 free(prop_prefix);
982 free(context);
983 }
984
985 free(buffer);
986 fclose(file);
987 return true;
988}
989
990static bool is_dir(const char* pathname) {
991 struct stat info;
992 if (stat(pathname, &info) == -1) {
993 return false;
994 }
995 return S_ISDIR(info.st_mode);
996}
997
Tom Cherryb4171692015-12-09 15:48:15 -0800998static void free_and_unmap_contexts() {
999 list_free(&prefixes);
1000 list_free(&contexts);
1001 if (__system_property_area__) {
1002 munmap(__system_property_area__, pa_size);
1003 __system_property_area__ = nullptr;
1004 }
1005}
1006
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001007int __system_properties_init()
1008{
Tom Cherryb4171692015-12-09 15:48:15 -08001009 if (initialized) {
1010 list_foreach(contexts, [](context_node* l) { l->reset_access(); });
1011 return 0;
1012 }
Tom Cherry49a309f2015-09-23 16:09:47 -07001013 if (is_dir(property_filename)) {
1014 if (!initialize_properties()) {
1015 return -1;
1016 }
1017 if (!map_system_property_area(false, nullptr)) {
Tom Cherryb4171692015-12-09 15:48:15 -08001018 free_and_unmap_contexts();
Tom Cherry49a309f2015-09-23 16:09:47 -07001019 return -1;
1020 }
1021 } else {
1022 __system_property_area__ = map_prop_area(property_filename, true);
1023 if (!__system_property_area__) {
1024 return -1;
1025 }
1026 list_add(&contexts, "legacy_system_prop_area", __system_property_area__);
1027 list_add_after_len(&prefixes, "*", contexts);
1028 }
Tom Cherryb4171692015-12-09 15:48:15 -08001029 initialized = true;
Tom Cherry49a309f2015-09-23 16:09:47 -07001030 return 0;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001031}
1032
1033int __system_property_set_filename(const char *filename)
1034{
1035 size_t len = strlen(filename);
1036 if (len >= sizeof(property_filename))
1037 return -1;
1038
1039 strcpy(property_filename, filename);
1040 return 0;
1041}
1042
1043int __system_property_area_init()
1044{
Tom Cherryb4171692015-12-09 15:48:15 -08001045 free_and_unmap_contexts();
Tom Cherry49a309f2015-09-23 16:09:47 -07001046 mkdir(property_filename, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
1047 if (!initialize_properties()) {
1048 return -1;
1049 }
Tom Cherryb4171692015-12-09 15:48:15 -08001050 bool open_failed = false;
Tom Cherry49a309f2015-09-23 16:09:47 -07001051 bool fsetxattr_failed = false;
Tom Cherryb4171692015-12-09 15:48:15 -08001052 list_foreach(contexts, [&fsetxattr_failed, &open_failed](context_node* l) {
1053 if (!l->open(true, &fsetxattr_failed)) {
1054 open_failed = true;
Tom Cherry49a309f2015-09-23 16:09:47 -07001055 }
1056 });
Tom Cherryb4171692015-12-09 15:48:15 -08001057 if (open_failed || !map_system_property_area(true, &fsetxattr_failed)) {
1058 free_and_unmap_contexts();
Tom Cherry49a309f2015-09-23 16:09:47 -07001059 return -1;
1060 }
Tom Cherryb4171692015-12-09 15:48:15 -08001061 initialized = true;
Tom Cherry49a309f2015-09-23 16:09:47 -07001062 return fsetxattr_failed ? -2 : 0;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001063}
1064
Mark Salyzynbfd65272015-04-24 09:31:32 -07001065unsigned int __system_property_area_serial()
1066{
1067 prop_area *pa = __system_property_area__;
1068 if (!pa) {
1069 return -1;
1070 }
1071 // Make sure this read fulfilled before __system_property_serial
Tom Cherry926ebe12015-09-23 15:34:40 -07001072 return atomic_load_explicit(pa->serial(), memory_order_acquire);
Mark Salyzynbfd65272015-04-24 09:31:32 -07001073}
1074
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001075const prop_info *__system_property_find(const char *name)
1076{
Tom Cherry6ed51c02015-12-04 11:34:42 -08001077 if (!__system_property_area__) {
1078 return nullptr;
1079 }
1080
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001081 if (__predict_false(compat_mode)) {
1082 return __system_property_find_compat(name);
1083 }
Tom Cherry926ebe12015-09-23 15:34:40 -07001084
Tom Cherry49a309f2015-09-23 16:09:47 -07001085 prop_area* pa = get_prop_area_for_name(name);
1086 if (!pa) {
1087 __libc_format_log(ANDROID_LOG_ERROR, "libc", "Access denied finding property \"%s\"", name);
Tom Cherry926ebe12015-09-23 15:34:40 -07001088 return nullptr;
1089 }
1090
Tom Cherry49a309f2015-09-23 16:09:47 -07001091 return pa->find(name);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001092}
1093
Hans Boehm1e8587a2014-08-19 14:07:55 -07001094// The C11 standard doesn't allow atomic loads from const fields,
1095// though C++11 does. Fudge it until standards get straightened out.
1096static inline uint_least32_t load_const_atomic(const atomic_uint_least32_t* s,
1097 memory_order mo) {
1098 atomic_uint_least32_t* non_const_s = const_cast<atomic_uint_least32_t*>(s);
1099 return atomic_load_explicit(non_const_s, mo);
1100}
1101
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001102int __system_property_read(const prop_info *pi, char *name, char *value)
1103{
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001104 if (__predict_false(compat_mode)) {
1105 return __system_property_read_compat(pi, name, value);
1106 }
1107
jiaguo879d3302014-03-13 17:39:58 +08001108 while (true) {
Hans Boehm30214b92014-07-31 15:53:22 -07001109 uint32_t serial = __system_property_serial(pi); // acquire semantics
jiaguo879d3302014-03-13 17:39:58 +08001110 size_t len = SERIAL_VALUE_LEN(serial);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001111 memcpy(value, pi->value, len + 1);
Hans Boehm30214b92014-07-31 15:53:22 -07001112 // TODO: Fix the synchronization scheme here.
1113 // There is no fully supported way to implement this kind
1114 // of synchronization in C++11, since the memcpy races with
1115 // updates to pi, and the data being accessed is not atomic.
1116 // The following fence is unintuitive, but would be the
1117 // correct one if memcpy used memory_order_relaxed atomic accesses.
1118 // In practice it seems unlikely that the generated code would
1119 // would be any different, so this should be OK.
1120 atomic_thread_fence(memory_order_acquire);
1121 if (serial ==
Hans Boehm1e8587a2014-08-19 14:07:55 -07001122 load_const_atomic(&(pi->serial), memory_order_relaxed)) {
jiaguo879d3302014-03-13 17:39:58 +08001123 if (name != 0) {
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001124 strcpy(name, pi->name);
1125 }
1126 return len;
1127 }
1128 }
1129}
1130
1131int __system_property_get(const char *name, char *value)
1132{
1133 const prop_info *pi = __system_property_find(name);
1134
1135 if (pi != 0) {
1136 return __system_property_read(pi, 0, value);
1137 } else {
1138 value[0] = 0;
1139 return 0;
1140 }
1141}
1142
1143int __system_property_set(const char *key, const char *value)
1144{
1145 if (key == 0) return -1;
1146 if (value == 0) value = "";
1147 if (strlen(key) >= PROP_NAME_MAX) return -1;
1148 if (strlen(value) >= PROP_VALUE_MAX) return -1;
1149
1150 prop_msg msg;
1151 memset(&msg, 0, sizeof msg);
1152 msg.cmd = PROP_MSG_SETPROP;
1153 strlcpy(msg.name, key, sizeof msg.name);
1154 strlcpy(msg.value, value, sizeof msg.value);
1155
1156 const int err = send_prop_msg(&msg);
1157 if (err < 0) {
1158 return err;
1159 }
1160
1161 return 0;
1162}
1163
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001164int __system_property_update(prop_info *pi, const char *value, unsigned int len)
1165{
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001166 if (len >= PROP_VALUE_MAX)
1167 return -1;
1168
Tom Cherry6ed51c02015-12-04 11:34:42 -08001169 prop_area* pa = __system_property_area__;
1170
1171 if (!pa) {
1172 return -1;
1173 }
1174
Hans Boehm30214b92014-07-31 15:53:22 -07001175 uint32_t serial = atomic_load_explicit(&pi->serial, memory_order_relaxed);
1176 serial |= 1;
1177 atomic_store_explicit(&pi->serial, serial, memory_order_relaxed);
1178 // The memcpy call here also races. Again pretend it
1179 // used memory_order_relaxed atomics, and use the analogous
1180 // counterintuitive fence.
1181 atomic_thread_fence(memory_order_release);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001182 memcpy(pi->value, value, len + 1);
Hans Boehm30214b92014-07-31 15:53:22 -07001183 atomic_store_explicit(
1184 &pi->serial,
1185 (len << 24) | ((serial + 1) & 0xffffff),
1186 memory_order_release);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001187 __futex_wake(&pi->serial, INT32_MAX);
1188
Hans Boehm30214b92014-07-31 15:53:22 -07001189 atomic_store_explicit(
Tom Cherry926ebe12015-09-23 15:34:40 -07001190 pa->serial(),
1191 atomic_load_explicit(pa->serial(), memory_order_relaxed) + 1,
Hans Boehm30214b92014-07-31 15:53:22 -07001192 memory_order_release);
Tom Cherry926ebe12015-09-23 15:34:40 -07001193 __futex_wake(pa->serial(), INT32_MAX);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001194
1195 return 0;
1196}
jiaguo879d3302014-03-13 17:39:58 +08001197
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001198int __system_property_add(const char *name, unsigned int namelen,
1199 const char *value, unsigned int valuelen)
1200{
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001201 if (namelen >= PROP_NAME_MAX)
1202 return -1;
1203 if (valuelen >= PROP_VALUE_MAX)
1204 return -1;
1205 if (namelen < 1)
1206 return -1;
1207
Tom Cherry6ed51c02015-12-04 11:34:42 -08001208 if (!__system_property_area__) {
1209 return -1;
1210 }
1211
Tom Cherry49a309f2015-09-23 16:09:47 -07001212 prop_area* pa = get_prop_area_for_name(name);
1213
1214 if (!pa) {
1215 __libc_format_log(ANDROID_LOG_ERROR, "libc", "Access denied adding property \"%s\"", name);
Tom Cherry926ebe12015-09-23 15:34:40 -07001216 return -1;
1217 }
1218
Tom Cherry49a309f2015-09-23 16:09:47 -07001219 bool ret = pa->add(name, namelen, value, valuelen);
Tom Cherry926ebe12015-09-23 15:34:40 -07001220 if (!ret)
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001221 return -1;
1222
Hans Boehm30214b92014-07-31 15:53:22 -07001223 // There is only a single mutator, but we want to make sure that
1224 // updates are visible to a reader waiting for the update.
1225 atomic_store_explicit(
Tom Cherry49a309f2015-09-23 16:09:47 -07001226 __system_property_area__->serial(),
1227 atomic_load_explicit(__system_property_area__->serial(), memory_order_relaxed) + 1,
Hans Boehm30214b92014-07-31 15:53:22 -07001228 memory_order_release);
Tom Cherry49a309f2015-09-23 16:09:47 -07001229 __futex_wake(__system_property_area__->serial(), INT32_MAX);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001230 return 0;
1231}
1232
Hans Boehm30214b92014-07-31 15:53:22 -07001233// Wait for non-locked serial, and retrieve it with acquire semantics.
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001234unsigned int __system_property_serial(const prop_info *pi)
1235{
Hans Boehm1e8587a2014-08-19 14:07:55 -07001236 uint32_t serial = load_const_atomic(&pi->serial, memory_order_acquire);
jiaguo879d3302014-03-13 17:39:58 +08001237 while (SERIAL_DIRTY(serial)) {
Hans Boehm30214b92014-07-31 15:53:22 -07001238 __futex_wait(const_cast<volatile void *>(
1239 reinterpret_cast<const void *>(&pi->serial)),
1240 serial, NULL);
Hans Boehm1e8587a2014-08-19 14:07:55 -07001241 serial = load_const_atomic(&pi->serial, memory_order_acquire);
jiaguo879d3302014-03-13 17:39:58 +08001242 }
1243 return serial;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001244}
1245
1246unsigned int __system_property_wait_any(unsigned int serial)
1247{
1248 prop_area *pa = __system_property_area__;
Hans Boehm30214b92014-07-31 15:53:22 -07001249 uint32_t my_serial;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001250
Tom Cherry6ed51c02015-12-04 11:34:42 -08001251 if (!pa) {
1252 return 0;
1253 }
1254
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001255 do {
Tom Cherry926ebe12015-09-23 15:34:40 -07001256 __futex_wait(pa->serial(), serial, NULL);
1257 my_serial = atomic_load_explicit(pa->serial(), memory_order_acquire);
Hans Boehm30214b92014-07-31 15:53:22 -07001258 } while (my_serial == serial);
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001259
Hans Boehm30214b92014-07-31 15:53:22 -07001260 return my_serial;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001261}
1262
1263const prop_info *__system_property_find_nth(unsigned n)
1264{
1265 find_nth_cookie cookie(n);
1266
1267 const int err = __system_property_foreach(find_nth_fn, &cookie);
1268 if (err < 0) {
1269 return NULL;
1270 }
1271
1272 return cookie.pi;
1273}
1274
1275int __system_property_foreach(void (*propfn)(const prop_info *pi, void *cookie),
1276 void *cookie)
1277{
Tom Cherry6ed51c02015-12-04 11:34:42 -08001278 if (!__system_property_area__) {
1279 return -1;
1280 }
1281
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001282 if (__predict_false(compat_mode)) {
1283 return __system_property_foreach_compat(propfn, cookie);
1284 }
1285
Tom Cherry845e24a2015-12-03 15:38:52 -08001286 list_foreach(contexts, [propfn, cookie](context_node* l) {
Tom Cherryb4171692015-12-09 15:48:15 -08001287 if (l->check_access_and_open()) {
1288 l->pa()->foreach(propfn, cookie);
Tom Cherry49a309f2015-09-23 16:09:47 -07001289 }
1290 });
1291 return 0;
Narayan Kamathc9ae21a2014-02-19 17:59:05 +00001292}