Home | History | Annotate | Download | only in bionic
      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