• 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 
29 #include <ctype.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <poll.h>
33 #include <stdatomic.h>
34 #include <stdbool.h>
35 #include <stddef.h>
36 #include <stdint.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <new>
41 
42 #include <linux/xattr.h>
43 #include <netinet/in.h>
44 #include <sys/mman.h>
45 #include <sys/select.h>
46 #include <sys/socket.h>
47 #include <sys/stat.h>
48 #include <sys/types.h>
49 #include <sys/uio.h>
50 #include <sys/un.h>
51 #include <sys/xattr.h>
52 
53 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
54 #include <sys/_system_properties.h>
55 #include <sys/system_properties.h>
56 
57 #include "private/ErrnoRestorer.h"
58 #include "private/bionic_futex.h"
59 #include "private/bionic_lock.h"
60 #include "private/bionic_macros.h"
61 #include "private/bionic_sdk_version.h"
62 #include "private/libc_logging.h"
63 
64 static constexpr int PROP_FILENAME_MAX = 1024;
65 
66 static constexpr uint32_t PROP_AREA_MAGIC = 0x504f5250;
67 static constexpr uint32_t PROP_AREA_VERSION = 0xfc6ed0ab;
68 
69 static constexpr size_t PA_SIZE = 128 * 1024;
70 
71 #define SERIAL_DIRTY(serial) ((serial)&1)
72 #define SERIAL_VALUE_LEN(serial) ((serial) >> 24)
73 
74 static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME;
75 static const char* kServiceVersionPropertyName = "ro.property_service.version";
76 
77 /*
78  * Properties are stored in a hybrid trie/binary tree structure.
79  * Each property's name is delimited at '.' characters, and the tokens are put
80  * into a trie structure.  Siblings at each level of the trie are stored in a
81  * binary tree.  For instance, "ro.secure"="1" could be stored as follows:
82  *
83  * +-----+   children    +----+   children    +--------+
84  * |     |-------------->| ro |-------------->| secure |
85  * +-----+               +----+               +--------+
86  *                       /    \                /   |
87  *                 left /      \ right   left /    |  prop   +===========+
88  *                     v        v            v     +-------->| ro.secure |
89  *                  +-----+   +-----+     +-----+            +-----------+
90  *                  | net |   | sys |     | com |            |     1     |
91  *                  +-----+   +-----+     +-----+            +===========+
92  */
93 
94 // Represents a node in the trie.
95 struct prop_bt {
96   uint32_t namelen;
97 
98   // The property trie is updated only by the init process (single threaded) which provides
99   // property service. And it can be read by multiple threads at the same time.
100   // As the property trie is not protected by locks, we use atomic_uint_least32_t types for the
101   // left, right, children "pointers" in the trie node. To make sure readers who see the
102   // change of "pointers" can also notice the change of prop_bt structure contents pointed by
103   // the "pointers", we always use release-consume ordering pair when accessing these "pointers".
104 
105   // prop "points" to prop_info structure if there is a propery associated with the trie node.
106   // Its situation is similar to the left, right, children "pointers". So we use
107   // atomic_uint_least32_t and release-consume ordering to protect it as well.
108 
109   // We should also avoid rereading these fields redundantly, since not
110   // all processor implementations ensure that multiple loads from the
111   // same field are carried out in the right order.
112   atomic_uint_least32_t prop;
113 
114   atomic_uint_least32_t left;
115   atomic_uint_least32_t right;
116 
117   atomic_uint_least32_t children;
118 
119   char name[0];
120 
prop_btprop_bt121   prop_bt(const char* name, const uint32_t name_length) {
122     this->namelen = name_length;
123     memcpy(this->name, name, name_length);
124     this->name[name_length] = '\0';
125   }
126 
127  private:
128   DISALLOW_COPY_AND_ASSIGN(prop_bt);
129 };
130 
131 class prop_area {
132  public:
prop_area(const uint32_t magic,const uint32_t version)133   prop_area(const uint32_t magic, const uint32_t version) : magic_(magic), version_(version) {
134     atomic_init(&serial_, 0);
135     memset(reserved_, 0, sizeof(reserved_));
136     // Allocate enough space for the root node.
137     bytes_used_ = sizeof(prop_bt);
138   }
139 
140   const prop_info* find(const char* name);
141   bool add(const char* name, unsigned int namelen, const char* value, unsigned int valuelen);
142 
143   bool foreach (void (*propfn)(const prop_info* pi, void* cookie), void* cookie);
144 
serial()145   atomic_uint_least32_t* serial() {
146     return &serial_;
147   }
magic() const148   uint32_t magic() const {
149     return magic_;
150   }
version() const151   uint32_t version() const {
152     return version_;
153   }
154 
155  private:
156   void* allocate_obj(const size_t size, uint_least32_t* const off);
157   prop_bt* new_prop_bt(const char* name, uint32_t namelen, uint_least32_t* const off);
158   prop_info* new_prop_info(const char* name, uint32_t namelen, const char* value, uint32_t valuelen,
159                            uint_least32_t* const off);
160   void* to_prop_obj(uint_least32_t off);
161   prop_bt* to_prop_bt(atomic_uint_least32_t* off_p);
162   prop_info* to_prop_info(atomic_uint_least32_t* off_p);
163 
164   prop_bt* root_node();
165 
166   prop_bt* find_prop_bt(prop_bt* const bt, const char* name, uint32_t namelen, bool alloc_if_needed);
167 
168   const prop_info* find_property(prop_bt* const trie, const char* name, uint32_t namelen,
169                                  const char* value, uint32_t valuelen, bool alloc_if_needed);
170 
171   bool foreach_property(prop_bt* const trie, void (*propfn)(const prop_info* pi, void* cookie),
172                         void* cookie);
173 
174   uint32_t bytes_used_;
175   atomic_uint_least32_t serial_;
176   uint32_t magic_;
177   uint32_t version_;
178   uint32_t reserved_[28];
179   char data_[0];
180 
181   DISALLOW_COPY_AND_ASSIGN(prop_area);
182 };
183 
184 struct prop_info {
185   atomic_uint_least32_t serial;
186   // we need to keep this buffer around because the property
187   // value can be modified whereas name is constant.
188   char value[PROP_VALUE_MAX];
189   char name[0];
190 
prop_infoprop_info191   prop_info(const char* name, uint32_t namelen, const char* value, uint32_t valuelen) {
192     memcpy(this->name, name, namelen);
193     this->name[namelen] = '\0';
194     atomic_init(&this->serial, valuelen << 24);
195     memcpy(this->value, value, valuelen);
196     this->value[valuelen] = '\0';
197   }
198 
199  private:
200   DISALLOW_IMPLICIT_CONSTRUCTORS(prop_info);
201 };
202 
203 // This is public because it was exposed in the NDK. As of 2017-01, ~60 apps reference this symbol.
204 prop_area* __system_property_area__ = nullptr;
205 
206 static char property_filename[PROP_FILENAME_MAX] = PROP_FILENAME;
207 static size_t pa_data_size;
208 static size_t pa_size;
209 static bool initialized = false;
210 
map_prop_area_rw(const char * filename,const char * context,bool * fsetxattr_failed)211 static prop_area* map_prop_area_rw(const char* filename, const char* context,
212                                    bool* fsetxattr_failed) {
213   /* dev is a tmpfs that we can use to carve a shared workspace
214    * out of, so let's do that...
215    */
216   const int fd = open(filename, O_RDWR | O_CREAT | O_NOFOLLOW | O_CLOEXEC | O_EXCL, 0444);
217 
218   if (fd < 0) {
219     if (errno == EACCES) {
220       /* for consistency with the case where the process has already
221        * mapped the page in and segfaults when trying to write to it
222        */
223       abort();
224     }
225     return nullptr;
226   }
227 
228   if (context) {
229     if (fsetxattr(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1, 0) != 0) {
230       __libc_format_log(ANDROID_LOG_ERROR, "libc",
231                         "fsetxattr failed to set context (%s) for \"%s\"", context, filename);
232       /*
233        * fsetxattr() will fail during system properties tests due to selinux policy.
234        * We do not want to create a custom policy for the tester, so we will continue in
235        * this function but set a flag that an error has occurred.
236        * Init, which is the only daemon that should ever call this function will abort
237        * when this error occurs.
238        * Otherwise, the tester will ignore it and continue, albeit without any selinux
239        * property separation.
240        */
241       if (fsetxattr_failed) {
242         *fsetxattr_failed = true;
243       }
244     }
245   }
246 
247   if (ftruncate(fd, PA_SIZE) < 0) {
248     close(fd);
249     return nullptr;
250   }
251 
252   pa_size = PA_SIZE;
253   pa_data_size = pa_size - sizeof(prop_area);
254 
255   void* const memory_area = mmap(nullptr, pa_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
256   if (memory_area == MAP_FAILED) {
257     close(fd);
258     return nullptr;
259   }
260 
261   prop_area* pa = new (memory_area) prop_area(PROP_AREA_MAGIC, PROP_AREA_VERSION);
262 
263   close(fd);
264   return pa;
265 }
266 
map_fd_ro(const int fd)267 static prop_area* map_fd_ro(const int fd) {
268   struct stat fd_stat;
269   if (fstat(fd, &fd_stat) < 0) {
270     return nullptr;
271   }
272 
273   if ((fd_stat.st_uid != 0) || (fd_stat.st_gid != 0) ||
274       ((fd_stat.st_mode & (S_IWGRP | S_IWOTH)) != 0) ||
275       (fd_stat.st_size < static_cast<off_t>(sizeof(prop_area)))) {
276     return nullptr;
277   }
278 
279   pa_size = fd_stat.st_size;
280   pa_data_size = pa_size - sizeof(prop_area);
281 
282   void* const map_result = mmap(nullptr, pa_size, PROT_READ, MAP_SHARED, fd, 0);
283   if (map_result == MAP_FAILED) {
284     return nullptr;
285   }
286 
287   prop_area* pa = reinterpret_cast<prop_area*>(map_result);
288   if ((pa->magic() != PROP_AREA_MAGIC) || (pa->version() != PROP_AREA_VERSION)) {
289     munmap(pa, pa_size);
290     return nullptr;
291   }
292 
293   return pa;
294 }
295 
map_prop_area(const char * filename)296 static prop_area* map_prop_area(const char* filename) {
297   int fd = open(filename, O_CLOEXEC | O_NOFOLLOW | O_RDONLY);
298   if (fd == -1) return nullptr;
299 
300   prop_area* map_result = map_fd_ro(fd);
301   close(fd);
302 
303   return map_result;
304 }
305 
allocate_obj(const size_t size,uint_least32_t * const off)306 void* prop_area::allocate_obj(const size_t size, uint_least32_t* const off) {
307   const size_t aligned = BIONIC_ALIGN(size, sizeof(uint_least32_t));
308   if (bytes_used_ + aligned > pa_data_size) {
309     return nullptr;
310   }
311 
312   *off = bytes_used_;
313   bytes_used_ += aligned;
314   return data_ + *off;
315 }
316 
new_prop_bt(const char * name,uint32_t namelen,uint_least32_t * const off)317 prop_bt* prop_area::new_prop_bt(const char* name, uint32_t namelen, uint_least32_t* const off) {
318   uint_least32_t new_offset;
319   void* const p = allocate_obj(sizeof(prop_bt) + namelen + 1, &new_offset);
320   if (p != nullptr) {
321     prop_bt* bt = new (p) prop_bt(name, namelen);
322     *off = new_offset;
323     return bt;
324   }
325 
326   return nullptr;
327 }
328 
new_prop_info(const char * name,uint32_t namelen,const char * value,uint32_t valuelen,uint_least32_t * const off)329 prop_info* prop_area::new_prop_info(const char* name, uint32_t namelen, const char* value,
330                                     uint32_t valuelen, uint_least32_t* const off) {
331   uint_least32_t new_offset;
332   void* const p = allocate_obj(sizeof(prop_info) + namelen + 1, &new_offset);
333   if (p != nullptr) {
334     prop_info* info = new (p) prop_info(name, namelen, value, valuelen);
335     *off = new_offset;
336     return info;
337   }
338 
339   return nullptr;
340 }
341 
to_prop_obj(uint_least32_t off)342 void* prop_area::to_prop_obj(uint_least32_t off) {
343   if (off > pa_data_size) return nullptr;
344 
345   return (data_ + off);
346 }
347 
to_prop_bt(atomic_uint_least32_t * off_p)348 inline prop_bt* prop_area::to_prop_bt(atomic_uint_least32_t* off_p) {
349   uint_least32_t off = atomic_load_explicit(off_p, memory_order_consume);
350   return reinterpret_cast<prop_bt*>(to_prop_obj(off));
351 }
352 
to_prop_info(atomic_uint_least32_t * off_p)353 inline prop_info* prop_area::to_prop_info(atomic_uint_least32_t* off_p) {
354   uint_least32_t off = atomic_load_explicit(off_p, memory_order_consume);
355   return reinterpret_cast<prop_info*>(to_prop_obj(off));
356 }
357 
root_node()358 inline prop_bt* prop_area::root_node() {
359   return reinterpret_cast<prop_bt*>(to_prop_obj(0));
360 }
361 
cmp_prop_name(const char * one,uint32_t one_len,const char * two,uint32_t two_len)362 static int cmp_prop_name(const char* one, uint32_t one_len, const char* two, uint32_t two_len) {
363   if (one_len < two_len)
364     return -1;
365   else if (one_len > two_len)
366     return 1;
367   else
368     return strncmp(one, two, one_len);
369 }
370 
find_prop_bt(prop_bt * const bt,const char * name,uint32_t namelen,bool alloc_if_needed)371 prop_bt* prop_area::find_prop_bt(prop_bt* const bt, const char* name, uint32_t namelen,
372                                  bool alloc_if_needed) {
373   prop_bt* current = bt;
374   while (true) {
375     if (!current) {
376       return nullptr;
377     }
378 
379     const int ret = cmp_prop_name(name, namelen, current->name, current->namelen);
380     if (ret == 0) {
381       return current;
382     }
383 
384     if (ret < 0) {
385       uint_least32_t left_offset = atomic_load_explicit(&current->left, memory_order_relaxed);
386       if (left_offset != 0) {
387         current = to_prop_bt(&current->left);
388       } else {
389         if (!alloc_if_needed) {
390           return nullptr;
391         }
392 
393         uint_least32_t new_offset;
394         prop_bt* new_bt = new_prop_bt(name, namelen, &new_offset);
395         if (new_bt) {
396           atomic_store_explicit(&current->left, new_offset, memory_order_release);
397         }
398         return new_bt;
399       }
400     } else {
401       uint_least32_t right_offset = atomic_load_explicit(&current->right, memory_order_relaxed);
402       if (right_offset != 0) {
403         current = to_prop_bt(&current->right);
404       } else {
405         if (!alloc_if_needed) {
406           return nullptr;
407         }
408 
409         uint_least32_t new_offset;
410         prop_bt* new_bt = new_prop_bt(name, namelen, &new_offset);
411         if (new_bt) {
412           atomic_store_explicit(&current->right, new_offset, memory_order_release);
413         }
414         return new_bt;
415       }
416     }
417   }
418 }
419 
find_property(prop_bt * const trie,const char * name,uint32_t namelen,const char * value,uint32_t valuelen,bool alloc_if_needed)420 const prop_info* prop_area::find_property(prop_bt* const trie, const char* name, uint32_t namelen,
421                                           const char* value, uint32_t valuelen,
422                                           bool alloc_if_needed) {
423   if (!trie) return nullptr;
424 
425   const char* remaining_name = name;
426   prop_bt* current = trie;
427   while (true) {
428     const char* sep = strchr(remaining_name, '.');
429     const bool want_subtree = (sep != nullptr);
430     const uint32_t substr_size = (want_subtree) ? sep - remaining_name : strlen(remaining_name);
431 
432     if (!substr_size) {
433       return nullptr;
434     }
435 
436     prop_bt* root = nullptr;
437     uint_least32_t children_offset = atomic_load_explicit(&current->children, memory_order_relaxed);
438     if (children_offset != 0) {
439       root = to_prop_bt(&current->children);
440     } else if (alloc_if_needed) {
441       uint_least32_t new_offset;
442       root = new_prop_bt(remaining_name, substr_size, &new_offset);
443       if (root) {
444         atomic_store_explicit(&current->children, new_offset, memory_order_release);
445       }
446     }
447 
448     if (!root) {
449       return nullptr;
450     }
451 
452     current = find_prop_bt(root, remaining_name, substr_size, alloc_if_needed);
453     if (!current) {
454       return nullptr;
455     }
456 
457     if (!want_subtree) break;
458 
459     remaining_name = sep + 1;
460   }
461 
462   uint_least32_t prop_offset = atomic_load_explicit(&current->prop, memory_order_relaxed);
463   if (prop_offset != 0) {
464     return to_prop_info(&current->prop);
465   } else if (alloc_if_needed) {
466     uint_least32_t new_offset;
467     prop_info* new_info = new_prop_info(name, namelen, value, valuelen, &new_offset);
468     if (new_info) {
469       atomic_store_explicit(&current->prop, new_offset, memory_order_release);
470     }
471 
472     return new_info;
473   } else {
474     return nullptr;
475   }
476 }
477 
478 class PropertyServiceConnection {
479  public:
PropertyServiceConnection()480   PropertyServiceConnection() : last_error_(0) {
481     socket_ = ::socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
482     if (socket_ == -1) {
483       last_error_ = errno;
484       return;
485     }
486 
487     const size_t namelen = strlen(property_service_socket);
488     sockaddr_un addr;
489     memset(&addr, 0, sizeof(addr));
490     strlcpy(addr.sun_path, property_service_socket, sizeof(addr.sun_path));
491     addr.sun_family = AF_LOCAL;
492     socklen_t alen = namelen + offsetof(sockaddr_un, sun_path) + 1;
493 
494     if (TEMP_FAILURE_RETRY(connect(socket_, reinterpret_cast<sockaddr*>(&addr), alen)) == -1) {
495       close(socket_);
496       socket_ = -1;
497       last_error_ = errno;
498     }
499   }
500 
IsValid()501   bool IsValid() {
502     return socket_ != -1;
503   }
504 
GetLastError()505   int GetLastError() {
506     return last_error_;
507   }
508 
RecvInt32(int32_t * value)509   bool RecvInt32(int32_t* value) {
510     int result = TEMP_FAILURE_RETRY(recv(socket_, value, sizeof(*value), MSG_WAITALL));
511     return CheckSendRecvResult(result, sizeof(*value));
512   }
513 
socket()514   int socket() {
515     return socket_;
516   }
517 
~PropertyServiceConnection()518   ~PropertyServiceConnection() {
519     if (socket_ != -1) {
520       close(socket_);
521     }
522   }
523 
524  private:
CheckSendRecvResult(int result,int expected_len)525   bool CheckSendRecvResult(int result, int expected_len) {
526     if (result == -1) {
527       last_error_ = errno;
528     } else if (result != expected_len) {
529       last_error_ = -1;
530     } else {
531       last_error_ = 0;
532     }
533 
534     return last_error_ == 0;
535   }
536 
537   int socket_;
538   int last_error_;
539 
540   friend class SocketWriter;
541 };
542 
543 class SocketWriter {
544  public:
SocketWriter(PropertyServiceConnection * connection)545   explicit SocketWriter(PropertyServiceConnection* connection)
546       : connection_(connection), iov_index_(0), uint_buf_index_(0)
547   {}
548 
WriteUint32(uint32_t value)549   SocketWriter& WriteUint32(uint32_t value) {
550     CHECK(uint_buf_index_ < kUintBufSize);
551     CHECK(iov_index_ < kIovSize);
552     uint32_t* ptr = uint_buf_ + uint_buf_index_;
553     uint_buf_[uint_buf_index_++] = value;
554     iov_[iov_index_].iov_base = ptr;
555     iov_[iov_index_].iov_len = sizeof(*ptr);
556     ++iov_index_;
557     return *this;
558   }
559 
WriteString(const char * value)560   SocketWriter& WriteString(const char* value) {
561     uint32_t valuelen = strlen(value);
562     WriteUint32(valuelen);
563     if (valuelen == 0) {
564       return *this;
565     }
566 
567     CHECK(iov_index_ < kIovSize);
568     iov_[iov_index_].iov_base = const_cast<char*>(value);
569     iov_[iov_index_].iov_len = valuelen;
570     ++iov_index_;
571 
572     return *this;
573   }
574 
Send()575   bool Send() {
576     if (!connection_->IsValid()) {
577       return false;
578     }
579 
580     if (writev(connection_->socket(), iov_, iov_index_) == -1) {
581       connection_->last_error_ = errno;
582       return false;
583     }
584 
585     iov_index_ = uint_buf_index_ = 0;
586     return true;
587   }
588 
589  private:
590   static constexpr size_t kUintBufSize = 8;
591   static constexpr size_t kIovSize = 8;
592 
593   PropertyServiceConnection* connection_;
594   iovec iov_[kIovSize];
595   size_t iov_index_;
596   uint32_t uint_buf_[kUintBufSize];
597   size_t uint_buf_index_;
598 
599   DISALLOW_IMPLICIT_CONSTRUCTORS(SocketWriter);
600 };
601 
602 struct prop_msg {
603   unsigned cmd;
604   char name[PROP_NAME_MAX];
605   char value[PROP_VALUE_MAX];
606 };
607 
send_prop_msg(const prop_msg * msg)608 static int send_prop_msg(const prop_msg* msg) {
609   PropertyServiceConnection connection;
610   if (!connection.IsValid()) {
611     return connection.GetLastError();
612   }
613 
614   int result = -1;
615   int s = connection.socket();
616 
617   const int num_bytes = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg), 0));
618   if (num_bytes == sizeof(prop_msg)) {
619     // We successfully wrote to the property server but now we
620     // wait for the property server to finish its work.  It
621     // acknowledges its completion by closing the socket so we
622     // poll here (on nothing), waiting for the socket to close.
623     // If you 'adb shell setprop foo bar' you'll see the POLLHUP
624     // once the socket closes.  Out of paranoia we cap our poll
625     // at 250 ms.
626     pollfd pollfds[1];
627     pollfds[0].fd = s;
628     pollfds[0].events = 0;
629     const int poll_result = TEMP_FAILURE_RETRY(poll(pollfds, 1, 250 /* ms */));
630     if (poll_result == 1 && (pollfds[0].revents & POLLHUP) != 0) {
631       result = 0;
632     } else {
633       // Ignore the timeout and treat it like a success anyway.
634       // The init process is single-threaded and its property
635       // service is sometimes slow to respond (perhaps it's off
636       // starting a child process or something) and thus this
637       // times out and the caller thinks it failed, even though
638       // it's still getting around to it.  So we fake it here,
639       // mostly for ctl.* properties, but we do try and wait 250
640       // ms so callers who do read-after-write can reliably see
641       // what they've written.  Most of the time.
642       // TODO: fix the system properties design.
643       __libc_format_log(ANDROID_LOG_WARN, "libc",
644                         "Property service has timed out while trying to set \"%s\" to \"%s\"",
645                         msg->name, msg->value);
646       result = 0;
647     }
648   }
649 
650   return result;
651 }
652 
foreach_property(prop_bt * const trie,void (* propfn)(const prop_info * pi,void * cookie),void * cookie)653 bool prop_area::foreach_property(prop_bt* const trie,
654                                  void (*propfn)(const prop_info* pi, void* cookie), void* cookie) {
655   if (!trie) return false;
656 
657   uint_least32_t left_offset = atomic_load_explicit(&trie->left, memory_order_relaxed);
658   if (left_offset != 0) {
659     const int err = foreach_property(to_prop_bt(&trie->left), propfn, cookie);
660     if (err < 0) return false;
661   }
662   uint_least32_t prop_offset = atomic_load_explicit(&trie->prop, memory_order_relaxed);
663   if (prop_offset != 0) {
664     prop_info* info = to_prop_info(&trie->prop);
665     if (!info) return false;
666     propfn(info, cookie);
667   }
668   uint_least32_t children_offset = atomic_load_explicit(&trie->children, memory_order_relaxed);
669   if (children_offset != 0) {
670     const int err = foreach_property(to_prop_bt(&trie->children), propfn, cookie);
671     if (err < 0) return false;
672   }
673   uint_least32_t right_offset = atomic_load_explicit(&trie->right, memory_order_relaxed);
674   if (right_offset != 0) {
675     const int err = foreach_property(to_prop_bt(&trie->right), propfn, cookie);
676     if (err < 0) return false;
677   }
678 
679   return true;
680 }
681 
find(const char * name)682 const prop_info* prop_area::find(const char* name) {
683   return find_property(root_node(), name, strlen(name), nullptr, 0, false);
684 }
685 
add(const char * name,unsigned int namelen,const char * value,unsigned int valuelen)686 bool prop_area::add(const char* name, unsigned int namelen, const char* value,
687                     unsigned int valuelen) {
688   return find_property(root_node(), name, namelen, value, valuelen, true);
689 }
690 
foreach(void (* propfn)(const prop_info * pi,void * cookie),void * cookie)691 bool prop_area::foreach (void (*propfn)(const prop_info* pi, void* cookie), void* cookie) {
692   return foreach_property(root_node(), propfn, cookie);
693 }
694 
695 class context_node {
696  public:
context_node(context_node * next,const char * context,prop_area * pa)697   context_node(context_node* next, const char* context, prop_area* pa)
698       : next(next), context_(strdup(context)), pa_(pa), no_access_(false) {
699     lock_.init(false);
700   }
~context_node()701   ~context_node() {
702     unmap();
703     free(context_);
704   }
705   bool open(bool access_rw, bool* fsetxattr_failed);
706   bool check_access_and_open();
707   void reset_access();
708 
context() const709   const char* context() const {
710     return context_;
711   }
pa()712   prop_area* pa() {
713     return pa_;
714   }
715 
716   context_node* next;
717 
718  private:
719   bool check_access();
720   void unmap();
721 
722   Lock lock_;
723   char* context_;
724   prop_area* pa_;
725   bool no_access_;
726 };
727 
728 struct prefix_node {
prefix_nodeprefix_node729   prefix_node(struct prefix_node* next, const char* prefix, context_node* context)
730       : prefix(strdup(prefix)), prefix_len(strlen(prefix)), context(context), next(next) {
731   }
~prefix_nodeprefix_node732   ~prefix_node() {
733     free(prefix);
734   }
735   char* prefix;
736   const size_t prefix_len;
737   context_node* context;
738   struct prefix_node* next;
739 };
740 
741 template <typename List, typename... Args>
list_add(List ** list,Args...args)742 static inline void list_add(List** list, Args... args) {
743   *list = new List(*list, args...);
744 }
745 
list_add_after_len(prefix_node ** list,const char * prefix,context_node * context)746 static void list_add_after_len(prefix_node** list, const char* prefix, context_node* context) {
747   size_t prefix_len = strlen(prefix);
748 
749   auto next_list = list;
750 
751   while (*next_list) {
752     if ((*next_list)->prefix_len < prefix_len || (*next_list)->prefix[0] == '*') {
753       list_add(next_list, prefix, context);
754       return;
755     }
756     next_list = &(*next_list)->next;
757   }
758   list_add(next_list, prefix, context);
759 }
760 
761 template <typename List, typename Func>
list_foreach(List * list,Func func)762 static void list_foreach(List* list, Func func) {
763   while (list) {
764     func(list);
765     list = list->next;
766   }
767 }
768 
769 template <typename List, typename Func>
list_find(List * list,Func func)770 static List* list_find(List* list, Func func) {
771   while (list) {
772     if (func(list)) {
773       return list;
774     }
775     list = list->next;
776   }
777   return nullptr;
778 }
779 
780 template <typename List>
list_free(List ** list)781 static void list_free(List** list) {
782   while (*list) {
783     auto old_list = *list;
784     *list = old_list->next;
785     delete old_list;
786   }
787 }
788 
789 static prefix_node* prefixes = nullptr;
790 static context_node* contexts = nullptr;
791 
792 /*
793  * pthread_mutex_lock() calls into system_properties in the case of contention.
794  * This creates a risk of dead lock if any system_properties functions
795  * use pthread locks after system_property initialization.
796  *
797  * For this reason, the below three functions use a bionic Lock and static
798  * allocation of memory for each filename.
799  */
800 
open(bool access_rw,bool * fsetxattr_failed)801 bool context_node::open(bool access_rw, bool* fsetxattr_failed) {
802   lock_.lock();
803   if (pa_) {
804     lock_.unlock();
805     return true;
806   }
807 
808   char filename[PROP_FILENAME_MAX];
809   int len = __libc_format_buffer(filename, sizeof(filename), "%s/%s", property_filename, context_);
810   if (len < 0 || len > PROP_FILENAME_MAX) {
811     lock_.unlock();
812     return false;
813   }
814 
815   if (access_rw) {
816     pa_ = map_prop_area_rw(filename, context_, fsetxattr_failed);
817   } else {
818     pa_ = map_prop_area(filename);
819   }
820   lock_.unlock();
821   return pa_;
822 }
823 
check_access_and_open()824 bool context_node::check_access_and_open() {
825   if (!pa_ && !no_access_) {
826     if (!check_access() || !open(false, nullptr)) {
827       no_access_ = true;
828     }
829   }
830   return pa_;
831 }
832 
reset_access()833 void context_node::reset_access() {
834   if (!check_access()) {
835     unmap();
836     no_access_ = true;
837   } else {
838     no_access_ = false;
839   }
840 }
841 
check_access()842 bool context_node::check_access() {
843   char filename[PROP_FILENAME_MAX];
844   int len = __libc_format_buffer(filename, sizeof(filename), "%s/%s", property_filename, context_);
845   if (len < 0 || len > PROP_FILENAME_MAX) {
846     return false;
847   }
848 
849   return access(filename, R_OK) == 0;
850 }
851 
unmap()852 void context_node::unmap() {
853   if (!pa_) {
854     return;
855   }
856 
857   munmap(pa_, pa_size);
858   if (pa_ == __system_property_area__) {
859     __system_property_area__ = nullptr;
860   }
861   pa_ = nullptr;
862 }
863 
map_system_property_area(bool access_rw,bool * fsetxattr_failed)864 static bool map_system_property_area(bool access_rw, bool* fsetxattr_failed) {
865   char filename[PROP_FILENAME_MAX];
866   int len =
867       __libc_format_buffer(filename, sizeof(filename), "%s/properties_serial", property_filename);
868   if (len < 0 || len > PROP_FILENAME_MAX) {
869     __system_property_area__ = nullptr;
870     return false;
871   }
872 
873   if (access_rw) {
874     __system_property_area__ =
875         map_prop_area_rw(filename, "u:object_r:properties_serial:s0", fsetxattr_failed);
876   } else {
877     __system_property_area__ = map_prop_area(filename);
878   }
879   return __system_property_area__;
880 }
881 
get_prop_area_for_name(const char * name)882 static prop_area* get_prop_area_for_name(const char* name) {
883   auto entry = list_find(prefixes, [name](prefix_node* l) {
884     return l->prefix[0] == '*' || !strncmp(l->prefix, name, l->prefix_len);
885   });
886   if (!entry) {
887     return nullptr;
888   }
889 
890   auto cnode = entry->context;
891   if (!cnode->pa()) {
892     /*
893      * We explicitly do not check no_access_ in this case because unlike the
894      * case of foreach(), we want to generate an selinux audit for each
895      * non-permitted property access in this function.
896      */
897     cnode->open(false, nullptr);
898   }
899   return cnode->pa();
900 }
901 
902 /*
903  * The below two functions are duplicated from label_support.c in libselinux.
904  * TODO: Find a location suitable for these functions such that both libc and
905  * libselinux can share a common source file.
906  */
907 
908 /*
909  * The read_spec_entries and read_spec_entry functions may be used to
910  * replace sscanf to read entries from spec files. The file and
911  * property services now use these.
912  */
913 
914 /* Read an entry from a spec file (e.g. file_contexts) */
read_spec_entry(char ** entry,char ** ptr,int * len)915 static inline int read_spec_entry(char** entry, char** ptr, int* len) {
916   *entry = nullptr;
917   char* tmp_buf = nullptr;
918 
919   while (isspace(**ptr) && **ptr != '\0') (*ptr)++;
920 
921   tmp_buf = *ptr;
922   *len = 0;
923 
924   while (!isspace(**ptr) && **ptr != '\0') {
925     (*ptr)++;
926     (*len)++;
927   }
928 
929   if (*len) {
930     *entry = strndup(tmp_buf, *len);
931     if (!*entry) return -1;
932   }
933 
934   return 0;
935 }
936 
937 /*
938  * line_buf - Buffer containing the spec entries .
939  * num_args - The number of spec parameter entries to process.
940  * ...      - A 'char **spec_entry' for each parameter.
941  * returns  - The number of items processed.
942  *
943  * This function calls read_spec_entry() to do the actual string processing.
944  */
read_spec_entries(char * line_buf,int num_args,...)945 static int read_spec_entries(char* line_buf, int num_args, ...) {
946   char **spec_entry, *buf_p;
947   int len, rc, items, entry_len = 0;
948   va_list ap;
949 
950   len = strlen(line_buf);
951   if (line_buf[len - 1] == '\n')
952     line_buf[len - 1] = '\0';
953   else
954     /* Handle case if line not \n terminated by bumping
955      * the len for the check below (as the line is NUL
956      * terminated by getline(3)) */
957     len++;
958 
959   buf_p = line_buf;
960   while (isspace(*buf_p)) buf_p++;
961 
962   /* Skip comment lines and empty lines. */
963   if (*buf_p == '#' || *buf_p == '\0') return 0;
964 
965   /* Process the spec file entries */
966   va_start(ap, num_args);
967 
968   items = 0;
969   while (items < num_args) {
970     spec_entry = va_arg(ap, char**);
971 
972     if (len - 1 == buf_p - line_buf) {
973       va_end(ap);
974       return items;
975     }
976 
977     rc = read_spec_entry(spec_entry, &buf_p, &entry_len);
978     if (rc < 0) {
979       va_end(ap);
980       return rc;
981     }
982     if (entry_len) items++;
983   }
984   va_end(ap);
985   return items;
986 }
987 
initialize_properties_from_file(const char * filename)988 static bool initialize_properties_from_file(const char* filename) {
989   FILE* file = fopen(filename, "re");
990   if (!file) {
991     return false;
992   }
993 
994   char* buffer = nullptr;
995   size_t line_len;
996   char* prop_prefix = nullptr;
997   char* context = nullptr;
998 
999   while (getline(&buffer, &line_len, file) > 0) {
1000     int items = read_spec_entries(buffer, 2, &prop_prefix, &context);
1001     if (items <= 0) {
1002       continue;
1003     }
1004     if (items == 1) {
1005       free(prop_prefix);
1006       continue;
1007     }
1008     /*
1009      * init uses ctl.* properties as an IPC mechanism and does not write them
1010      * to a property file, therefore we do not need to create property files
1011      * to store them.
1012      */
1013     if (!strncmp(prop_prefix, "ctl.", 4)) {
1014       free(prop_prefix);
1015       free(context);
1016       continue;
1017     }
1018 
1019     auto old_context =
1020         list_find(contexts, [context](context_node* l) { return !strcmp(l->context(), context); });
1021     if (old_context) {
1022       list_add_after_len(&prefixes, prop_prefix, old_context);
1023     } else {
1024       list_add(&contexts, context, nullptr);
1025       list_add_after_len(&prefixes, prop_prefix, contexts);
1026     }
1027     free(prop_prefix);
1028     free(context);
1029   }
1030 
1031   free(buffer);
1032   fclose(file);
1033 
1034   return true;
1035 }
1036 
initialize_properties()1037 static bool initialize_properties() {
1038   // If we do find /property_contexts, then this is being
1039   // run as part of the OTA updater on older release that had
1040   // /property_contexts - b/34370523
1041   if (initialize_properties_from_file("/property_contexts")) {
1042     return true;
1043   }
1044 
1045   // Use property_contexts from /system & /vendor, fall back to those from /
1046   if (access("/system/etc/selinux/plat_property_contexts", R_OK) != -1) {
1047     if (!initialize_properties_from_file("/system/etc/selinux/plat_property_contexts")) {
1048       return false;
1049     }
1050     // Don't check for failure here, so we always have a sane list of properties.
1051     // E.g. In case of recovery, the vendor partition will not have mounted and we
1052     // still need the system / platform properties to function.
1053     initialize_properties_from_file("/vendor/etc/selinux/nonplat_property_contexts");
1054   } else {
1055     if (!initialize_properties_from_file("/plat_property_contexts")) {
1056       return false;
1057     }
1058     initialize_properties_from_file("/nonplat_property_contexts");
1059   }
1060 
1061   return true;
1062 }
1063 
is_dir(const char * pathname)1064 static bool is_dir(const char* pathname) {
1065   struct stat info;
1066   if (stat(pathname, &info) == -1) {
1067     return false;
1068   }
1069   return S_ISDIR(info.st_mode);
1070 }
1071 
free_and_unmap_contexts()1072 static void free_and_unmap_contexts() {
1073   list_free(&prefixes);
1074   list_free(&contexts);
1075   if (__system_property_area__) {
1076     munmap(__system_property_area__, pa_size);
1077     __system_property_area__ = nullptr;
1078   }
1079 }
1080 
__system_properties_init()1081 int __system_properties_init() {
1082   // This is called from __libc_init_common, and should leave errno at 0 (http://b/37248982).
1083   ErrnoRestorer errno_restorer;
1084 
1085   if (initialized) {
1086     list_foreach(contexts, [](context_node* l) { l->reset_access(); });
1087     return 0;
1088   }
1089   if (is_dir(property_filename)) {
1090     if (!initialize_properties()) {
1091       return -1;
1092     }
1093     if (!map_system_property_area(false, nullptr)) {
1094       free_and_unmap_contexts();
1095       return -1;
1096     }
1097   } else {
1098     __system_property_area__ = map_prop_area(property_filename);
1099     if (!__system_property_area__) {
1100       return -1;
1101     }
1102     list_add(&contexts, "legacy_system_prop_area", __system_property_area__);
1103     list_add_after_len(&prefixes, "*", contexts);
1104   }
1105   initialized = true;
1106   return 0;
1107 }
1108 
__system_property_set_filename(const char * filename)1109 int __system_property_set_filename(const char* filename) {
1110   size_t len = strlen(filename);
1111   if (len >= sizeof(property_filename)) return -1;
1112 
1113   strcpy(property_filename, filename);
1114   return 0;
1115 }
1116 
__system_property_area_init()1117 int __system_property_area_init() {
1118   free_and_unmap_contexts();
1119   mkdir(property_filename, S_IRWXU | S_IXGRP | S_IXOTH);
1120   if (!initialize_properties()) {
1121     return -1;
1122   }
1123   bool open_failed = false;
1124   bool fsetxattr_failed = false;
1125   list_foreach(contexts, [&fsetxattr_failed, &open_failed](context_node* l) {
1126     if (!l->open(true, &fsetxattr_failed)) {
1127       open_failed = true;
1128     }
1129   });
1130   if (open_failed || !map_system_property_area(true, &fsetxattr_failed)) {
1131     free_and_unmap_contexts();
1132     return -1;
1133   }
1134   initialized = true;
1135   return fsetxattr_failed ? -2 : 0;
1136 }
1137 
__system_property_area_serial()1138 uint32_t __system_property_area_serial() {
1139   prop_area* pa = __system_property_area__;
1140   if (!pa) {
1141     return -1;
1142   }
1143   // Make sure this read fulfilled before __system_property_serial
1144   return atomic_load_explicit(pa->serial(), memory_order_acquire);
1145 }
1146 
__system_property_find(const char * name)1147 const prop_info* __system_property_find(const char* name) {
1148   if (!__system_property_area__) {
1149     return nullptr;
1150   }
1151 
1152   prop_area* pa = get_prop_area_for_name(name);
1153   if (!pa) {
1154     __libc_format_log(ANDROID_LOG_ERROR, "libc", "Access denied finding property \"%s\"", name);
1155     return nullptr;
1156   }
1157 
1158   return pa->find(name);
1159 }
1160 
1161 // The C11 standard doesn't allow atomic loads from const fields,
1162 // though C++11 does.  Fudge it until standards get straightened out.
load_const_atomic(const atomic_uint_least32_t * s,memory_order mo)1163 static inline uint_least32_t load_const_atomic(const atomic_uint_least32_t* s, memory_order mo) {
1164   atomic_uint_least32_t* non_const_s = const_cast<atomic_uint_least32_t*>(s);
1165   return atomic_load_explicit(non_const_s, mo);
1166 }
1167 
__system_property_read(const prop_info * pi,char * name,char * value)1168 int __system_property_read(const prop_info* pi, char* name, char* value) {
1169   while (true) {
1170     uint32_t serial = __system_property_serial(pi);  // acquire semantics
1171     size_t len = SERIAL_VALUE_LEN(serial);
1172     memcpy(value, pi->value, len + 1);
1173     // TODO: Fix the synchronization scheme here.
1174     // There is no fully supported way to implement this kind
1175     // of synchronization in C++11, since the memcpy races with
1176     // updates to pi, and the data being accessed is not atomic.
1177     // The following fence is unintuitive, but would be the
1178     // correct one if memcpy used memory_order_relaxed atomic accesses.
1179     // In practice it seems unlikely that the generated code would
1180     // would be any different, so this should be OK.
1181     atomic_thread_fence(memory_order_acquire);
1182     if (serial == load_const_atomic(&(pi->serial), memory_order_relaxed)) {
1183       if (name != nullptr) {
1184         size_t namelen = strlcpy(name, pi->name, PROP_NAME_MAX);
1185         if (namelen >= PROP_NAME_MAX) {
1186           __libc_format_log(ANDROID_LOG_ERROR, "libc",
1187                             "The property name length for \"%s\" is >= %d;"
1188                             " please use __system_property_read_callback"
1189                             " to read this property. (the name is truncated to \"%s\")",
1190                             pi->name, PROP_NAME_MAX - 1, name);
1191         }
1192       }
1193       return len;
1194     }
1195   }
1196 }
1197 
__system_property_read_callback(const prop_info * pi,void (* callback)(void * cookie,const char * name,const char * value,uint32_t serial),void * cookie)1198 void __system_property_read_callback(const prop_info* pi,
1199                                      void (*callback)(void* cookie,
1200                                                       const char* name,
1201                                                       const char* value,
1202                                                       uint32_t serial),
1203                                      void* cookie) {
1204   while (true) {
1205     uint32_t serial = __system_property_serial(pi);  // acquire semantics
1206     size_t len = SERIAL_VALUE_LEN(serial);
1207     char value_buf[len + 1];
1208 
1209     memcpy(value_buf, pi->value, len);
1210     value_buf[len] = '\0';
1211 
1212     // TODO: see todo in __system_property_read function
1213     atomic_thread_fence(memory_order_acquire);
1214     if (serial == load_const_atomic(&(pi->serial), memory_order_relaxed)) {
1215       callback(cookie, pi->name, value_buf, serial);
1216       return;
1217     }
1218   }
1219 }
1220 
__system_property_get(const char * name,char * value)1221 int __system_property_get(const char* name, char* value) {
1222   const prop_info* pi = __system_property_find(name);
1223 
1224   if (pi != 0) {
1225     return __system_property_read(pi, nullptr, value);
1226   } else {
1227     value[0] = 0;
1228     return 0;
1229   }
1230 }
1231 
1232 static constexpr uint32_t kProtocolVersion1 = 1;
1233 static constexpr uint32_t kProtocolVersion2 = 2;  // current
1234 
1235 static atomic_uint_least32_t g_propservice_protocol_version = 0;
1236 
detect_protocol_version()1237 static void detect_protocol_version() {
1238   char value[PROP_VALUE_MAX];
1239   if (__system_property_get(kServiceVersionPropertyName, value) == 0) {
1240     g_propservice_protocol_version = kProtocolVersion1;
1241     __libc_format_log(ANDROID_LOG_WARN, "libc",
1242                       "Using old property service protocol (\"%s\" is not set)",
1243                       kServiceVersionPropertyName);
1244   } else {
1245     uint32_t version = static_cast<uint32_t>(atoll(value));
1246     if (version >= kProtocolVersion2) {
1247       g_propservice_protocol_version = kProtocolVersion2;
1248     } else {
1249       __libc_format_log(ANDROID_LOG_WARN, "libc",
1250                         "Using old property service protocol (\"%s\"=\"%s\")",
1251                         kServiceVersionPropertyName, value);
1252       g_propservice_protocol_version = kProtocolVersion1;
1253     }
1254   }
1255 }
1256 
__system_property_set(const char * key,const char * value)1257 int __system_property_set(const char* key, const char* value) {
1258   if (key == nullptr) return -1;
1259   if (value == nullptr) value = "";
1260   if (strlen(value) >= PROP_VALUE_MAX) return -1;
1261 
1262   if (g_propservice_protocol_version == 0) {
1263     detect_protocol_version();
1264   }
1265 
1266   if (g_propservice_protocol_version == kProtocolVersion1) {
1267     // Old protocol does not support long names
1268     if (strlen(key) >= PROP_NAME_MAX) return -1;
1269 
1270     prop_msg msg;
1271     memset(&msg, 0, sizeof msg);
1272     msg.cmd = PROP_MSG_SETPROP;
1273     strlcpy(msg.name, key, sizeof msg.name);
1274     strlcpy(msg.value, value, sizeof msg.value);
1275 
1276     return send_prop_msg(&msg);
1277   } else {
1278     // Use proper protocol
1279     PropertyServiceConnection connection;
1280     if (!connection.IsValid()) {
1281       errno = connection.GetLastError();
1282       __libc_format_log(ANDROID_LOG_WARN,
1283                         "libc",
1284                         "Unable to set property \"%s\" to \"%s\": connection failed; errno=%d (%s)",
1285                         key,
1286                         value,
1287                         errno,
1288                         strerror(errno));
1289       return -1;
1290     }
1291 
1292     SocketWriter writer(&connection);
1293     if (!writer.WriteUint32(PROP_MSG_SETPROP2).WriteString(key).WriteString(value).Send()) {
1294       errno = connection.GetLastError();
1295       __libc_format_log(ANDROID_LOG_WARN,
1296                         "libc",
1297                         "Unable to set property \"%s\" to \"%s\": write failed; errno=%d (%s)",
1298                         key,
1299                         value,
1300                         errno,
1301                         strerror(errno));
1302       return -1;
1303     }
1304 
1305     int result = -1;
1306     if (!connection.RecvInt32(&result)) {
1307       errno = connection.GetLastError();
1308       __libc_format_log(ANDROID_LOG_WARN,
1309                         "libc",
1310                         "Unable to set property \"%s\" to \"%s\": recv failed; errno=%d (%s)",
1311                         key,
1312                         value,
1313                         errno,
1314                         strerror(errno));
1315       return -1;
1316     }
1317 
1318     if (result != PROP_SUCCESS) {
1319       __libc_format_log(ANDROID_LOG_WARN,
1320                         "libc",
1321                         "Unable to set property \"%s\" to \"%s\": error code: 0x%x",
1322                         key,
1323                         value,
1324                         result);
1325       return -1;
1326     }
1327 
1328     return 0;
1329   }
1330 }
1331 
__system_property_update(prop_info * pi,const char * value,unsigned int len)1332 int __system_property_update(prop_info* pi, const char* value, unsigned int len) {
1333   if (len >= PROP_VALUE_MAX) {
1334     return -1;
1335   }
1336 
1337   prop_area* pa = __system_property_area__;
1338 
1339   if (!pa) {
1340     return -1;
1341   }
1342 
1343   uint32_t serial = atomic_load_explicit(&pi->serial, memory_order_relaxed);
1344   serial |= 1;
1345   atomic_store_explicit(&pi->serial, serial, memory_order_relaxed);
1346   // The memcpy call here also races.  Again pretend it
1347   // used memory_order_relaxed atomics, and use the analogous
1348   // counterintuitive fence.
1349   atomic_thread_fence(memory_order_release);
1350   strlcpy(pi->value, value, len + 1);
1351 
1352   atomic_store_explicit(&pi->serial, (len << 24) | ((serial + 1) & 0xffffff), memory_order_release);
1353   __futex_wake(&pi->serial, INT32_MAX);
1354 
1355   atomic_store_explicit(pa->serial(), atomic_load_explicit(pa->serial(), memory_order_relaxed) + 1,
1356                         memory_order_release);
1357   __futex_wake(pa->serial(), INT32_MAX);
1358 
1359   return 0;
1360 }
1361 
__system_property_add(const char * name,unsigned int namelen,const char * value,unsigned int valuelen)1362 int __system_property_add(const char* name, unsigned int namelen, const char* value,
1363                           unsigned int valuelen) {
1364   if (valuelen >= PROP_VALUE_MAX) {
1365     return -1;
1366   }
1367 
1368   if (namelen < 1) {
1369     return -1;
1370   }
1371 
1372   if (!__system_property_area__) {
1373     return -1;
1374   }
1375 
1376   prop_area* pa = get_prop_area_for_name(name);
1377 
1378   if (!pa) {
1379     __libc_format_log(ANDROID_LOG_ERROR, "libc", "Access denied adding property \"%s\"", name);
1380     return -1;
1381   }
1382 
1383   bool ret = pa->add(name, namelen, value, valuelen);
1384   if (!ret) {
1385     return -1;
1386   }
1387 
1388   // There is only a single mutator, but we want to make sure that
1389   // updates are visible to a reader waiting for the update.
1390   atomic_store_explicit(
1391       __system_property_area__->serial(),
1392       atomic_load_explicit(__system_property_area__->serial(), memory_order_relaxed) + 1,
1393       memory_order_release);
1394   __futex_wake(__system_property_area__->serial(), INT32_MAX);
1395   return 0;
1396 }
1397 
1398 // Wait for non-locked serial, and retrieve it with acquire semantics.
__system_property_serial(const prop_info * pi)1399 uint32_t __system_property_serial(const prop_info* pi) {
1400   uint32_t serial = load_const_atomic(&pi->serial, memory_order_acquire);
1401   while (SERIAL_DIRTY(serial)) {
1402     __futex_wait(const_cast<_Atomic(uint_least32_t)*>(&pi->serial), serial, nullptr);
1403     serial = load_const_atomic(&pi->serial, memory_order_acquire);
1404   }
1405   return serial;
1406 }
1407 
__system_property_wait_any(uint32_t old_serial)1408 uint32_t __system_property_wait_any(uint32_t old_serial) {
1409   uint32_t new_serial;
1410   __system_property_wait(nullptr, old_serial, &new_serial, nullptr);
1411   return new_serial;
1412 }
1413 
__system_property_wait(const prop_info * pi,uint32_t old_serial,uint32_t * new_serial_ptr,const timespec * relative_timeout)1414 bool __system_property_wait(const prop_info* pi,
1415                             uint32_t old_serial,
1416                             uint32_t* new_serial_ptr,
1417                             const timespec* relative_timeout) {
1418   // Are we waiting on the global serial or a specific serial?
1419   atomic_uint_least32_t* serial_ptr;
1420   if (pi == nullptr) {
1421     if (__system_property_area__ == nullptr) return -1;
1422     serial_ptr = __system_property_area__->serial();
1423   } else {
1424     serial_ptr = const_cast<atomic_uint_least32_t*>(&pi->serial);
1425   }
1426 
1427   uint32_t new_serial;
1428   do {
1429     int rc;
1430     if ((rc = __futex_wait(serial_ptr, old_serial, relative_timeout)) != 0 && rc == -ETIMEDOUT) {
1431       return false;
1432     }
1433     new_serial = load_const_atomic(serial_ptr, memory_order_acquire);
1434   } while (new_serial == old_serial);
1435 
1436   *new_serial_ptr = new_serial;
1437   return true;
1438 }
1439 
__system_property_find_nth(unsigned n)1440 const prop_info* __system_property_find_nth(unsigned n) {
1441   struct find_nth {
1442     const uint32_t sought;
1443     uint32_t current;
1444     const prop_info* result;
1445 
1446     explicit find_nth(uint32_t n) : sought(n), current(0), result(nullptr) {}
1447     static void fn(const prop_info* pi, void* ptr) {
1448       find_nth* self = reinterpret_cast<find_nth*>(ptr);
1449       if (self->current++ == self->sought) self->result = pi;
1450     }
1451   } state(n);
1452   __system_property_foreach(find_nth::fn, &state);
1453   return state.result;
1454 }
1455 
__system_property_foreach(void (* propfn)(const prop_info * pi,void * cookie),void * cookie)1456 int __system_property_foreach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) {
1457   if (!__system_property_area__) {
1458     return -1;
1459   }
1460 
1461   list_foreach(contexts, [propfn, cookie](context_node* l) {
1462     if (l->check_access_and_open()) {
1463       l->pa()->foreach(propfn, cookie);
1464     }
1465   });
1466   return 0;
1467 }
1468