• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "property_service.h"
18 
19 #include <android/api-level.h>
20 #include <ctype.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <inttypes.h>
24 #include <limits.h>
25 #include <netinet/in.h>
26 #include <stdarg.h>
27 #include <stddef.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/mman.h>
32 #include <sys/poll.h>
33 #include <sys/select.h>
34 #include <sys/types.h>
35 #include <sys/un.h>
36 #include <unistd.h>
37 #include <wchar.h>
38 
39 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
40 #include <sys/_system_properties.h>
41 
42 #include <map>
43 #include <memory>
44 #include <queue>
45 #include <vector>
46 
47 #include <android-base/chrono_utils.h>
48 #include <android-base/file.h>
49 #include <android-base/logging.h>
50 #include <android-base/properties.h>
51 #include <android-base/stringprintf.h>
52 #include <android-base/strings.h>
53 #include <property_info_parser/property_info_parser.h>
54 #include <property_info_serializer/property_info_serializer.h>
55 #include <selinux/android.h>
56 #include <selinux/label.h>
57 #include <selinux/selinux.h>
58 
59 #include "debug_ramdisk.h"
60 #include "epoll.h"
61 #include "init.h"
62 #include "persistent_properties.h"
63 #include "property_type.h"
64 #include "selinux.h"
65 #include "subcontext.h"
66 #include "util.h"
67 
68 using namespace std::literals;
69 
70 using android::base::GetProperty;
71 using android::base::ReadFileToString;
72 using android::base::Split;
73 using android::base::StartsWith;
74 using android::base::StringPrintf;
75 using android::base::Timer;
76 using android::base::Trim;
77 using android::base::WriteStringToFile;
78 using android::properties::BuildTrie;
79 using android::properties::ParsePropertyInfoFile;
80 using android::properties::PropertyInfoAreaFile;
81 using android::properties::PropertyInfoEntry;
82 
83 namespace android {
84 namespace init {
85 
86 static bool persistent_properties_loaded = false;
87 
88 static int property_set_fd = -1;
89 
90 static PropertyInfoAreaFile property_info_area;
91 
92 uint32_t InitPropertySet(const std::string& name, const std::string& value);
93 
94 uint32_t (*property_set)(const std::string& name, const std::string& value) = InitPropertySet;
95 
96 void CreateSerializedPropertyInfo();
97 
98 struct PropertyAuditData {
99     const ucred* cr;
100     const char* name;
101 };
102 
property_init()103 void property_init() {
104     mkdir("/dev/__properties__", S_IRWXU | S_IXGRP | S_IXOTH);
105     CreateSerializedPropertyInfo();
106     if (__system_property_area_init()) {
107         LOG(FATAL) << "Failed to initialize property area";
108     }
109     if (!property_info_area.LoadDefaultPath()) {
110         LOG(FATAL) << "Failed to load serialized property info file";
111     }
112 }
113 
CanReadProperty(const std::string & source_context,const std::string & name)114 bool CanReadProperty(const std::string& source_context, const std::string& name) {
115     const char* target_context = nullptr;
116     property_info_area->GetPropertyInfo(name.c_str(), &target_context, nullptr);
117 
118     PropertyAuditData audit_data;
119 
120     audit_data.name = name.c_str();
121 
122     ucred cr = {.pid = 0, .uid = 0, .gid = 0};
123     audit_data.cr = &cr;
124 
125     return selinux_check_access(source_context.c_str(), target_context, "file", "read",
126                                 &audit_data) == 0;
127 }
128 
CheckMacPerms(const std::string & name,const char * target_context,const char * source_context,const ucred & cr)129 static bool CheckMacPerms(const std::string& name, const char* target_context,
130                           const char* source_context, const ucred& cr) {
131     if (!target_context || !source_context) {
132         return false;
133     }
134 
135     PropertyAuditData audit_data;
136 
137     audit_data.name = name.c_str();
138     audit_data.cr = &cr;
139 
140     bool has_access = (selinux_check_access(source_context, target_context, "property_service",
141                                             "set", &audit_data) == 0);
142 
143     return has_access;
144 }
145 
PropertySet(const std::string & name,const std::string & value,std::string * error)146 static uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error) {
147     size_t valuelen = value.size();
148 
149     if (!IsLegalPropertyName(name)) {
150         *error = "Illegal property name";
151         return PROP_ERROR_INVALID_NAME;
152     }
153 
154     if (valuelen >= PROP_VALUE_MAX && !StartsWith(name, "ro.")) {
155         *error = "Property value too long";
156         return PROP_ERROR_INVALID_VALUE;
157     }
158 
159     if (mbstowcs(nullptr, value.data(), 0) == static_cast<std::size_t>(-1)) {
160         *error = "Value is not a UTF8 encoded string";
161         return PROP_ERROR_INVALID_VALUE;
162     }
163 
164     prop_info* pi = (prop_info*) __system_property_find(name.c_str());
165     if (pi != nullptr) {
166         // ro.* properties are actually "write-once".
167         if (StartsWith(name, "ro.")) {
168             *error = "Read-only property was already set";
169             return PROP_ERROR_READ_ONLY_PROPERTY;
170         }
171 
172         __system_property_update(pi, value.c_str(), valuelen);
173     } else {
174         int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen);
175         if (rc < 0) {
176             *error = "__system_property_add failed";
177             return PROP_ERROR_SET_FAILED;
178         }
179     }
180 
181     // Don't write properties to disk until after we have read all default
182     // properties to prevent them from being overwritten by default values.
183     if (persistent_properties_loaded && StartsWith(name, "persist.")) {
184         WritePersistentProperty(name, value);
185     }
186     property_changed(name, value);
187     return PROP_SUCCESS;
188 }
189 
190 typedef int (*PropertyAsyncFunc)(const std::string&, const std::string&);
191 
192 struct PropertyChildInfo {
193     pid_t pid;
194     PropertyAsyncFunc func;
195     std::string name;
196     std::string value;
197 };
198 
199 static std::queue<PropertyChildInfo> property_children;
200 
PropertyChildLaunch()201 static void PropertyChildLaunch() {
202     auto& info = property_children.front();
203     pid_t pid = fork();
204     if (pid < 0) {
205         LOG(ERROR) << "Failed to fork for property_set_async";
206         while (!property_children.empty()) {
207             property_children.pop();
208         }
209         return;
210     }
211     if (pid != 0) {
212         info.pid = pid;
213     } else {
214         if (info.func(info.name, info.value) != 0) {
215             LOG(ERROR) << "property_set_async(\"" << info.name << "\", \"" << info.value
216                        << "\") failed";
217         }
218         _exit(0);
219     }
220 }
221 
PropertyChildReap(pid_t pid)222 bool PropertyChildReap(pid_t pid) {
223     if (property_children.empty()) {
224         return false;
225     }
226     auto& info = property_children.front();
227     if (info.pid != pid) {
228         return false;
229     }
230     std::string error;
231     if (PropertySet(info.name, info.value, &error) != PROP_SUCCESS) {
232         LOG(ERROR) << "Failed to set async property " << info.name << " to " << info.value << ": "
233                    << error;
234     }
235     property_children.pop();
236     if (!property_children.empty()) {
237         PropertyChildLaunch();
238     }
239     return true;
240 }
241 
PropertySetAsync(const std::string & name,const std::string & value,PropertyAsyncFunc func,std::string * error)242 static uint32_t PropertySetAsync(const std::string& name, const std::string& value,
243                                  PropertyAsyncFunc func, std::string* error) {
244     if (value.empty()) {
245         return PropertySet(name, value, error);
246     }
247 
248     PropertyChildInfo info;
249     info.func = func;
250     info.name = name;
251     info.value = value;
252     property_children.push(info);
253     if (property_children.size() == 1) {
254         PropertyChildLaunch();
255     }
256     return PROP_SUCCESS;
257 }
258 
RestoreconRecursiveAsync(const std::string & name,const std::string & value)259 static int RestoreconRecursiveAsync(const std::string& name, const std::string& value) {
260     return selinux_android_restorecon(value.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE);
261 }
262 
InitPropertySet(const std::string & name,const std::string & value)263 uint32_t InitPropertySet(const std::string& name, const std::string& value) {
264     if (StartsWith(name, "ctl.")) {
265         LOG(ERROR) << "InitPropertySet: Do not set ctl. properties from init; call the Service "
266                       "functions directly";
267         return PROP_ERROR_INVALID_NAME;
268     }
269     if (name == "selinux.restorecon_recursive") {
270         LOG(ERROR) << "InitPropertySet: Do not set selinux.restorecon_recursive from init; use the "
271                       "restorecon builtin directly";
272         return PROP_ERROR_INVALID_NAME;
273     }
274 
275     uint32_t result = 0;
276     ucred cr = {.pid = 1, .uid = 0, .gid = 0};
277     std::string error;
278     result = HandlePropertySet(name, value, kInitContext.c_str(), cr, &error);
279     if (result != PROP_SUCCESS) {
280         LOG(ERROR) << "Init cannot set '" << name << "' to '" << value << "': " << error;
281     }
282 
283     return result;
284 }
285 
286 class SocketConnection {
287   public:
SocketConnection(int socket,const ucred & cred)288     SocketConnection(int socket, const ucred& cred) : socket_(socket), cred_(cred) {}
289 
~SocketConnection()290     ~SocketConnection() { close(socket_); }
291 
RecvUint32(uint32_t * value,uint32_t * timeout_ms)292     bool RecvUint32(uint32_t* value, uint32_t* timeout_ms) {
293         return RecvFully(value, sizeof(*value), timeout_ms);
294     }
295 
RecvChars(char * chars,size_t size,uint32_t * timeout_ms)296     bool RecvChars(char* chars, size_t size, uint32_t* timeout_ms) {
297         return RecvFully(chars, size, timeout_ms);
298     }
299 
RecvString(std::string * value,uint32_t * timeout_ms)300     bool RecvString(std::string* value, uint32_t* timeout_ms) {
301         uint32_t len = 0;
302         if (!RecvUint32(&len, timeout_ms)) {
303             return false;
304         }
305 
306         if (len == 0) {
307             *value = "";
308             return true;
309         }
310 
311         // http://b/35166374: don't allow init to make arbitrarily large allocations.
312         if (len > 0xffff) {
313             LOG(ERROR) << "sys_prop: RecvString asked to read huge string: " << len;
314             errno = ENOMEM;
315             return false;
316         }
317 
318         std::vector<char> chars(len);
319         if (!RecvChars(&chars[0], len, timeout_ms)) {
320             return false;
321         }
322 
323         *value = std::string(&chars[0], len);
324         return true;
325     }
326 
SendUint32(uint32_t value)327     bool SendUint32(uint32_t value) {
328         int result = TEMP_FAILURE_RETRY(send(socket_, &value, sizeof(value), 0));
329         return result == sizeof(value);
330     }
331 
socket()332     int socket() { return socket_; }
333 
cred()334     const ucred& cred() { return cred_; }
335 
source_context() const336     std::string source_context() const {
337         char* source_context = nullptr;
338         getpeercon(socket_, &source_context);
339         std::string result = source_context;
340         freecon(source_context);
341         return result;
342     }
343 
344   private:
PollIn(uint32_t * timeout_ms)345     bool PollIn(uint32_t* timeout_ms) {
346         struct pollfd ufds[1];
347         ufds[0].fd = socket_;
348         ufds[0].events = POLLIN;
349         ufds[0].revents = 0;
350         while (*timeout_ms > 0) {
351             auto start_time = std::chrono::steady_clock::now();
352             int nr = poll(ufds, 1, *timeout_ms);
353             auto now = std::chrono::steady_clock::now();
354             auto time_elapsed =
355                 std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
356             uint64_t millis = time_elapsed.count();
357             *timeout_ms = (millis > *timeout_ms) ? 0 : *timeout_ms - millis;
358 
359             if (nr > 0) {
360                 return true;
361             }
362 
363             if (nr == 0) {
364                 // Timeout
365                 break;
366             }
367 
368             if (nr < 0 && errno != EINTR) {
369                 PLOG(ERROR) << "sys_prop: error waiting for uid " << cred_.uid
370                             << " to send property message";
371                 return false;
372             } else {  // errno == EINTR
373                 // Timer rounds milliseconds down in case of EINTR we want it to be rounded up
374                 // to avoid slowing init down by causing EINTR with under millisecond timeout.
375                 if (*timeout_ms > 0) {
376                     --(*timeout_ms);
377                 }
378             }
379         }
380 
381         LOG(ERROR) << "sys_prop: timeout waiting for uid " << cred_.uid
382                    << " to send property message.";
383         return false;
384     }
385 
RecvFully(void * data_ptr,size_t size,uint32_t * timeout_ms)386     bool RecvFully(void* data_ptr, size_t size, uint32_t* timeout_ms) {
387         size_t bytes_left = size;
388         char* data = static_cast<char*>(data_ptr);
389         while (*timeout_ms > 0 && bytes_left > 0) {
390             if (!PollIn(timeout_ms)) {
391                 return false;
392             }
393 
394             int result = TEMP_FAILURE_RETRY(recv(socket_, data, bytes_left, MSG_DONTWAIT));
395             if (result <= 0) {
396                 PLOG(ERROR) << "sys_prop: recv error";
397                 return false;
398             }
399 
400             bytes_left -= result;
401             data += result;
402         }
403 
404         if (bytes_left != 0) {
405             LOG(ERROR) << "sys_prop: recv data is not properly obtained.";
406         }
407 
408         return bytes_left == 0;
409     }
410 
411     int socket_;
412     ucred cred_;
413 
414     DISALLOW_IMPLICIT_CONSTRUCTORS(SocketConnection);
415 };
416 
CheckControlPropertyPerms(const std::string & name,const std::string & value,const std::string & source_context,const ucred & cr)417 bool CheckControlPropertyPerms(const std::string& name, const std::string& value,
418                                const std::string& source_context, const ucred& cr) {
419     // We check the legacy method first but these properties are dontaudit, so we only log an audit
420     // if the newer method fails as well.  We only do this with the legacy ctl. properties.
421     if (name == "ctl.start" || name == "ctl.stop" || name == "ctl.restart") {
422         // The legacy permissions model is that ctl. properties have their name ctl.<action> and
423         // their value is the name of the service to apply that action to.  Permissions for these
424         // actions are based on the service, so we must create a fake name of ctl.<service> to
425         // check permissions.
426         auto control_string_legacy = "ctl." + value;
427         const char* target_context_legacy = nullptr;
428         const char* type_legacy = nullptr;
429         property_info_area->GetPropertyInfo(control_string_legacy.c_str(), &target_context_legacy,
430                                             &type_legacy);
431 
432         if (CheckMacPerms(control_string_legacy, target_context_legacy, source_context.c_str(), cr)) {
433             return true;
434         }
435     }
436 
437     auto control_string_full = name + "$" + value;
438     const char* target_context_full = nullptr;
439     const char* type_full = nullptr;
440     property_info_area->GetPropertyInfo(control_string_full.c_str(), &target_context_full,
441                                         &type_full);
442 
443     return CheckMacPerms(control_string_full, target_context_full, source_context.c_str(), cr);
444 }
445 
446 // This returns one of the enum of PROP_SUCCESS or PROP_ERROR*.
CheckPermissions(const std::string & name,const std::string & value,const std::string & source_context,const ucred & cr,std::string * error)447 uint32_t CheckPermissions(const std::string& name, const std::string& value,
448                           const std::string& source_context, const ucred& cr, std::string* error) {
449     if (!IsLegalPropertyName(name)) {
450         *error = "Illegal property name";
451         return PROP_ERROR_INVALID_NAME;
452     }
453 
454     if (StartsWith(name, "ctl.")) {
455         if (!CheckControlPropertyPerms(name, value, source_context, cr)) {
456             *error = StringPrintf("Invalid permissions to perform '%s' on '%s'", name.c_str() + 4,
457                                   value.c_str());
458             return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
459         }
460 
461         return PROP_SUCCESS;
462     }
463 
464     const char* target_context = nullptr;
465     const char* type = nullptr;
466     property_info_area->GetPropertyInfo(name.c_str(), &target_context, &type);
467 
468     if (!CheckMacPerms(name, target_context, source_context.c_str(), cr)) {
469         *error = "SELinux permission check failed";
470         return PROP_ERROR_PERMISSION_DENIED;
471     }
472 
473     if (type == nullptr || !CheckType(type, value)) {
474         *error = StringPrintf("Property type check failed, value doesn't match expected type '%s'",
475                               (type ?: "(null)"));
476         return PROP_ERROR_INVALID_VALUE;
477     }
478 
479     return PROP_SUCCESS;
480 }
481 
482 // This returns one of the enum of PROP_SUCCESS or PROP_ERROR*.
HandlePropertySet(const std::string & name,const std::string & value,const std::string & source_context,const ucred & cr,std::string * error)483 uint32_t HandlePropertySet(const std::string& name, const std::string& value,
484                            const std::string& source_context, const ucred& cr, std::string* error) {
485     if (auto ret = CheckPermissions(name, value, source_context, cr, error); ret != PROP_SUCCESS) {
486         return ret;
487     }
488 
489     if (StartsWith(name, "ctl.")) {
490         HandleControlMessage(name.c_str() + 4, value, cr.pid);
491         return PROP_SUCCESS;
492     }
493 
494     // sys.powerctl is a special property that is used to make the device reboot.  We want to log
495     // any process that sets this property to be able to accurately blame the cause of a shutdown.
496     if (name == "sys.powerctl") {
497         std::string cmdline_path = StringPrintf("proc/%d/cmdline", cr.pid);
498         std::string process_cmdline;
499         std::string process_log_string;
500         if (ReadFileToString(cmdline_path, &process_cmdline)) {
501             // Since cmdline is null deliminated, .c_str() conveniently gives us just the process
502             // path.
503             process_log_string = StringPrintf(" (%s)", process_cmdline.c_str());
504         }
505         LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
506                   << process_log_string;
507     }
508 
509     if (name == "selinux.restorecon_recursive") {
510         return PropertySetAsync(name, value, RestoreconRecursiveAsync, error);
511     }
512 
513     return PropertySet(name, value, error);
514 }
515 
handle_property_set_fd()516 static void handle_property_set_fd() {
517     static constexpr uint32_t kDefaultSocketTimeout = 2000; /* ms */
518 
519     int s = accept4(property_set_fd, nullptr, nullptr, SOCK_CLOEXEC);
520     if (s == -1) {
521         return;
522     }
523 
524     ucred cr;
525     socklen_t cr_size = sizeof(cr);
526     if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
527         close(s);
528         PLOG(ERROR) << "sys_prop: unable to get SO_PEERCRED";
529         return;
530     }
531 
532     SocketConnection socket(s, cr);
533     uint32_t timeout_ms = kDefaultSocketTimeout;
534 
535     uint32_t cmd = 0;
536     if (!socket.RecvUint32(&cmd, &timeout_ms)) {
537         PLOG(ERROR) << "sys_prop: error while reading command from the socket";
538         socket.SendUint32(PROP_ERROR_READ_CMD);
539         return;
540     }
541 
542     switch (cmd) {
543     case PROP_MSG_SETPROP: {
544         char prop_name[PROP_NAME_MAX];
545         char prop_value[PROP_VALUE_MAX];
546 
547         if (!socket.RecvChars(prop_name, PROP_NAME_MAX, &timeout_ms) ||
548             !socket.RecvChars(prop_value, PROP_VALUE_MAX, &timeout_ms)) {
549           PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP): error while reading name/value from the socket";
550           return;
551         }
552 
553         prop_name[PROP_NAME_MAX-1] = 0;
554         prop_value[PROP_VALUE_MAX-1] = 0;
555 
556         const auto& cr = socket.cred();
557         std::string error;
558         uint32_t result =
559             HandlePropertySet(prop_name, prop_value, socket.source_context(), cr, &error);
560         if (result != PROP_SUCCESS) {
561             LOG(ERROR) << "Unable to set property '" << prop_name << "' to '" << prop_value
562                        << "' from uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid << ": "
563                        << error;
564         }
565 
566         break;
567       }
568 
569     case PROP_MSG_SETPROP2: {
570         std::string name;
571         std::string value;
572         if (!socket.RecvString(&name, &timeout_ms) ||
573             !socket.RecvString(&value, &timeout_ms)) {
574           PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP2): error while reading name/value from the socket";
575           socket.SendUint32(PROP_ERROR_READ_DATA);
576           return;
577         }
578 
579         const auto& cr = socket.cred();
580         std::string error;
581         uint32_t result = HandlePropertySet(name, value, socket.source_context(), cr, &error);
582         if (result != PROP_SUCCESS) {
583             LOG(ERROR) << "Unable to set property '" << name << "' to '" << value
584                        << "' from uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid << ": "
585                        << error;
586         }
587         socket.SendUint32(result);
588         break;
589       }
590 
591     default:
592         LOG(ERROR) << "sys_prop: invalid command " << cmd;
593         socket.SendUint32(PROP_ERROR_INVALID_CMD);
594         break;
595     }
596 }
597 
598 static bool load_properties_from_file(const char*, const char*,
599                                       std::map<std::string, std::string>*);
600 
601 /*
602  * Filter is used to decide which properties to load: NULL loads all keys,
603  * "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match.
604  */
LoadProperties(char * data,const char * filter,const char * filename,std::map<std::string,std::string> * properties)605 static void LoadProperties(char* data, const char* filter, const char* filename,
606                            std::map<std::string, std::string>* properties) {
607     char *key, *value, *eol, *sol, *tmp, *fn;
608     size_t flen = 0;
609 
610     const char* context = kInitContext.c_str();
611     if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_P__) {
612         for (const auto& [path_prefix, secontext] : paths_and_secontexts) {
613             if (StartsWith(filename, path_prefix)) {
614                 context = secontext;
615             }
616         }
617     }
618 
619     if (filter) {
620         flen = strlen(filter);
621     }
622 
623     sol = data;
624     while ((eol = strchr(sol, '\n'))) {
625         key = sol;
626         *eol++ = 0;
627         sol = eol;
628 
629         while (isspace(*key)) key++;
630         if (*key == '#') continue;
631 
632         tmp = eol - 2;
633         while ((tmp > key) && isspace(*tmp)) *tmp-- = 0;
634 
635         if (!strncmp(key, "import ", 7) && flen == 0) {
636             fn = key + 7;
637             while (isspace(*fn)) fn++;
638 
639             key = strchr(fn, ' ');
640             if (key) {
641                 *key++ = 0;
642                 while (isspace(*key)) key++;
643             }
644 
645             std::string raw_filename(fn);
646             std::string expanded_filename;
647             if (!expand_props(raw_filename, &expanded_filename)) {
648                 LOG(ERROR) << "Could not expand filename '" << raw_filename << "'";
649                 continue;
650             }
651 
652             load_properties_from_file(expanded_filename.c_str(), key, properties);
653         } else {
654             value = strchr(key, '=');
655             if (!value) continue;
656             *value++ = 0;
657 
658             tmp = value - 2;
659             while ((tmp > key) && isspace(*tmp)) *tmp-- = 0;
660 
661             while (isspace(*value)) value++;
662 
663             if (flen > 0) {
664                 if (filter[flen - 1] == '*') {
665                     if (strncmp(key, filter, flen - 1)) continue;
666                 } else {
667                     if (strcmp(key, filter)) continue;
668                 }
669             }
670 
671             if (StartsWith(key, "ctl.") || key == "sys.powerctl"s ||
672                 key == "selinux.restorecon_recursive"s) {
673                 LOG(ERROR) << "Ignoring disallowed property '" << key
674                            << "' with special meaning in prop file '" << filename << "'";
675                 continue;
676             }
677 
678             ucred cr = {.pid = 1, .uid = 0, .gid = 0};
679             std::string error;
680             if (CheckPermissions(key, value, context, cr, &error) == PROP_SUCCESS) {
681                 auto it = properties->find(key);
682                 if (it == properties->end()) {
683                     (*properties)[key] = value;
684                 } else if (it->second != value) {
685                     LOG(WARNING) << "Overriding previous 'ro.' property '" << key << "':'"
686                                  << it->second << "' with new value '" << value << "'";
687                     it->second = value;
688                 }
689             } else {
690                 LOG(ERROR) << "Do not have permissions to set '" << key << "' to '" << value
691                            << "' in property file '" << filename << "': " << error;
692             }
693         }
694     }
695 }
696 
697 // Filter is used to decide which properties to load: NULL loads all keys,
698 // "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match.
load_properties_from_file(const char * filename,const char * filter,std::map<std::string,std::string> * properties)699 static bool load_properties_from_file(const char* filename, const char* filter,
700                                       std::map<std::string, std::string>* properties) {
701     Timer t;
702     auto file_contents = ReadFile(filename);
703     if (!file_contents) {
704         PLOG(WARNING) << "Couldn't load property file '" << filename
705                       << "': " << file_contents.error();
706         return false;
707     }
708     file_contents->push_back('\n');
709 
710     LoadProperties(file_contents->data(), filter, filename, properties);
711     LOG(VERBOSE) << "(Loading properties from " << filename << " took " << t << ".)";
712     return true;
713 }
714 
715 // persist.sys.usb.config values can't be combined on build-time when property
716 // files are split into each partition.
717 // So we need to apply the same rule of build/make/tools/post_process_props.py
718 // on runtime.
update_sys_usb_config()719 static void update_sys_usb_config() {
720     bool is_debuggable = android::base::GetBoolProperty("ro.debuggable", false);
721     std::string config = android::base::GetProperty("persist.sys.usb.config", "");
722     if (config.empty()) {
723         property_set("persist.sys.usb.config", is_debuggable ? "adb" : "none");
724     } else if (is_debuggable && config.find("adb") == std::string::npos &&
725                config.length() + 4 < PROP_VALUE_MAX) {
726         config.append(",adb");
727         property_set("persist.sys.usb.config", config);
728     }
729 }
730 
load_override_properties()731 static void load_override_properties() {
732     if (ALLOW_LOCAL_PROP_OVERRIDE) {
733         std::map<std::string, std::string> properties;
734         load_properties_from_file("/data/local.prop", nullptr, &properties);
735         for (const auto& [name, value] : properties) {
736             std::string error;
737             if (PropertySet(name, value, &error) != PROP_SUCCESS) {
738                 LOG(ERROR) << "Could not set '" << name << "' to '" << value
739                            << "' in /data/local.prop: " << error;
740             }
741         }
742     }
743 }
744 
745 /* When booting an encrypted system, /data is not mounted when the
746  * property service is started, so any properties stored there are
747  * not loaded.  Vold triggers init to load these properties once it
748  * has mounted /data.
749  */
load_persist_props(void)750 void load_persist_props(void) {
751     // Devices with FDE have load_persist_props called twice; the first time when the temporary
752     // /data partition is mounted and then again once /data is truly mounted.  We do not want to
753     // read persistent properties from the temporary /data partition or mark persistent properties
754     // as having been loaded during the first call, so we return in that case.
755     std::string crypto_state = android::base::GetProperty("ro.crypto.state", "");
756     std::string crypto_type = android::base::GetProperty("ro.crypto.type", "");
757     if (crypto_state == "encrypted" && crypto_type == "block") {
758         static size_t num_calls = 0;
759         if (++num_calls == 1) return;
760     }
761 
762     load_override_properties();
763     /* Read persistent properties after all default values have been loaded. */
764     auto persistent_properties = LoadPersistentProperties();
765     for (const auto& persistent_property_record : persistent_properties.properties()) {
766         property_set(persistent_property_record.name(), persistent_property_record.value());
767     }
768     persistent_properties_loaded = true;
769     property_set("ro.persistent_properties.ready", "true");
770 }
771 
772 // If the ro.product.[brand|device|manufacturer|model|name] properties have not been explicitly
773 // set, derive them from ro.product.${partition}.* properties
property_initialize_ro_product_props()774 static void property_initialize_ro_product_props() {
775     const char* RO_PRODUCT_PROPS_PREFIX = "ro.product.";
776     const char* RO_PRODUCT_PROPS[] = {
777             "brand", "device", "manufacturer", "model", "name",
778     };
779     const char* RO_PRODUCT_PROPS_ALLOWED_SOURCES[] = {
780             "odm", "product", "product_services", "system", "vendor",
781     };
782     const char* RO_PRODUCT_PROPS_DEFAULT_SOURCE_ORDER =
783             "product,product_services,odm,vendor,system";
784     const std::string EMPTY = "";
785 
786     std::string ro_product_props_source_order =
787             GetProperty("ro.product.property_source_order", EMPTY);
788 
789     if (!ro_product_props_source_order.empty()) {
790         // Verify that all specified sources are valid
791         for (const auto& source : Split(ro_product_props_source_order, ",")) {
792             // Verify that the specified source is valid
793             bool is_allowed_source = false;
794             for (const auto& allowed_source : RO_PRODUCT_PROPS_ALLOWED_SOURCES) {
795                 if (source == allowed_source) {
796                     is_allowed_source = true;
797                     break;
798                 }
799             }
800             if (!is_allowed_source) {
801                 LOG(ERROR) << "Found unexpected source in ro.product.property_source_order; "
802                               "using the default property source order";
803                 ro_product_props_source_order = RO_PRODUCT_PROPS_DEFAULT_SOURCE_ORDER;
804                 break;
805             }
806         }
807     } else {
808         ro_product_props_source_order = RO_PRODUCT_PROPS_DEFAULT_SOURCE_ORDER;
809     }
810 
811     for (const auto& ro_product_prop : RO_PRODUCT_PROPS) {
812         std::string base_prop(RO_PRODUCT_PROPS_PREFIX);
813         base_prop += ro_product_prop;
814 
815         std::string base_prop_val = GetProperty(base_prop, EMPTY);
816         if (!base_prop_val.empty()) {
817             continue;
818         }
819 
820         for (const auto& source : Split(ro_product_props_source_order, ",")) {
821             std::string target_prop(RO_PRODUCT_PROPS_PREFIX);
822             target_prop += source;
823             target_prop += '.';
824             target_prop += ro_product_prop;
825 
826             std::string target_prop_val = GetProperty(target_prop, EMPTY);
827             if (!target_prop_val.empty()) {
828                 LOG(INFO) << "Setting product property " << base_prop << " to '" << target_prop_val
829                           << "' (from " << target_prop << ")";
830                 std::string error;
831                 uint32_t res = PropertySet(base_prop, target_prop_val, &error);
832                 if (res != PROP_SUCCESS) {
833                     LOG(ERROR) << "Error setting product property " << base_prop << ": err=" << res
834                                << " (" << error << ")";
835                 }
836                 break;
837             }
838         }
839     }
840 }
841 
842 // If the ro.build.fingerprint property has not been set, derive it from constituent pieces
property_derive_build_fingerprint()843 static void property_derive_build_fingerprint() {
844     std::string build_fingerprint = GetProperty("ro.build.fingerprint", "");
845     if (!build_fingerprint.empty()) {
846         return;
847     }
848 
849     const std::string UNKNOWN = "unknown";
850     build_fingerprint = GetProperty("ro.product.brand", UNKNOWN);
851     build_fingerprint += '/';
852     build_fingerprint += GetProperty("ro.product.name", UNKNOWN);
853     build_fingerprint += '/';
854     build_fingerprint += GetProperty("ro.product.device", UNKNOWN);
855     build_fingerprint += ':';
856     build_fingerprint += GetProperty("ro.build.version.release", UNKNOWN);
857     build_fingerprint += '/';
858     build_fingerprint += GetProperty("ro.build.id", UNKNOWN);
859     build_fingerprint += '/';
860     build_fingerprint += GetProperty("ro.build.version.incremental", UNKNOWN);
861     build_fingerprint += ':';
862     build_fingerprint += GetProperty("ro.build.type", UNKNOWN);
863     build_fingerprint += '/';
864     build_fingerprint += GetProperty("ro.build.tags", UNKNOWN);
865 
866     LOG(INFO) << "Setting property 'ro.build.fingerprint' to '" << build_fingerprint << "'";
867 
868     std::string error;
869     uint32_t res = PropertySet("ro.build.fingerprint", build_fingerprint, &error);
870     if (res != PROP_SUCCESS) {
871         LOG(ERROR) << "Error setting property 'ro.build.fingerprint': err=" << res << " (" << error
872                    << ")";
873     }
874 }
875 
property_load_boot_defaults(bool load_debug_prop)876 void property_load_boot_defaults(bool load_debug_prop) {
877     // TODO(b/117892318): merge prop.default and build.prop files into one
878     // We read the properties and their values into a map, in order to always allow properties
879     // loaded in the later property files to override the properties in loaded in the earlier
880     // property files, regardless of if they are "ro." properties or not.
881     std::map<std::string, std::string> properties;
882     if (!load_properties_from_file("/system/etc/prop.default", nullptr, &properties)) {
883         // Try recovery path
884         if (!load_properties_from_file("/prop.default", nullptr, &properties)) {
885             // Try legacy path
886             load_properties_from_file("/default.prop", nullptr, &properties);
887         }
888     }
889     load_properties_from_file("/system/build.prop", nullptr, &properties);
890     load_properties_from_file("/vendor/default.prop", nullptr, &properties);
891     load_properties_from_file("/vendor/build.prop", nullptr, &properties);
892     if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_Q__) {
893         load_properties_from_file("/odm/etc/build.prop", nullptr, &properties);
894     } else {
895         load_properties_from_file("/odm/default.prop", nullptr, &properties);
896         load_properties_from_file("/odm/build.prop", nullptr, &properties);
897     }
898     load_properties_from_file("/product/build.prop", nullptr, &properties);
899     load_properties_from_file("/product_services/build.prop", nullptr, &properties);
900     load_properties_from_file("/factory/factory.prop", "ro.*", &properties);
901 
902     if (load_debug_prop) {
903         LOG(INFO) << "Loading " << kDebugRamdiskProp;
904         load_properties_from_file(kDebugRamdiskProp, nullptr, &properties);
905     }
906 
907     for (const auto& [name, value] : properties) {
908         std::string error;
909         if (PropertySet(name, value, &error) != PROP_SUCCESS) {
910             LOG(ERROR) << "Could not set '" << name << "' to '" << value
911                        << "' while loading .prop files" << error;
912         }
913     }
914 
915     property_initialize_ro_product_props();
916     property_derive_build_fingerprint();
917 
918     update_sys_usb_config();
919 }
920 
SelinuxAuditCallback(void * data,security_class_t,char * buf,size_t len)921 static int SelinuxAuditCallback(void* data, security_class_t /*cls*/, char* buf, size_t len) {
922     auto* d = reinterpret_cast<PropertyAuditData*>(data);
923 
924     if (!d || !d->name || !d->cr) {
925         LOG(ERROR) << "AuditCallback invoked with null data arguments!";
926         return 0;
927     }
928 
929     snprintf(buf, len, "property=%s pid=%d uid=%d gid=%d", d->name, d->cr->pid, d->cr->uid,
930              d->cr->gid);
931     return 0;
932 }
933 
LoadPropertyInfoFromFile(const std::string & filename,std::vector<PropertyInfoEntry> * property_infos)934 bool LoadPropertyInfoFromFile(const std::string& filename,
935                               std::vector<PropertyInfoEntry>* property_infos) {
936     auto file_contents = std::string();
937     if (!ReadFileToString(filename, &file_contents)) {
938         PLOG(ERROR) << "Could not read properties from '" << filename << "'";
939         return false;
940     }
941 
942     auto errors = std::vector<std::string>{};
943     ParsePropertyInfoFile(file_contents, property_infos, &errors);
944     // Individual parsing errors are reported but do not cause a failed boot, which is what
945     // returning false would do here.
946     for (const auto& error : errors) {
947         LOG(ERROR) << "Could not read line from '" << filename << "': " << error;
948     }
949 
950     return true;
951 }
952 
CreateSerializedPropertyInfo()953 void CreateSerializedPropertyInfo() {
954     auto property_infos = std::vector<PropertyInfoEntry>();
955     if (access("/system/etc/selinux/plat_property_contexts", R_OK) != -1) {
956         if (!LoadPropertyInfoFromFile("/system/etc/selinux/plat_property_contexts",
957                                       &property_infos)) {
958             return;
959         }
960         // Don't check for failure here, so we always have a sane list of properties.
961         // E.g. In case of recovery, the vendor partition will not have mounted and we
962         // still need the system / platform properties to function.
963         if (!LoadPropertyInfoFromFile("/vendor/etc/selinux/vendor_property_contexts",
964                                       &property_infos)) {
965             // Fallback to nonplat_* if vendor_* doesn't exist.
966             LoadPropertyInfoFromFile("/vendor/etc/selinux/nonplat_property_contexts",
967                                      &property_infos);
968         }
969         if (access("/product/etc/selinux/product_property_contexts", R_OK) != -1) {
970             LoadPropertyInfoFromFile("/product/etc/selinux/product_property_contexts",
971                                      &property_infos);
972         }
973         if (access("/odm/etc/selinux/odm_property_contexts", R_OK) != -1) {
974             LoadPropertyInfoFromFile("/odm/etc/selinux/odm_property_contexts", &property_infos);
975         }
976     } else {
977         if (!LoadPropertyInfoFromFile("/plat_property_contexts", &property_infos)) {
978             return;
979         }
980         if (!LoadPropertyInfoFromFile("/vendor_property_contexts", &property_infos)) {
981             // Fallback to nonplat_* if vendor_* doesn't exist.
982             LoadPropertyInfoFromFile("/nonplat_property_contexts", &property_infos);
983         }
984         LoadPropertyInfoFromFile("/product_property_contexts", &property_infos);
985         LoadPropertyInfoFromFile("/odm_property_contexts", &property_infos);
986     }
987 
988     auto serialized_contexts = std::string();
989     auto error = std::string();
990     if (!BuildTrie(property_infos, "u:object_r:default_prop:s0", "string", &serialized_contexts,
991                    &error)) {
992         LOG(ERROR) << "Unable to serialize property contexts: " << error;
993         return;
994     }
995 
996     constexpr static const char kPropertyInfosPath[] = "/dev/__properties__/property_info";
997     if (!WriteStringToFile(serialized_contexts, kPropertyInfosPath, 0444, 0, 0, false)) {
998         PLOG(ERROR) << "Unable to write serialized property infos to file";
999     }
1000     selinux_android_restorecon(kPropertyInfosPath, 0);
1001 }
1002 
StartPropertyService(Epoll * epoll)1003 void StartPropertyService(Epoll* epoll) {
1004     selinux_callback cb;
1005     cb.func_audit = SelinuxAuditCallback;
1006     selinux_set_callback(SELINUX_CB_AUDIT, cb);
1007 
1008     property_set("ro.property_service.version", "2");
1009 
1010     property_set_fd = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
1011                                    false, 0666, 0, 0, nullptr);
1012     if (property_set_fd == -1) {
1013         PLOG(FATAL) << "start_property_service socket creation failed";
1014     }
1015 
1016     listen(property_set_fd, 8);
1017 
1018     if (auto result = epoll->RegisterHandler(property_set_fd, handle_property_set_fd); !result) {
1019         PLOG(FATAL) << result.error();
1020     }
1021 }
1022 
1023 }  // namespace init
1024 }  // namespace android
1025