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 #include <stdio.h> 29 #include <stdint.h> 30 #include <stdlib.h> 31 #include <unistd.h> 32 #include <stddef.h> 33 #include <errno.h> 34 #include <poll.h> 35 #include <fcntl.h> 36 #include <stdbool.h> 37 #include <string.h> 38 39 #include <sys/mman.h> 40 41 #include <sys/socket.h> 42 #include <sys/un.h> 43 #include <sys/select.h> 44 #include <sys/stat.h> 45 #include <sys/types.h> 46 #include <netinet/in.h> 47 #include <unistd.h> 48 49 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ 50 #include <sys/_system_properties.h> 51 52 #include <sys/atomics.h> 53 #include <bionic_atomic_inline.h> 54 55 #define ALIGN(x, a) (((x) + (a - 1)) & ~(a - 1)) 56 57 struct prop_area { 58 unsigned bytes_used; 59 unsigned volatile serial; 60 unsigned magic; 61 unsigned version; 62 unsigned reserved[28]; 63 char data[0]; 64 }; 65 66 typedef struct prop_area prop_area; 67 68 struct prop_info { 69 unsigned volatile serial; 70 char value[PROP_VALUE_MAX]; 71 char name[0]; 72 }; 73 74 typedef struct prop_info prop_info; 75 76 /* 77 * Properties are stored in a hybrid trie/binary tree structure. 78 * Each property's name is delimited at '.' characters, and the tokens are put 79 * into a trie structure. Siblings at each level of the trie are stored in a 80 * binary tree. For instance, "ro.secure"="1" could be stored as follows: 81 * 82 * +-----+ children +----+ children +--------+ 83 * | |-------------->| ro |-------------->| secure | 84 * +-----+ +----+ +--------+ 85 * / \ / | 86 * left / \ right left / | prop +===========+ 87 * v v v +-------->| ro.secure | 88 * +-----+ +-----+ +-----+ +-----------+ 89 * | net | | sys | | com | | 1 | 90 * +-----+ +-----+ +-----+ +===========+ 91 */ 92 93 typedef volatile uint32_t prop_off_t; 94 struct prop_bt { 95 uint8_t namelen; 96 uint8_t reserved[3]; 97 98 prop_off_t prop; 99 100 prop_off_t left; 101 prop_off_t right; 102 103 prop_off_t children; 104 105 char name[0]; 106 }; 107 108 typedef struct prop_bt prop_bt; 109 110 static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME; 111 static char property_filename[PATH_MAX] = PROP_FILENAME; 112 static bool compat_mode = false; 113 114 prop_area *__system_property_area__ = NULL; 115 116 size_t pa_data_size; 117 size_t pa_size; 118 119 static int get_fd_from_env(void) 120 { 121 char *env = getenv("ANDROID_PROPERTY_WORKSPACE"); 122 123 if (!env) { 124 return -1; 125 } 126 127 return atoi(env); 128 } 129 130 static int map_prop_area_rw() 131 { 132 prop_area *pa; 133 int fd; 134 int ret; 135 136 /* dev is a tmpfs that we can use to carve a shared workspace 137 * out of, so let's do that... 138 */ 139 fd = open(property_filename, O_RDWR | O_CREAT | O_NOFOLLOW | O_CLOEXEC | 140 O_EXCL, 0444); 141 if (fd < 0) { 142 if (errno == EACCES) { 143 /* for consistency with the case where the process has already 144 * mapped the page in and segfaults when trying to write to it 145 */ 146 abort(); 147 } 148 return -1; 149 } 150 151 ret = fcntl(fd, F_SETFD, FD_CLOEXEC); 152 if (ret < 0) 153 goto out; 154 155 if (ftruncate(fd, PA_SIZE) < 0) 156 goto out; 157 158 pa_size = PA_SIZE; 159 pa_data_size = pa_size - sizeof(prop_area); 160 compat_mode = false; 161 162 pa = mmap(NULL, pa_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 163 if(pa == MAP_FAILED) 164 goto out; 165 166 memset(pa, 0, pa_size); 167 pa->magic = PROP_AREA_MAGIC; 168 pa->version = PROP_AREA_VERSION; 169 /* reserve root node */ 170 pa->bytes_used = sizeof(prop_bt); 171 172 /* plug into the lib property services */ 173 __system_property_area__ = pa; 174 175 close(fd); 176 return 0; 177 178 out: 179 close(fd); 180 return -1; 181 } 182 183 int __system_property_set_filename(const char *filename) 184 { 185 size_t len = strlen(filename); 186 if (len >= sizeof(property_filename)) 187 return -1; 188 189 strcpy(property_filename, filename); 190 return 0; 191 } 192 193 int __system_property_area_init() 194 { 195 return map_prop_area_rw(); 196 } 197 198 static int map_prop_area() 199 { 200 bool fromFile = true; 201 int result = -1; 202 int fd; 203 int ret; 204 205 fd = open(property_filename, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); 206 if (fd >= 0) { 207 /* For old kernels that don't support O_CLOEXEC */ 208 ret = fcntl(fd, F_SETFD, FD_CLOEXEC); 209 if (ret < 0) 210 goto cleanup; 211 } 212 213 if ((fd < 0) && (errno == ENOENT)) { 214 /* 215 * For backwards compatibility, if the file doesn't 216 * exist, we use the environment to get the file descriptor. 217 * For security reasons, we only use this backup if the kernel 218 * returns ENOENT. We don't want to use the backup if the kernel 219 * returns other errors such as ENOMEM or ENFILE, since it 220 * might be possible for an external program to trigger this 221 * condition. 222 */ 223 fd = get_fd_from_env(); 224 fromFile = false; 225 } 226 227 if (fd < 0) { 228 return -1; 229 } 230 231 struct stat fd_stat; 232 if (fstat(fd, &fd_stat) < 0) { 233 goto cleanup; 234 } 235 236 if ((fd_stat.st_uid != 0) 237 || (fd_stat.st_gid != 0) 238 || ((fd_stat.st_mode & (S_IWGRP | S_IWOTH)) != 0) 239 || (fd_stat.st_size < sizeof(prop_area)) ) { 240 goto cleanup; 241 } 242 243 pa_size = fd_stat.st_size; 244 pa_data_size = pa_size - sizeof(prop_area); 245 prop_area *pa = mmap(NULL, pa_size, PROT_READ, MAP_SHARED, fd, 0); 246 247 if (pa == MAP_FAILED) { 248 goto cleanup; 249 } 250 251 if((pa->magic != PROP_AREA_MAGIC) || (pa->version != PROP_AREA_VERSION && 252 pa->version != PROP_AREA_VERSION_COMPAT)) { 253 munmap(pa, pa_size); 254 goto cleanup; 255 } 256 257 if (pa->version == PROP_AREA_VERSION_COMPAT) { 258 compat_mode = true; 259 } 260 261 result = 0; 262 263 __system_property_area__ = pa; 264 265 cleanup: 266 if (fromFile) { 267 close(fd); 268 } 269 270 return result; 271 } 272 273 int __system_properties_init() 274 { 275 return map_prop_area(); 276 } 277 278 static void *new_prop_obj(size_t size, prop_off_t *off) 279 { 280 prop_area *pa = __system_property_area__; 281 size = ALIGN(size, sizeof(uint32_t)); 282 283 if (pa->bytes_used + size > pa_data_size) 284 return NULL; 285 286 *off = pa->bytes_used; 287 __system_property_area__->bytes_used += size; 288 return __system_property_area__->data + *off; 289 } 290 291 static prop_bt *new_prop_bt(const char *name, uint8_t namelen, prop_off_t *off) 292 { 293 prop_off_t off_tmp; 294 prop_bt *bt = new_prop_obj(sizeof(prop_bt) + namelen + 1, &off_tmp); 295 if (bt) { 296 memcpy(bt->name, name, namelen); 297 bt->name[namelen] = '\0'; 298 bt->namelen = namelen; 299 ANDROID_MEMBAR_FULL(); 300 *off = off_tmp; 301 } 302 303 return bt; 304 } 305 306 static prop_info *new_prop_info(const char *name, uint8_t namelen, 307 const char *value, uint8_t valuelen, prop_off_t *off) 308 { 309 prop_off_t off_tmp; 310 prop_info *info = new_prop_obj(sizeof(prop_info) + namelen + 1, &off_tmp); 311 if (info) { 312 memcpy(info->name, name, namelen); 313 info->name[namelen] = '\0'; 314 info->serial = (valuelen << 24); 315 memcpy(info->value, value, valuelen); 316 info->value[valuelen] = '\0'; 317 ANDROID_MEMBAR_FULL(); 318 *off = off_tmp; 319 } 320 321 return info; 322 } 323 324 static void *to_prop_obj(prop_off_t off) 325 { 326 if (off > pa_data_size) 327 return NULL; 328 329 return __system_property_area__->data + off; 330 } 331 332 static prop_bt *root_node() 333 { 334 return to_prop_obj(0); 335 } 336 337 static int cmp_prop_name(const char *one, uint8_t one_len, const char *two, 338 uint8_t two_len) 339 { 340 if (one_len < two_len) 341 return -1; 342 else if (one_len > two_len) 343 return 1; 344 else 345 return strncmp(one, two, one_len); 346 } 347 348 static prop_bt *find_prop_bt(prop_bt *bt, const char *name, uint8_t namelen, 349 bool alloc_if_needed) 350 { 351 while (true) { 352 int ret; 353 if (!bt) 354 return bt; 355 ret = cmp_prop_name(name, namelen, bt->name, bt->namelen); 356 357 if (ret == 0) { 358 return bt; 359 } else if (ret < 0) { 360 if (bt->left) { 361 bt = to_prop_obj(bt->left); 362 } else { 363 if (!alloc_if_needed) 364 return NULL; 365 366 bt = new_prop_bt(name, namelen, &bt->left); 367 } 368 } else { 369 if (bt->right) { 370 bt = to_prop_obj(bt->right); 371 } else { 372 if (!alloc_if_needed) 373 return NULL; 374 375 bt = new_prop_bt(name, namelen, &bt->right); 376 } 377 } 378 } 379 } 380 381 static const prop_info *find_property(prop_bt *trie, const char *name, 382 uint8_t namelen, const char *value, uint8_t valuelen, 383 bool alloc_if_needed) 384 { 385 const char *remaining_name = name; 386 387 while (true) { 388 char *sep = strchr(remaining_name, '.'); 389 bool want_subtree = (sep != NULL); 390 uint8_t substr_size; 391 392 prop_bt *root; 393 394 if (want_subtree) { 395 substr_size = sep - remaining_name; 396 } else { 397 substr_size = strlen(remaining_name); 398 } 399 400 if (!substr_size) 401 return NULL; 402 403 if (trie->children) { 404 root = to_prop_obj(trie->children); 405 } else if (alloc_if_needed) { 406 root = new_prop_bt(remaining_name, substr_size, &trie->children); 407 } else { 408 root = NULL; 409 } 410 411 if (!root) 412 return NULL; 413 414 trie = find_prop_bt(root, remaining_name, substr_size, alloc_if_needed); 415 if (!trie) 416 return NULL; 417 418 if (!want_subtree) 419 break; 420 421 remaining_name = sep + 1; 422 } 423 424 if (trie->prop) { 425 return to_prop_obj(trie->prop); 426 } else if (alloc_if_needed) { 427 return new_prop_info(name, namelen, value, valuelen, &trie->prop); 428 } else { 429 return NULL; 430 } 431 } 432 433 const prop_info *__system_property_find(const char *name) 434 { 435 if (__predict_false(compat_mode)) { 436 return __system_property_find_compat(name); 437 } 438 return find_property(root_node(), name, strlen(name), NULL, 0, false); 439 } 440 441 int __system_property_read(const prop_info *pi, char *name, char *value) 442 { 443 unsigned serial, len; 444 445 if (__predict_false(compat_mode)) { 446 return __system_property_read_compat(pi, name, value); 447 } 448 449 for(;;) { 450 serial = pi->serial; 451 while(SERIAL_DIRTY(serial)) { 452 __futex_wait((volatile void *)&pi->serial, serial, 0); 453 serial = pi->serial; 454 } 455 len = SERIAL_VALUE_LEN(serial); 456 memcpy(value, pi->value, len + 1); 457 ANDROID_MEMBAR_FULL(); 458 if(serial == pi->serial) { 459 if(name != 0) { 460 strcpy(name, pi->name); 461 } 462 return len; 463 } 464 } 465 } 466 467 int __system_property_get(const char *name, char *value) 468 { 469 const prop_info *pi = __system_property_find(name); 470 471 if(pi != 0) { 472 return __system_property_read(pi, 0, value); 473 } else { 474 value[0] = 0; 475 return 0; 476 } 477 } 478 479 480 static int send_prop_msg(prop_msg *msg) 481 { 482 struct pollfd pollfds[1]; 483 struct sockaddr_un addr; 484 socklen_t alen; 485 size_t namelen; 486 int s; 487 int r; 488 int result = -1; 489 490 s = socket(AF_LOCAL, SOCK_STREAM, 0); 491 if(s < 0) { 492 return result; 493 } 494 495 memset(&addr, 0, sizeof(addr)); 496 namelen = strlen(property_service_socket); 497 strlcpy(addr.sun_path, property_service_socket, sizeof addr.sun_path); 498 addr.sun_family = AF_LOCAL; 499 alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1; 500 501 if(TEMP_FAILURE_RETRY(connect(s, (struct sockaddr *) &addr, alen)) < 0) { 502 close(s); 503 return result; 504 } 505 506 r = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg), 0)); 507 508 if(r == sizeof(prop_msg)) { 509 // We successfully wrote to the property server but now we 510 // wait for the property server to finish its work. It 511 // acknowledges its completion by closing the socket so we 512 // poll here (on nothing), waiting for the socket to close. 513 // If you 'adb shell setprop foo bar' you'll see the POLLHUP 514 // once the socket closes. Out of paranoia we cap our poll 515 // at 250 ms. 516 pollfds[0].fd = s; 517 pollfds[0].events = 0; 518 r = TEMP_FAILURE_RETRY(poll(pollfds, 1, 250 /* ms */)); 519 if (r == 1 && (pollfds[0].revents & POLLHUP) != 0) { 520 result = 0; 521 } else { 522 // Ignore the timeout and treat it like a success anyway. 523 // The init process is single-threaded and its property 524 // service is sometimes slow to respond (perhaps it's off 525 // starting a child process or something) and thus this 526 // times out and the caller thinks it failed, even though 527 // it's still getting around to it. So we fake it here, 528 // mostly for ctl.* properties, but we do try and wait 250 529 // ms so callers who do read-after-write can reliably see 530 // what they've written. Most of the time. 531 // TODO: fix the system properties design. 532 result = 0; 533 } 534 } 535 536 close(s); 537 return result; 538 } 539 540 int __system_property_set(const char *key, const char *value) 541 { 542 int err; 543 prop_msg msg; 544 545 if(key == 0) return -1; 546 if(value == 0) value = ""; 547 if(strlen(key) >= PROP_NAME_MAX) return -1; 548 if(strlen(value) >= PROP_VALUE_MAX) return -1; 549 550 memset(&msg, 0, sizeof msg); 551 msg.cmd = PROP_MSG_SETPROP; 552 strlcpy(msg.name, key, sizeof msg.name); 553 strlcpy(msg.value, value, sizeof msg.value); 554 555 err = send_prop_msg(&msg); 556 if(err < 0) { 557 return err; 558 } 559 560 return 0; 561 } 562 563 int __system_property_wait(const prop_info *pi) 564 { 565 unsigned n; 566 if(pi == 0) { 567 prop_area *pa = __system_property_area__; 568 n = pa->serial; 569 do { 570 __futex_wait(&pa->serial, n, 0); 571 } while(n == pa->serial); 572 } else { 573 n = pi->serial; 574 do { 575 __futex_wait((volatile void *)&pi->serial, n, 0); 576 } while(n == pi->serial); 577 } 578 return 0; 579 } 580 581 int __system_property_update(prop_info *pi, const char *value, unsigned int len) 582 { 583 prop_area *pa = __system_property_area__; 584 585 if (len >= PROP_VALUE_MAX) 586 return -1; 587 588 pi->serial = pi->serial | 1; 589 ANDROID_MEMBAR_FULL(); 590 memcpy(pi->value, value, len + 1); 591 ANDROID_MEMBAR_FULL(); 592 pi->serial = (len << 24) | ((pi->serial + 1) & 0xffffff); 593 __futex_wake(&pi->serial, INT32_MAX); 594 595 pa->serial++; 596 __futex_wake(&pa->serial, INT32_MAX); 597 598 return 0; 599 } 600 601 int __system_property_add(const char *name, unsigned int namelen, 602 const char *value, unsigned int valuelen) 603 { 604 prop_area *pa = __system_property_area__; 605 const prop_info *pi; 606 607 if (namelen >= PROP_NAME_MAX) 608 return -1; 609 if (valuelen >= PROP_VALUE_MAX) 610 return -1; 611 if (namelen < 1) 612 return -1; 613 614 pi = find_property(root_node(), name, namelen, value, valuelen, true); 615 if (!pi) 616 return -1; 617 618 pa->serial++; 619 __futex_wake(&pa->serial, INT32_MAX); 620 return 0; 621 } 622 623 unsigned int __system_property_serial(const prop_info *pi) 624 { 625 return pi->serial; 626 } 627 628 unsigned int __system_property_wait_any(unsigned int serial) 629 { 630 prop_area *pa = __system_property_area__; 631 632 do { 633 __futex_wait(&pa->serial, serial, 0); 634 } while(pa->serial == serial); 635 636 return pa->serial; 637 } 638 639 struct find_nth_cookie { 640 unsigned count; 641 unsigned n; 642 const prop_info *pi; 643 }; 644 645 static void find_nth_fn(const prop_info *pi, void *ptr) 646 { 647 struct find_nth_cookie *cookie = ptr; 648 649 if (cookie->n == cookie->count) 650 cookie->pi = pi; 651 652 cookie->count++; 653 } 654 655 const prop_info *__system_property_find_nth(unsigned n) 656 { 657 struct find_nth_cookie cookie; 658 int err; 659 660 memset(&cookie, 0, sizeof(cookie)); 661 cookie.n = n; 662 663 err = __system_property_foreach(find_nth_fn, &cookie); 664 if (err < 0) 665 return NULL; 666 667 return cookie.pi; 668 } 669 670 static int foreach_property(prop_off_t off, 671 void (*propfn)(const prop_info *pi, void *cookie), void *cookie) 672 { 673 prop_bt *trie = to_prop_obj(off); 674 if (!trie) 675 return -1; 676 677 if (trie->left) { 678 int err = foreach_property(trie->left, propfn, cookie); 679 if (err < 0) 680 return -1; 681 } 682 if (trie->prop) { 683 prop_info *info = to_prop_obj(trie->prop); 684 if (!info) 685 return -1; 686 propfn(info, cookie); 687 } 688 if (trie->children) { 689 int err = foreach_property(trie->children, propfn, cookie); 690 if (err < 0) 691 return -1; 692 } 693 if (trie->right) { 694 int err = foreach_property(trie->right, propfn, cookie); 695 if (err < 0) 696 return -1; 697 } 698 699 return 0; 700 } 701 702 int __system_property_foreach(void (*propfn)(const prop_info *pi, void *cookie), 703 void *cookie) 704 { 705 if (__predict_false(compat_mode)) { 706 return __system_property_foreach_compat(propfn, cookie); 707 } 708 return foreach_property(0, propfn, cookie); 709 } 710