• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
get_fd_from_env(void)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 
map_prop_area_rw()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 
__system_property_set_filename(const char * filename)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 
__system_property_area_init()193 int __system_property_area_init()
194 {
195     return map_prop_area_rw();
196 }
197 
map_prop_area()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 
__system_properties_init()273 int __system_properties_init()
274 {
275     return map_prop_area();
276 }
277 
new_prop_obj(size_t size,prop_off_t * off)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 
new_prop_bt(const char * name,uint8_t namelen,prop_off_t * off)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 
new_prop_info(const char * name,uint8_t namelen,const char * value,uint8_t valuelen,prop_off_t * off)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 
to_prop_obj(prop_off_t off)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 
root_node()332 static prop_bt *root_node()
333 {
334     return to_prop_obj(0);
335 }
336 
cmp_prop_name(const char * one,uint8_t one_len,const char * two,uint8_t two_len)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 
find_prop_bt(prop_bt * bt,const char * name,uint8_t namelen,bool alloc_if_needed)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 
find_property(prop_bt * trie,const char * name,uint8_t namelen,const char * value,uint8_t valuelen,bool alloc_if_needed)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 
__system_property_find(const char * name)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 
__system_property_read(const prop_info * pi,char * name,char * value)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 
__system_property_get(const char * name,char * value)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 
send_prop_msg(prop_msg * msg)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 
__system_property_set(const char * key,const char * value)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 
__system_property_wait(const prop_info * pi)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 
__system_property_update(prop_info * pi,const char * value,unsigned int len)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 
__system_property_add(const char * name,unsigned int namelen,const char * value,unsigned int valuelen)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 
__system_property_serial(const prop_info * pi)623 unsigned int __system_property_serial(const prop_info *pi)
624 {
625     return pi->serial;
626 }
627 
__system_property_wait_any(unsigned int serial)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 
find_nth_fn(const prop_info * pi,void * ptr)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 
__system_property_find_nth(unsigned n)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 
foreach_property(prop_off_t off,void (* propfn)(const prop_info * pi,void * cookie),void * cookie)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 
__system_property_foreach(void (* propfn)(const prop_info * pi,void * cookie),void * cookie)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