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 <ctype.h>
20#include <errno.h>
21#include <fcntl.h>
22#include <inttypes.h>
23#include <limits.h>
24#include <netinet/in.h>
25#include <stdarg.h>
26#include <stddef.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <sys/mman.h>
31#include <sys/poll.h>
32#include <sys/select.h>
33#include <sys/types.h>
34#include <sys/un.h>
35#include <unistd.h>
36#include <wchar.h>
37
38#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
39#include <sys/_system_properties.h>
40
41#include <memory>
42#include <queue>
43#include <vector>
44
45#include <android-base/chrono_utils.h>
46#include <android-base/file.h>
47#include <android-base/logging.h>
48#include <android-base/properties.h>
49#include <android-base/stringprintf.h>
50#include <android-base/strings.h>
51#include <bootimg.h>
52#include <fs_mgr.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 "init.h"
60#include "persistent_properties.h"
61#include "property_type.h"
62#include "selinux.h"
63#include "subcontext.h"
64#include "util.h"
65
66using namespace std::literals;
67
68using android::base::GetIntProperty;
69using android::base::ReadFileToString;
70using android::base::Split;
71using android::base::StartsWith;
72using android::base::StringPrintf;
73using android::base::Timer;
74using android::base::Trim;
75using android::base::WriteStringToFile;
76using android::properties::BuildTrie;
77using android::properties::ParsePropertyInfoFile;
78using android::properties::PropertyInfoAreaFile;
79using android::properties::PropertyInfoEntry;
80
81#define RECOVERY_MOUNT_POINT "/recovery"
82
83namespace android {
84namespace init {
85
86static bool persistent_properties_loaded = false;
87
88static int property_set_fd = -1;
89
90static PropertyInfoAreaFile property_info_area;
91
92uint32_t InitPropertySet(const std::string& name, const std::string& value);
93
94uint32_t (*property_set)(const std::string& name, const std::string& value) = InitPropertySet;
95
96void CreateSerializedPropertyInfo();
97
98struct PropertyAuditData {
99    const ucred* cr;
100    const char* name;
101};
102
103void 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}
113static bool CheckMacPerms(const std::string& name, const char* target_context,
114                          const char* source_context, const ucred& cr) {
115    if (!target_context || !source_context) {
116        return false;
117    }
118
119    PropertyAuditData audit_data;
120
121    audit_data.name = name.c_str();
122    audit_data.cr = &cr;
123
124    bool has_access = (selinux_check_access(source_context, target_context, "property_service",
125                                            "set", &audit_data) == 0);
126
127    return has_access;
128}
129
130static uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error) {
131    size_t valuelen = value.size();
132
133    if (!IsLegalPropertyName(name)) {
134        *error = "Illegal property name";
135        return PROP_ERROR_INVALID_NAME;
136    }
137
138    if (valuelen >= PROP_VALUE_MAX && !StartsWith(name, "ro.")) {
139        *error = "Property value too long";
140        return PROP_ERROR_INVALID_VALUE;
141    }
142
143    if (mbstowcs(nullptr, value.data(), 0) == static_cast<std::size_t>(-1)) {
144        *error = "Value is not a UTF8 encoded string";
145        return PROP_ERROR_INVALID_VALUE;
146    }
147
148    prop_info* pi = (prop_info*) __system_property_find(name.c_str());
149    if (pi != nullptr) {
150        // ro.* properties are actually "write-once".
151        if (StartsWith(name, "ro.")) {
152            *error = "Read-only property was already set";
153            return PROP_ERROR_READ_ONLY_PROPERTY;
154        }
155
156        __system_property_update(pi, value.c_str(), valuelen);
157    } else {
158        int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen);
159        if (rc < 0) {
160            *error = "__system_property_add failed";
161            return PROP_ERROR_SET_FAILED;
162        }
163    }
164
165    // Don't write properties to disk until after we have read all default
166    // properties to prevent them from being overwritten by default values.
167    if (persistent_properties_loaded && StartsWith(name, "persist.")) {
168        WritePersistentProperty(name, value);
169    }
170    property_changed(name, value);
171    return PROP_SUCCESS;
172}
173
174typedef int (*PropertyAsyncFunc)(const std::string&, const std::string&);
175
176struct PropertyChildInfo {
177    pid_t pid;
178    PropertyAsyncFunc func;
179    std::string name;
180    std::string value;
181};
182
183static std::queue<PropertyChildInfo> property_children;
184
185static void PropertyChildLaunch() {
186    auto& info = property_children.front();
187    pid_t pid = fork();
188    if (pid < 0) {
189        LOG(ERROR) << "Failed to fork for property_set_async";
190        while (!property_children.empty()) {
191            property_children.pop();
192        }
193        return;
194    }
195    if (pid != 0) {
196        info.pid = pid;
197    } else {
198        if (info.func(info.name, info.value) != 0) {
199            LOG(ERROR) << "property_set_async(\"" << info.name << "\", \"" << info.value
200                       << "\") failed";
201        }
202        _exit(0);
203    }
204}
205
206bool PropertyChildReap(pid_t pid) {
207    if (property_children.empty()) {
208        return false;
209    }
210    auto& info = property_children.front();
211    if (info.pid != pid) {
212        return false;
213    }
214    std::string error;
215    if (PropertySet(info.name, info.value, &error) != PROP_SUCCESS) {
216        LOG(ERROR) << "Failed to set async property " << info.name << " to " << info.value << ": "
217                   << error;
218    }
219    property_children.pop();
220    if (!property_children.empty()) {
221        PropertyChildLaunch();
222    }
223    return true;
224}
225
226static uint32_t PropertySetAsync(const std::string& name, const std::string& value,
227                                 PropertyAsyncFunc func, std::string* error) {
228    if (value.empty()) {
229        return PropertySet(name, value, error);
230    }
231
232    PropertyChildInfo info;
233    info.func = func;
234    info.name = name;
235    info.value = value;
236    property_children.push(info);
237    if (property_children.size() == 1) {
238        PropertyChildLaunch();
239    }
240    return PROP_SUCCESS;
241}
242
243static int RestoreconRecursiveAsync(const std::string& name, const std::string& value) {
244    return selinux_android_restorecon(value.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE);
245}
246
247uint32_t InitPropertySet(const std::string& name, const std::string& value) {
248    if (StartsWith(name, "ctl.")) {
249        LOG(ERROR) << "InitPropertySet: Do not set ctl. properties from init; call the Service "
250                      "functions directly";
251        return PROP_ERROR_INVALID_NAME;
252    }
253    if (name == "selinux.restorecon_recursive") {
254        LOG(ERROR) << "InitPropertySet: Do not set selinux.restorecon_recursive from init; use the "
255                      "restorecon builtin directly";
256        return PROP_ERROR_INVALID_NAME;
257    }
258
259    uint32_t result = 0;
260    ucred cr = {.pid = 1, .uid = 0, .gid = 0};
261    std::string error;
262    result = HandlePropertySet(name, value, kInitContext.c_str(), cr, &error);
263    if (result != PROP_SUCCESS) {
264        LOG(ERROR) << "Init cannot set '" << name << "' to '" << value << "': " << error;
265    }
266
267    return result;
268}
269
270class SocketConnection {
271  public:
272    SocketConnection(int socket, const ucred& cred) : socket_(socket), cred_(cred) {}
273
274    ~SocketConnection() { close(socket_); }
275
276    bool RecvUint32(uint32_t* value, uint32_t* timeout_ms) {
277        return RecvFully(value, sizeof(*value), timeout_ms);
278    }
279
280    bool RecvChars(char* chars, size_t size, uint32_t* timeout_ms) {
281        return RecvFully(chars, size, timeout_ms);
282    }
283
284    bool RecvString(std::string* value, uint32_t* timeout_ms) {
285        uint32_t len = 0;
286        if (!RecvUint32(&len, timeout_ms)) {
287            return false;
288        }
289
290        if (len == 0) {
291            *value = "";
292            return true;
293        }
294
295        // http://b/35166374: don't allow init to make arbitrarily large allocations.
296        if (len > 0xffff) {
297            LOG(ERROR) << "sys_prop: RecvString asked to read huge string: " << len;
298            errno = ENOMEM;
299            return false;
300        }
301
302        std::vector<char> chars(len);
303        if (!RecvChars(&chars[0], len, timeout_ms)) {
304            return false;
305        }
306
307        *value = std::string(&chars[0], len);
308        return true;
309    }
310
311    bool SendUint32(uint32_t value) {
312        int result = TEMP_FAILURE_RETRY(send(socket_, &value, sizeof(value), 0));
313        return result == sizeof(value);
314    }
315
316    int socket() { return socket_; }
317
318    const ucred& cred() { return cred_; }
319
320    std::string source_context() const {
321        char* source_context = nullptr;
322        getpeercon(socket_, &source_context);
323        std::string result = source_context;
324        freecon(source_context);
325        return result;
326    }
327
328  private:
329    bool PollIn(uint32_t* timeout_ms) {
330        struct pollfd ufds[1];
331        ufds[0].fd = socket_;
332        ufds[0].events = POLLIN;
333        ufds[0].revents = 0;
334        while (*timeout_ms > 0) {
335            auto start_time = std::chrono::steady_clock::now();
336            int nr = poll(ufds, 1, *timeout_ms);
337            auto now = std::chrono::steady_clock::now();
338            auto time_elapsed =
339                std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
340            uint64_t millis = time_elapsed.count();
341            *timeout_ms = (millis > *timeout_ms) ? 0 : *timeout_ms - millis;
342
343            if (nr > 0) {
344                return true;
345            }
346
347            if (nr == 0) {
348                // Timeout
349                break;
350            }
351
352            if (nr < 0 && errno != EINTR) {
353                PLOG(ERROR) << "sys_prop: error waiting for uid " << cred_.uid
354                            << " to send property message";
355                return false;
356            } else {  // errno == EINTR
357                // Timer rounds milliseconds down in case of EINTR we want it to be rounded up
358                // to avoid slowing init down by causing EINTR with under millisecond timeout.
359                if (*timeout_ms > 0) {
360                    --(*timeout_ms);
361                }
362            }
363        }
364
365        LOG(ERROR) << "sys_prop: timeout waiting for uid " << cred_.uid
366                   << " to send property message.";
367        return false;
368    }
369
370    bool RecvFully(void* data_ptr, size_t size, uint32_t* timeout_ms) {
371        size_t bytes_left = size;
372        char* data = static_cast<char*>(data_ptr);
373        while (*timeout_ms > 0 && bytes_left > 0) {
374            if (!PollIn(timeout_ms)) {
375                return false;
376            }
377
378            int result = TEMP_FAILURE_RETRY(recv(socket_, data, bytes_left, MSG_DONTWAIT));
379            if (result <= 0) {
380                return false;
381            }
382
383            bytes_left -= result;
384            data += result;
385        }
386
387        return bytes_left == 0;
388    }
389
390    int socket_;
391    ucred cred_;
392
393    DISALLOW_IMPLICIT_CONSTRUCTORS(SocketConnection);
394};
395
396bool CheckControlPropertyPerms(const std::string& name, const std::string& value,
397                               const std::string& source_context, const ucred& cr) {
398    // We check the legacy method first but these properties are dontaudit, so we only log an audit
399    // if the newer method fails as well.  We only do this with the legacy ctl. properties.
400    if (name == "ctl.start" || name == "ctl.stop" || name == "ctl.restart") {
401        // The legacy permissions model is that ctl. properties have their name ctl.<action> and
402        // their value is the name of the service to apply that action to.  Permissions for these
403        // actions are based on the service, so we must create a fake name of ctl.<service> to
404        // check permissions.
405        auto control_string_legacy = "ctl." + value;
406        const char* target_context_legacy = nullptr;
407        const char* type_legacy = nullptr;
408        property_info_area->GetPropertyInfo(control_string_legacy.c_str(), &target_context_legacy,
409                                            &type_legacy);
410
411        if (CheckMacPerms(control_string_legacy, target_context_legacy, source_context.c_str(), cr)) {
412            return true;
413        }
414    }
415
416    auto control_string_full = name + "$" + value;
417    const char* target_context_full = nullptr;
418    const char* type_full = nullptr;
419    property_info_area->GetPropertyInfo(control_string_full.c_str(), &target_context_full,
420                                        &type_full);
421
422    return CheckMacPerms(control_string_full, target_context_full, source_context.c_str(), cr);
423}
424
425// This returns one of the enum of PROP_SUCCESS or PROP_ERROR*.
426uint32_t HandlePropertySet(const std::string& name, const std::string& value,
427                           const std::string& source_context, const ucred& cr, std::string* error) {
428    if (!IsLegalPropertyName(name)) {
429        *error = "Illegal property name";
430        return PROP_ERROR_INVALID_NAME;
431    }
432
433    if (StartsWith(name, "ctl.")) {
434        if (!CheckControlPropertyPerms(name, value, source_context, cr)) {
435            *error = StringPrintf("Invalid permissions to perform '%s' on '%s'", name.c_str() + 4,
436                                  value.c_str());
437            return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
438        }
439
440        HandleControlMessage(name.c_str() + 4, value, cr.pid);
441        return PROP_SUCCESS;
442    }
443
444    const char* target_context = nullptr;
445    const char* type = nullptr;
446    property_info_area->GetPropertyInfo(name.c_str(), &target_context, &type);
447
448    if (!CheckMacPerms(name, target_context, source_context.c_str(), cr)) {
449        *error = "SELinux permission check failed";
450        return PROP_ERROR_PERMISSION_DENIED;
451    }
452
453    if (type == nullptr || !CheckType(type, value)) {
454        *error = StringPrintf("Property type check failed, value doesn't match expected type '%s'",
455                              (type ?: "(null)"));
456        return PROP_ERROR_INVALID_VALUE;
457    }
458
459    // sys.powerctl is a special property that is used to make the device reboot.  We want to log
460    // any process that sets this property to be able to accurately blame the cause of a shutdown.
461    if (name == "sys.powerctl") {
462        std::string cmdline_path = StringPrintf("proc/%d/cmdline", cr.pid);
463        std::string process_cmdline;
464        std::string process_log_string;
465        if (ReadFileToString(cmdline_path, &process_cmdline)) {
466            // Since cmdline is null deliminated, .c_str() conveniently gives us just the process
467            // path.
468            process_log_string = StringPrintf(" (%s)", process_cmdline.c_str());
469        }
470        LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
471                  << process_log_string;
472    }
473
474    if (name == "selinux.restorecon_recursive") {
475        return PropertySetAsync(name, value, RestoreconRecursiveAsync, error);
476    }
477
478    return PropertySet(name, value, error);
479}
480
481static void handle_property_set_fd() {
482    static constexpr uint32_t kDefaultSocketTimeout = 2000; /* ms */
483
484    int s = accept4(property_set_fd, nullptr, nullptr, SOCK_CLOEXEC);
485    if (s == -1) {
486        return;
487    }
488
489    ucred cr;
490    socklen_t cr_size = sizeof(cr);
491    if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
492        close(s);
493        PLOG(ERROR) << "sys_prop: unable to get SO_PEERCRED";
494        return;
495    }
496
497    SocketConnection socket(s, cr);
498    uint32_t timeout_ms = kDefaultSocketTimeout;
499
500    uint32_t cmd = 0;
501    if (!socket.RecvUint32(&cmd, &timeout_ms)) {
502        PLOG(ERROR) << "sys_prop: error while reading command from the socket";
503        socket.SendUint32(PROP_ERROR_READ_CMD);
504        return;
505    }
506
507    switch (cmd) {
508    case PROP_MSG_SETPROP: {
509        char prop_name[PROP_NAME_MAX];
510        char prop_value[PROP_VALUE_MAX];
511
512        if (!socket.RecvChars(prop_name, PROP_NAME_MAX, &timeout_ms) ||
513            !socket.RecvChars(prop_value, PROP_VALUE_MAX, &timeout_ms)) {
514          PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP): error while reading name/value from the socket";
515          return;
516        }
517
518        prop_name[PROP_NAME_MAX-1] = 0;
519        prop_value[PROP_VALUE_MAX-1] = 0;
520
521        const auto& cr = socket.cred();
522        std::string error;
523        uint32_t result =
524            HandlePropertySet(prop_name, prop_value, socket.source_context(), cr, &error);
525        if (result != PROP_SUCCESS) {
526            LOG(ERROR) << "Unable to set property '" << prop_name << "' to '" << prop_value
527                       << "' from uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid << ": "
528                       << error;
529        }
530
531        break;
532      }
533
534    case PROP_MSG_SETPROP2: {
535        std::string name;
536        std::string value;
537        if (!socket.RecvString(&name, &timeout_ms) ||
538            !socket.RecvString(&value, &timeout_ms)) {
539          PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP2): error while reading name/value from the socket";
540          socket.SendUint32(PROP_ERROR_READ_DATA);
541          return;
542        }
543
544        const auto& cr = socket.cred();
545        std::string error;
546        uint32_t result = HandlePropertySet(name, value, socket.source_context(), cr, &error);
547        if (result != PROP_SUCCESS) {
548            LOG(ERROR) << "Unable to set property '" << name << "' to '" << value
549                       << "' from uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid << ": "
550                       << error;
551        }
552        socket.SendUint32(result);
553        break;
554      }
555
556    default:
557        LOG(ERROR) << "sys_prop: invalid command " << cmd;
558        socket.SendUint32(PROP_ERROR_INVALID_CMD);
559        break;
560    }
561}
562
563static bool load_properties_from_file(const char *, const char *);
564
565/*
566 * Filter is used to decide which properties to load: NULL loads all keys,
567 * "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match.
568 */
569static void LoadProperties(char* data, const char* filter, const char* filename) {
570    char *key, *value, *eol, *sol, *tmp, *fn;
571    size_t flen = 0;
572
573    const char* context = kInitContext.c_str();
574    if (SelinuxHasVendorInit()) {
575        for (const auto& [path_prefix, secontext] : paths_and_secontexts) {
576            if (StartsWith(filename, path_prefix)) {
577                context = secontext;
578            }
579        }
580    }
581
582    if (filter) {
583        flen = strlen(filter);
584    }
585
586    sol = data;
587    while ((eol = strchr(sol, '\n'))) {
588        key = sol;
589        *eol++ = 0;
590        sol = eol;
591
592        while (isspace(*key)) key++;
593        if (*key == '#') continue;
594
595        tmp = eol - 2;
596        while ((tmp > key) && isspace(*tmp)) *tmp-- = 0;
597
598        if (!strncmp(key, "import ", 7) && flen == 0) {
599            fn = key + 7;
600            while (isspace(*fn)) fn++;
601
602            key = strchr(fn, ' ');
603            if (key) {
604                *key++ = 0;
605                while (isspace(*key)) key++;
606            }
607
608            load_properties_from_file(fn, key);
609
610        } else {
611            value = strchr(key, '=');
612            if (!value) continue;
613            *value++ = 0;
614
615            tmp = value - 2;
616            while ((tmp > key) && isspace(*tmp)) *tmp-- = 0;
617
618            while (isspace(*value)) value++;
619
620            if (flen > 0) {
621                if (filter[flen - 1] == '*') {
622                    if (strncmp(key, filter, flen - 1)) continue;
623                } else {
624                    if (strcmp(key, filter)) continue;
625                }
626            }
627
628            if (StartsWith(key, "ctl.") || key == "sys.powerctl"s ||
629                key == "selinux.restorecon_recursive"s) {
630                LOG(ERROR) << "Ignoring disallowed property '" << key
631                           << "' with special meaning in prop file '" << filename << "'";
632                continue;
633            }
634
635            uint32_t result = 0;
636            ucred cr = {.pid = 1, .uid = 0, .gid = 0};
637            std::string error;
638            result = HandlePropertySet(key, value, context, cr, &error);
639            if (result != PROP_SUCCESS) {
640                LOG(ERROR) << "Unable to set property '" << key << "' to '" << value
641                           << "' in property file '" << filename << "': " << error;
642            }
643        }
644    }
645}
646
647// Filter is used to decide which properties to load: NULL loads all keys,
648// "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match.
649static bool load_properties_from_file(const char* filename, const char* filter) {
650    Timer t;
651    auto file_contents = ReadFile(filename);
652    if (!file_contents) {
653        PLOG(WARNING) << "Couldn't load property file '" << filename
654                      << "': " << file_contents.error();
655        return false;
656    }
657    file_contents->push_back('\n');
658
659    LoadProperties(file_contents->data(), filter, filename);
660    LOG(VERBOSE) << "(Loading properties from " << filename << " took " << t << ".)";
661    return true;
662}
663
664// persist.sys.usb.config values can't be combined on build-time when property
665// files are split into each partition.
666// So we need to apply the same rule of build/make/tools/post_process_props.py
667// on runtime.
668static void update_sys_usb_config() {
669    bool is_debuggable = android::base::GetBoolProperty("ro.debuggable", false);
670    std::string config = android::base::GetProperty("persist.sys.usb.config", "");
671    if (config.empty()) {
672        property_set("persist.sys.usb.config", is_debuggable ? "adb" : "none");
673    } else if (is_debuggable && config.find("adb") == std::string::npos &&
674               config.length() + 4 < PROP_VALUE_MAX) {
675        config.append(",adb");
676        property_set("persist.sys.usb.config", config);
677    }
678}
679
680void property_load_boot_defaults() {
681    if (!load_properties_from_file("/system/etc/prop.default", NULL)) {
682        // Try recovery path
683        if (!load_properties_from_file("/prop.default", NULL)) {
684            // Try legacy path
685            load_properties_from_file("/default.prop", NULL);
686        }
687    }
688    load_properties_from_file("/product/build.prop", NULL);
689    load_properties_from_file("/odm/default.prop", NULL);
690    load_properties_from_file("/vendor/default.prop", NULL);
691
692    update_sys_usb_config();
693}
694
695static void load_override_properties() {
696    if (ALLOW_LOCAL_PROP_OVERRIDE) {
697        load_properties_from_file("/data/local.prop", NULL);
698    }
699}
700
701/* When booting an encrypted system, /data is not mounted when the
702 * property service is started, so any properties stored there are
703 * not loaded.  Vold triggers init to load these properties once it
704 * has mounted /data.
705 */
706void load_persist_props(void) {
707    // Devices with FDE have load_persist_props called twice; the first time when the temporary
708    // /data partition is mounted and then again once /data is truly mounted.  We do not want to
709    // read persistent properties from the temporary /data partition or mark persistent properties
710    // as having been loaded during the first call, so we return in that case.
711    std::string crypto_state = android::base::GetProperty("ro.crypto.state", "");
712    std::string crypto_type = android::base::GetProperty("ro.crypto.type", "");
713    if (crypto_state == "encrypted" && crypto_type == "block") {
714        static size_t num_calls = 0;
715        if (++num_calls == 1) return;
716    }
717
718    load_override_properties();
719    /* Read persistent properties after all default values have been loaded. */
720    auto persistent_properties = LoadPersistentProperties();
721    for (const auto& persistent_property_record : persistent_properties.properties()) {
722        property_set(persistent_property_record.name(), persistent_property_record.value());
723    }
724    persistent_properties_loaded = true;
725    property_set("ro.persistent_properties.ready", "true");
726}
727
728void load_recovery_id_prop() {
729    std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
730                                                               fs_mgr_free_fstab);
731    if (!fstab) {
732        PLOG(ERROR) << "unable to read default fstab";
733        return;
734    }
735
736    fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab.get(), RECOVERY_MOUNT_POINT);
737    if (rec == NULL) {
738        LOG(ERROR) << "/recovery not specified in fstab";
739        return;
740    }
741
742    int fd = open(rec->blk_device, O_RDONLY);
743    if (fd == -1) {
744        PLOG(ERROR) << "error opening block device " << rec->blk_device;
745        return;
746    }
747
748    boot_img_hdr hdr;
749    if (android::base::ReadFully(fd, &hdr, sizeof(hdr))) {
750        std::string hex = bytes_to_hex(reinterpret_cast<uint8_t*>(hdr.id), sizeof(hdr.id));
751        property_set("ro.recovery_id", hex);
752    } else {
753        PLOG(ERROR) << "error reading /recovery";
754    }
755
756    close(fd);
757}
758
759void load_system_props() {
760    load_properties_from_file("/system/build.prop", NULL);
761    load_properties_from_file("/odm/build.prop", NULL);
762    load_properties_from_file("/vendor/build.prop", NULL);
763    load_properties_from_file("/factory/factory.prop", "ro.*");
764    load_recovery_id_prop();
765}
766
767static int SelinuxAuditCallback(void* data, security_class_t /*cls*/, char* buf, size_t len) {
768    auto* d = reinterpret_cast<PropertyAuditData*>(data);
769
770    if (!d || !d->name || !d->cr) {
771        LOG(ERROR) << "AuditCallback invoked with null data arguments!";
772        return 0;
773    }
774
775    snprintf(buf, len, "property=%s pid=%d uid=%d gid=%d", d->name, d->cr->pid, d->cr->uid,
776             d->cr->gid);
777    return 0;
778}
779
780bool LoadPropertyInfoFromFile(const std::string& filename,
781                              std::vector<PropertyInfoEntry>* property_infos) {
782    auto file_contents = std::string();
783    if (!ReadFileToString(filename, &file_contents)) {
784        PLOG(ERROR) << "Could not read properties from '" << filename << "'";
785        return false;
786    }
787
788    auto errors = std::vector<std::string>{};
789    ParsePropertyInfoFile(file_contents, property_infos, &errors);
790    // Individual parsing errors are reported but do not cause a failed boot, which is what
791    // returning false would do here.
792    for (const auto& error : errors) {
793        LOG(ERROR) << "Could not read line from '" << filename << "': " << error;
794    }
795
796    return true;
797}
798
799void CreateSerializedPropertyInfo() {
800    auto property_infos = std::vector<PropertyInfoEntry>();
801    if (access("/system/etc/selinux/plat_property_contexts", R_OK) != -1) {
802        if (!LoadPropertyInfoFromFile("/system/etc/selinux/plat_property_contexts",
803                                      &property_infos)) {
804            return;
805        }
806        // Don't check for failure here, so we always have a sane list of properties.
807        // E.g. In case of recovery, the vendor partition will not have mounted and we
808        // still need the system / platform properties to function.
809        if (!LoadPropertyInfoFromFile("/vendor/etc/selinux/vendor_property_contexts",
810                                      &property_infos)) {
811            // Fallback to nonplat_* if vendor_* doesn't exist.
812            LoadPropertyInfoFromFile("/vendor/etc/selinux/nonplat_property_contexts",
813                                     &property_infos);
814        }
815    } else {
816        if (!LoadPropertyInfoFromFile("/plat_property_contexts", &property_infos)) {
817            return;
818        }
819        if (!LoadPropertyInfoFromFile("/vendor_property_contexts", &property_infos)) {
820            // Fallback to nonplat_* if vendor_* doesn't exist.
821            LoadPropertyInfoFromFile("/nonplat_property_contexts", &property_infos);
822        }
823    }
824
825    auto serialized_contexts = std::string();
826    auto error = std::string();
827    if (!BuildTrie(property_infos, "u:object_r:default_prop:s0", "string", &serialized_contexts,
828                   &error)) {
829        LOG(ERROR) << "Unable to serialize property contexts: " << error;
830        return;
831    }
832
833    constexpr static const char kPropertyInfosPath[] = "/dev/__properties__/property_info";
834    if (!WriteStringToFile(serialized_contexts, kPropertyInfosPath, 0444, 0, 0, false)) {
835        PLOG(ERROR) << "Unable to write serialized property infos to file";
836    }
837    selinux_android_restorecon(kPropertyInfosPath, 0);
838}
839
840void start_property_service() {
841    selinux_callback cb;
842    cb.func_audit = SelinuxAuditCallback;
843    selinux_set_callback(SELINUX_CB_AUDIT, cb);
844
845    property_set("ro.property_service.version", "2");
846
847    property_set_fd = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
848                                   false, 0666, 0, 0, nullptr);
849    if (property_set_fd == -1) {
850        PLOG(FATAL) << "start_property_service socket creation failed";
851    }
852
853    listen(property_set_fd, 8);
854
855    register_epoll_handler(property_set_fd, handle_property_set_fd);
856}
857
858}  // namespace init
859}  // namespace android
860