blob: 7e925380f881236c13bbcf9478626129c0f1955a [file] [log] [blame]
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001/*
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
Tom Cherry3f5eaae52017-04-06 16:30:22 -070017#include "property_service.h"
18
Tom Cherry40acb372018-08-01 13:41:12 -070019#include <android/api-level.h>
Tom Cherry3f5eaae52017-04-06 16:30:22 -070020#include <ctype.h>
Tom Cherry3f5eaae52017-04-06 16:30:22 -070021#include <errno.h>
22#include <fcntl.h>
Keun-young Park7d320262017-02-17 17:48:56 -080023#include <inttypes.h>
Tom Cherry3f5eaae52017-04-06 16:30:22 -070024#include <limits.h>
25#include <netinet/in.h>
26#include <stdarg.h>
Tom Cherryf57c0bf2017-04-07 13:46:21 -070027#include <stddef.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080028#include <stdio.h>
29#include <stdlib.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080030#include <string.h>
Tom Cherry3f5eaae52017-04-06 16:30:22 -070031#include <sys/mman.h>
JP Abgrall4515d812014-01-31 14:37:07 -080032#include <sys/poll.h>
Tom Cherry3f5eaae52017-04-06 16:30:22 -070033#include <sys/select.h>
34#include <sys/types.h>
35#include <sys/un.h>
36#include <unistd.h>
Tom Cherry8702dcb2017-10-13 16:20:19 -070037#include <wchar.h>
Elliott Hughes81399e12015-03-10 08:39:45 -070038
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080039#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
40#include <sys/_system_properties.h>
41
Tom Cherrybe048922019-02-16 12:03:19 -080042#include <map>
Tom Cherry3f5eaae52017-04-06 16:30:22 -070043#include <memory>
Tom Cherryfe815412019-04-23 15:11:07 -070044#include <mutex>
Tom Cherry1ab3dfc2019-04-22 17:46:37 -070045#include <optional>
Tom Marshall62696902017-06-09 18:29:23 +000046#include <queue>
Roman Kiryanovccc15c52021-03-09 13:20:36 -080047#include <string_view>
Tom Cherryfe815412019-04-23 15:11:07 -070048#include <thread>
Tom Cherry3f5eaae52017-04-06 16:30:22 -070049#include <vector>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080050
Nikita Ioffe92116e42020-03-31 01:28:35 +010051#include <InitProperties.sysprop.h>
Tom Cherryede0d532017-07-06 14:20:11 -070052#include <android-base/chrono_utils.h>
Elliott Hughes4f713192015-12-04 22:00:26 -080053#include <android-base/file.h>
Tom Cherry3f5eaae52017-04-06 16:30:22 -070054#include <android-base/logging.h>
Jiyong Park8178c5f2020-06-29 10:42:03 +090055#include <android-base/parseint.h>
Jaekyun Seok0cf3a072017-04-24 18:52:54 +090056#include <android-base/properties.h>
Inseob Kim946c9722022-05-23 16:37:44 +090057#include <android-base/result.h>
Tom Cherrya84e14d2017-09-05 12:38:30 -070058#include <android-base/stringprintf.h>
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +000059#include <android-base/strings.h>
Tom Cherry2ae2f602017-12-14 01:58:17 +000060#include <property_info_parser/property_info_parser.h>
61#include <property_info_serializer/property_info_serializer.h>
Tom Cherry3f5eaae52017-04-06 16:30:22 -070062#include <selinux/android.h>
63#include <selinux/label.h>
64#include <selinux/selinux.h>
Andres Moralesdb5f5d42015-05-08 08:30:33 -070065
Bowgo Tsai30afda72019-04-11 23:57:24 +080066#include "debug_ramdisk.h"
Tom Cherry3707d322019-08-15 13:07:24 -070067#include "epoll.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080068#include "init.h"
Tom Cherry16fad422017-08-04 15:59:03 -070069#include "persistent_properties.h"
Tom Cherry927c5d52017-12-11 01:40:07 -080070#include "property_type.h"
Tom Cherry1ab3dfc2019-04-22 17:46:37 -070071#include "proto_utils.h"
Yifan Honga68ee762020-10-06 16:58:19 -070072#include "second_stage_resources.h"
Logan Chien837b2a42018-05-03 14:33:52 +080073#include "selinux.h"
Tom Cherrydc375862018-02-28 10:39:01 -080074#include "subcontext.h"
Tom Cherry1ab3dfc2019-04-22 17:46:37 -070075#include "system/core/init/property_service.pb.h"
Colin Cross3899e9f2010-04-13 20:35:46 -070076#include "util.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080077
Tom Cherrydc375862018-02-28 10:39:01 -080078using namespace std::literals;
79
Inseob Kim946c9722022-05-23 16:37:44 +090080using android::base::ErrnoError;
81using android::base::Error;
Steven Laver57a740e2019-01-29 20:19:05 -080082using android::base::GetProperty;
Jiyong Park8178c5f2020-06-29 10:42:03 +090083using android::base::ParseInt;
Tom Cherry2ae2f602017-12-14 01:58:17 +000084using android::base::ReadFileToString;
Inseob Kim946c9722022-05-23 16:37:44 +090085using android::base::Result;
Tom Cherry2ae2f602017-12-14 01:58:17 +000086using android::base::Split;
Tom Cherry1cf8d692017-10-10 13:35:01 -070087using android::base::StartsWith;
Tom Cherrya84e14d2017-09-05 12:38:30 -070088using android::base::StringPrintf;
Tom Cherryede0d532017-07-06 14:20:11 -070089using android::base::Timer;
Tom Cherry2ae2f602017-12-14 01:58:17 +000090using android::base::Trim;
Tom Cherry1ab3dfc2019-04-22 17:46:37 -070091using android::base::unique_fd;
Tom Cherry2ae2f602017-12-14 01:58:17 +000092using android::base::WriteStringToFile;
93using android::properties::BuildTrie;
Tom Cherry919458c2018-01-03 14:39:28 -080094using android::properties::ParsePropertyInfoFile;
Tom Cherry2ae2f602017-12-14 01:58:17 +000095using android::properties::PropertyInfoAreaFile;
96using android::properties::PropertyInfoEntry;
Nikita Ioffe92116e42020-03-31 01:28:35 +010097using android::sysprop::InitProperties::is_userspace_reboot_supported;
Tom Cherryede0d532017-07-06 14:20:11 -070098
Tom Cherry81f5d3e2017-06-22 12:53:17 -070099namespace android {
100namespace init {
Tianjiebecfa772021-05-05 17:23:46 -0700101constexpr auto FINGERPRINT_PROP = "ro.build.fingerprint";
102constexpr auto LEGACY_FINGERPRINT_PROP = "ro.build.legacy.fingerprint";
103constexpr auto ID_PROP = "ro.build.id";
104constexpr auto LEGACY_ID_PROP = "ro.build.legacy.id";
105constexpr auto VBMETA_DIGEST_PROP = "ro.boot.vbmeta.digest";
106constexpr auto DIGEST_SIZE_USED = 8;
Justin Yun4446a852021-10-13 18:13:28 +0900107constexpr auto API_LEVEL_CURRENT = 10000;
Tom Cherry81f5d3e2017-06-22 12:53:17 -0700108
Tom Cherry16fad422017-08-04 15:59:03 -0700109static bool persistent_properties_loaded = false;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800110
Colin Crossd11beb22010-04-13 19:33:37 -0700111static int property_set_fd = -1;
Tom Cherry802864c2020-03-12 14:29:25 -0700112static int from_init_socket = -1;
Tom Cherry1ab3dfc2019-04-22 17:46:37 -0700113static int init_socket = -1;
Nikita Ioffeba6968e2019-10-07 16:26:33 +0100114static bool accept_messages = false;
Tom Cherry802864c2020-03-12 14:29:25 -0700115static std::mutex accept_messages_lock;
116static std::thread property_service_thread;
Colin Crossd11beb22010-04-13 19:33:37 -0700117
Tom Cherry2ae2f602017-12-14 01:58:17 +0000118static PropertyInfoAreaFile property_info_area;
119
Tom Cherry5ab2e1c2018-05-03 16:57:19 -0700120struct PropertyAuditData {
121 const ucred* cr;
122 const char* name;
123};
124
Tom Cherry2f113ad2019-04-22 10:22:41 -0700125static int PropertyAuditCallback(void* data, security_class_t /*cls*/, char* buf, size_t len) {
126 auto* d = reinterpret_cast<PropertyAuditData*>(data);
127
128 if (!d || !d->name || !d->cr) {
129 LOG(ERROR) << "AuditCallback invoked with null data arguments!";
130 return 0;
131 }
132
133 snprintf(buf, len, "property=%s pid=%d uid=%d gid=%d", d->name, d->cr->pid, d->cr->uid,
134 d->cr->gid);
135 return 0;
136}
137
Tom Cherry802864c2020-03-12 14:29:25 -0700138void StartSendingMessages() {
139 auto lock = std::lock_guard{accept_messages_lock};
140 accept_messages = true;
141}
142
143void StopSendingMessages() {
144 auto lock = std::lock_guard{accept_messages_lock};
Tom Cherry68855272020-03-27 13:57:53 -0700145 accept_messages = false;
Tom Cherry802864c2020-03-12 14:29:25 -0700146}
147
Tom Cherryb35f8272018-10-22 14:50:52 -0700148bool CanReadProperty(const std::string& source_context, const std::string& name) {
149 const char* target_context = nullptr;
150 property_info_area->GetPropertyInfo(name.c_str(), &target_context, nullptr);
151
152 PropertyAuditData audit_data;
153
154 audit_data.name = name.c_str();
155
156 ucred cr = {.pid = 0, .uid = 0, .gid = 0};
157 audit_data.cr = &cr;
158
159 return selinux_check_access(source_context.c_str(), target_context, "file", "read",
160 &audit_data) == 0;
161}
162
Tom Cherry927c5d52017-12-11 01:40:07 -0800163static bool CheckMacPerms(const std::string& name, const char* target_context,
Tom Cherry32228482018-01-18 16:14:25 -0800164 const char* source_context, const ucred& cr) {
Tom Cherry927c5d52017-12-11 01:40:07 -0800165 if (!target_context || !source_context) {
Tom Cherry2ae2f602017-12-14 01:58:17 +0000166 return false;
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000167 }
168
Tom Cherry5ab2e1c2018-05-03 16:57:19 -0700169 PropertyAuditData audit_data;
rpcraig63207cd2012-08-09 10:05:49 -0400170
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000171 audit_data.name = name.c_str();
Tom Cherry32228482018-01-18 16:14:25 -0800172 audit_data.cr = &cr;
William Robertsd7aea442015-10-01 16:03:47 -0700173
Tom Cherry927c5d52017-12-11 01:40:07 -0800174 bool has_access = (selinux_check_access(source_context, target_context, "property_service",
175 "set", &audit_data) == 0);
rpcraig63207cd2012-08-09 10:05:49 -0400176
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000177 return has_access;
rpcraig63207cd2012-08-09 10:05:49 -0400178}
179
Tom Cherry69d47aa2018-03-01 11:00:57 -0800180static uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error) {
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000181 size_t valuelen = value.size();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800182
Tom Cherryde6bd502018-02-13 16:50:08 -0800183 if (!IsLegalPropertyName(name)) {
Tom Cherry69d47aa2018-03-01 11:00:57 -0800184 *error = "Illegal property name";
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000185 return PROP_ERROR_INVALID_NAME;
Elliott Hughes331cf2f2016-11-29 19:20:58 +0000186 }
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000187
Bernie Innocenticecebbb2020-02-06 03:49:33 +0900188 if (auto result = IsLegalPropertyValue(name, value); !result.ok()) {
Tom Cherry4772f1d2019-07-30 09:34:41 -0700189 *error = result.error().message();
Tom Cherry8702dcb2017-10-13 16:20:19 -0700190 return PROP_ERROR_INVALID_VALUE;
191 }
192
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000193 prop_info* pi = (prop_info*) __system_property_find(name.c_str());
Elliott Hughes331cf2f2016-11-29 19:20:58 +0000194 if (pi != nullptr) {
195 // ro.* properties are actually "write-once".
Tom Cherry1cf8d692017-10-10 13:35:01 -0700196 if (StartsWith(name, "ro.")) {
Tom Cherry69d47aa2018-03-01 11:00:57 -0800197 *error = "Read-only property was already set";
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000198 return PROP_ERROR_READ_ONLY_PROPERTY;
Elliott Hughes331cf2f2016-11-29 19:20:58 +0000199 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800200
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000201 __system_property_update(pi, value.c_str(), valuelen);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800202 } else {
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000203 int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen);
Elliott Hughesdb3f2672015-03-20 09:45:18 -0700204 if (rc < 0) {
Tom Cherry69d47aa2018-03-01 11:00:57 -0800205 *error = "__system_property_add failed";
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000206 return PROP_ERROR_SET_FAILED;
Johan Redestigfd7ffb12013-04-29 09:11:57 +0200207 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800208 }
Elliott Hughes331cf2f2016-11-29 19:20:58 +0000209
Elliott Hughes4f915812016-12-05 13:12:48 -0800210 // Don't write properties to disk until after we have read all default
211 // properties to prevent them from being overwritten by default values.
Tom Cherry1cf8d692017-10-10 13:35:01 -0700212 if (persistent_properties_loaded && StartsWith(name, "persist.")) {
Tom Cherry16fad422017-08-04 15:59:03 -0700213 WritePersistentProperty(name, value);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800214 }
Tom Cherry1ab3dfc2019-04-22 17:46:37 -0700215 // If init hasn't started its main loop, then it won't be handling property changed messages
216 // anyway, so there's no need to try to send them.
Tom Cherry802864c2020-03-12 14:29:25 -0700217 auto lock = std::lock_guard{accept_messages_lock};
Nikita Ioffeba6968e2019-10-07 16:26:33 +0100218 if (accept_messages) {
Tom Cherry802864c2020-03-12 14:29:25 -0700219 PropertyChanged(name, value);
Tom Cherry1ab3dfc2019-04-22 17:46:37 -0700220 }
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000221 return PROP_SUCCESS;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800222}
223
Tom Cherry832f9f12020-03-10 11:47:24 -0700224class AsyncRestorecon {
Tom Cherryfe815412019-04-23 15:11:07 -0700225 public:
Tom Cherry832f9f12020-03-10 11:47:24 -0700226 void TriggerRestorecon(const std::string& path) {
Tom Cherry7205c622020-01-29 14:09:24 -0800227 auto guard = std::lock_guard{mutex_};
Tom Cherry832f9f12020-03-10 11:47:24 -0700228 paths_.emplace(path);
Tom Cherry7205c622020-01-29 14:09:24 -0800229
Tom Cherry832f9f12020-03-10 11:47:24 -0700230 if (!thread_started_) {
231 thread_started_ = true;
232 std::thread{&AsyncRestorecon::ThreadFunction, this}.detach();
Tom Cherryfe815412019-04-23 15:11:07 -0700233 }
234 }
235
236 private:
237 void ThreadFunction() {
238 auto lock = std::unique_lock{mutex_};
239
Tom Cherry832f9f12020-03-10 11:47:24 -0700240 while (!paths_.empty()) {
241 auto path = paths_.front();
242 paths_.pop();
Tom Cherryfe815412019-04-23 15:11:07 -0700243
244 lock.unlock();
Tom Cherry832f9f12020-03-10 11:47:24 -0700245 if (selinux_android_restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
246 LOG(ERROR) << "Asynchronous restorecon of '" << path << "' failed'";
247 }
248 android::base::SetProperty(kRestoreconProperty, path);
Tom Cherryfe815412019-04-23 15:11:07 -0700249 lock.lock();
250 }
251
Tom Cherry832f9f12020-03-10 11:47:24 -0700252 thread_started_ = false;
Tom Cherryfe815412019-04-23 15:11:07 -0700253 }
254
255 std::mutex mutex_;
Tom Cherry832f9f12020-03-10 11:47:24 -0700256 std::queue<std::string> paths_;
257 bool thread_started_ = false;
Tom Marshall62696902017-06-09 18:29:23 +0000258};
259
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000260class SocketConnection {
Tom Cherry32228482018-01-18 16:14:25 -0800261 public:
262 SocketConnection(int socket, const ucred& cred) : socket_(socket), cred_(cred) {}
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000263
Tom Cherry32228482018-01-18 16:14:25 -0800264 bool RecvUint32(uint32_t* value, uint32_t* timeout_ms) {
265 return RecvFully(value, sizeof(*value), timeout_ms);
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000266 }
267
Tom Cherry32228482018-01-18 16:14:25 -0800268 bool RecvChars(char* chars, size_t size, uint32_t* timeout_ms) {
269 return RecvFully(chars, size, timeout_ms);
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000270 }
271
Tom Cherry32228482018-01-18 16:14:25 -0800272 bool RecvString(std::string* value, uint32_t* timeout_ms) {
273 uint32_t len = 0;
274 if (!RecvUint32(&len, timeout_ms)) {
275 return false;
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000276 }
Tom Cherry32228482018-01-18 16:14:25 -0800277
278 if (len == 0) {
279 *value = "";
280 return true;
281 }
282
283 // http://b/35166374: don't allow init to make arbitrarily large allocations.
284 if (len > 0xffff) {
285 LOG(ERROR) << "sys_prop: RecvString asked to read huge string: " << len;
286 errno = ENOMEM;
287 return false;
288 }
289
290 std::vector<char> chars(len);
291 if (!RecvChars(&chars[0], len, timeout_ms)) {
292 return false;
293 }
294
295 *value = std::string(&chars[0], len);
296 return true;
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000297 }
298
Tom Cherry32228482018-01-18 16:14:25 -0800299 bool SendUint32(uint32_t value) {
Tom Cherry1ab3dfc2019-04-22 17:46:37 -0700300 if (!socket_.ok()) {
301 return true;
302 }
Tom Cherry32228482018-01-18 16:14:25 -0800303 int result = TEMP_FAILURE_RETRY(send(socket_, &value, sizeof(value), 0));
304 return result == sizeof(value);
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000305 }
306
Tom Cherry7f160af2019-04-22 13:28:28 -0700307 bool GetSourceContext(std::string* source_context) const {
308 char* c_source_context = nullptr;
309 if (getpeercon(socket_, &c_source_context) != 0) {
310 return false;
311 }
312 *source_context = c_source_context;
313 freecon(c_source_context);
314 return true;
315 }
316
Tom Cherry1ab3dfc2019-04-22 17:46:37 -0700317 [[nodiscard]] int Release() { return socket_.release(); }
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000318
Tom Cherry32228482018-01-18 16:14:25 -0800319 const ucred& cred() { return cred_; }
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000320
Tom Cherry32228482018-01-18 16:14:25 -0800321 private:
322 bool PollIn(uint32_t* timeout_ms) {
323 struct pollfd ufds[1];
324 ufds[0].fd = socket_;
325 ufds[0].events = POLLIN;
326 ufds[0].revents = 0;
327 while (*timeout_ms > 0) {
328 auto start_time = std::chrono::steady_clock::now();
329 int nr = poll(ufds, 1, *timeout_ms);
330 auto now = std::chrono::steady_clock::now();
331 auto time_elapsed =
332 std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
333 uint64_t millis = time_elapsed.count();
334 *timeout_ms = (millis > *timeout_ms) ? 0 : *timeout_ms - millis;
335
336 if (nr > 0) {
337 return true;
338 }
339
340 if (nr == 0) {
341 // Timeout
342 break;
343 }
344
345 if (nr < 0 && errno != EINTR) {
346 PLOG(ERROR) << "sys_prop: error waiting for uid " << cred_.uid
347 << " to send property message";
348 return false;
349 } else { // errno == EINTR
350 // Timer rounds milliseconds down in case of EINTR we want it to be rounded up
351 // to avoid slowing init down by causing EINTR with under millisecond timeout.
352 if (*timeout_ms > 0) {
353 --(*timeout_ms);
354 }
355 }
356 }
357
358 LOG(ERROR) << "sys_prop: timeout waiting for uid " << cred_.uid
359 << " to send property message.";
360 return false;
361 }
362
363 bool RecvFully(void* data_ptr, size_t size, uint32_t* timeout_ms) {
364 size_t bytes_left = size;
365 char* data = static_cast<char*>(data_ptr);
366 while (*timeout_ms > 0 && bytes_left > 0) {
367 if (!PollIn(timeout_ms)) {
368 return false;
369 }
370
371 int result = TEMP_FAILURE_RETRY(recv(socket_, data, bytes_left, MSG_DONTWAIT));
372 if (result <= 0) {
DuXiao40533592018-05-21 14:43:56 +0800373 PLOG(ERROR) << "sys_prop: recv error";
Tom Cherry32228482018-01-18 16:14:25 -0800374 return false;
375 }
376
377 bytes_left -= result;
378 data += result;
379 }
380
DuXiao40533592018-05-21 14:43:56 +0800381 if (bytes_left != 0) {
382 LOG(ERROR) << "sys_prop: recv data is not properly obtained.";
383 }
384
Tom Cherry32228482018-01-18 16:14:25 -0800385 return bytes_left == 0;
386 }
387
Tom Cherry1ab3dfc2019-04-22 17:46:37 -0700388 unique_fd socket_;
Tom Cherry32228482018-01-18 16:14:25 -0800389 ucred cred_;
Tom Cherry3da2ba62019-08-28 17:47:49 +0000390
391 DISALLOW_IMPLICIT_CONSTRUCTORS(SocketConnection);
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000392};
393
Tom Cherry1ab3dfc2019-04-22 17:46:37 -0700394static uint32_t SendControlMessage(const std::string& msg, const std::string& name, pid_t pid,
395 SocketConnection* socket, std::string* error) {
Tom Cherry802864c2020-03-12 14:29:25 -0700396 auto lock = std::lock_guard{accept_messages_lock};
Nikita Ioffeba6968e2019-10-07 16:26:33 +0100397 if (!accept_messages) {
Tom Cherry1ab3dfc2019-04-22 17:46:37 -0700398 *error = "Received control message after shutdown, ignoring";
399 return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
400 }
401
Tom Cherry832f9f12020-03-10 11:47:24 -0700402 // We must release the fd before sending it to init, otherwise there will be a race with init.
403 // If init calls close() before Release(), then fdsan will see the wrong tag and abort().
Tom Cherry1ab3dfc2019-04-22 17:46:37 -0700404 int fd = -1;
Tom Cherry5310db82019-10-22 08:27:23 -0700405 if (socket != nullptr && SelinuxGetVendorAndroidVersion() > __ANDROID_API_Q__) {
Tom Cherry1ab3dfc2019-04-22 17:46:37 -0700406 fd = socket->Release();
Tom Cherry1ab3dfc2019-04-22 17:46:37 -0700407 }
408
Tom Cherry802864c2020-03-12 14:29:25 -0700409 bool queue_success = QueueControlMessage(msg, name, pid, fd);
410 if (!queue_success && fd != -1) {
411 uint32_t response = PROP_ERROR_HANDLE_CONTROL_MESSAGE;
412 TEMP_FAILURE_RETRY(send(fd, &response, sizeof(response), 0));
413 close(fd);
Tom Cherry832f9f12020-03-10 11:47:24 -0700414 }
Tom Cherry1ab3dfc2019-04-22 17:46:37 -0700415
416 return PROP_SUCCESS;
417}
418
Tom Cherry5ab2e1c2018-05-03 16:57:19 -0700419bool CheckControlPropertyPerms(const std::string& name, const std::string& value,
420 const std::string& source_context, const ucred& cr) {
421 // We check the legacy method first but these properties are dontaudit, so we only log an audit
422 // if the newer method fails as well. We only do this with the legacy ctl. properties.
423 if (name == "ctl.start" || name == "ctl.stop" || name == "ctl.restart") {
424 // The legacy permissions model is that ctl. properties have their name ctl.<action> and
425 // their value is the name of the service to apply that action to. Permissions for these
426 // actions are based on the service, so we must create a fake name of ctl.<service> to
427 // check permissions.
428 auto control_string_legacy = "ctl." + value;
429 const char* target_context_legacy = nullptr;
430 const char* type_legacy = nullptr;
431 property_info_area->GetPropertyInfo(control_string_legacy.c_str(), &target_context_legacy,
432 &type_legacy);
433
434 if (CheckMacPerms(control_string_legacy, target_context_legacy, source_context.c_str(), cr)) {
435 return true;
436 }
437 }
438
439 auto control_string_full = name + "$" + value;
440 const char* target_context_full = nullptr;
441 const char* type_full = nullptr;
442 property_info_area->GetPropertyInfo(control_string_full.c_str(), &target_context_full,
443 &type_full);
444
445 return CheckMacPerms(control_string_full, target_context_full, source_context.c_str(), cr);
446}
447
Tom Cherry32228482018-01-18 16:14:25 -0800448// This returns one of the enum of PROP_SUCCESS or PROP_ERROR*.
Tom Cherrybe048922019-02-16 12:03:19 -0800449uint32_t CheckPermissions(const std::string& name, const std::string& value,
450 const std::string& source_context, const ucred& cr, std::string* error) {
Tom Cherryde6bd502018-02-13 16:50:08 -0800451 if (!IsLegalPropertyName(name)) {
Tom Cherry69d47aa2018-03-01 11:00:57 -0800452 *error = "Illegal property name";
Tom Cherry32228482018-01-18 16:14:25 -0800453 return PROP_ERROR_INVALID_NAME;
454 }
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000455
Tom Cherry32228482018-01-18 16:14:25 -0800456 if (StartsWith(name, "ctl.")) {
Tom Cherry5ab2e1c2018-05-03 16:57:19 -0700457 if (!CheckControlPropertyPerms(name, value, source_context, cr)) {
458 *error = StringPrintf("Invalid permissions to perform '%s' on '%s'", name.c_str() + 4,
459 value.c_str());
Tom Cherry32228482018-01-18 16:14:25 -0800460 return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
461 }
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000462
Tom Cherry32228482018-01-18 16:14:25 -0800463 return PROP_SUCCESS;
464 }
Tom Cherry927c5d52017-12-11 01:40:07 -0800465
Tom Cherry32228482018-01-18 16:14:25 -0800466 const char* target_context = nullptr;
467 const char* type = nullptr;
468 property_info_area->GetPropertyInfo(name.c_str(), &target_context, &type);
Tom Cherrya84e14d2017-09-05 12:38:30 -0700469
Tom Cherry32228482018-01-18 16:14:25 -0800470 if (!CheckMacPerms(name, target_context, source_context.c_str(), cr)) {
Tom Cherry69d47aa2018-03-01 11:00:57 -0800471 *error = "SELinux permission check failed";
Tom Cherry32228482018-01-18 16:14:25 -0800472 return PROP_ERROR_PERMISSION_DENIED;
473 }
474
Tom Cherryb5f2ec02019-11-08 17:54:27 -0800475 if (!CheckType(type, value)) {
Tom Cherry69d47aa2018-03-01 11:00:57 -0800476 *error = StringPrintf("Property type check failed, value doesn't match expected type '%s'",
477 (type ?: "(null)"));
Tom Cherry32228482018-01-18 16:14:25 -0800478 return PROP_ERROR_INVALID_VALUE;
479 }
480
Tom Cherrybe048922019-02-16 12:03:19 -0800481 return PROP_SUCCESS;
482}
483
484// This returns one of the enum of PROP_SUCCESS or PROP_ERROR*.
485uint32_t HandlePropertySet(const std::string& name, const std::string& value,
Tom Cherry1ab3dfc2019-04-22 17:46:37 -0700486 const std::string& source_context, const ucred& cr,
487 SocketConnection* socket, std::string* error) {
Tom Cherrybe048922019-02-16 12:03:19 -0800488 if (auto ret = CheckPermissions(name, value, source_context, cr, error); ret != PROP_SUCCESS) {
489 return ret;
490 }
491
492 if (StartsWith(name, "ctl.")) {
Tom Cherry1ab3dfc2019-04-22 17:46:37 -0700493 return SendControlMessage(name.c_str() + 4, value, cr.pid, socket, error);
Tom Cherrybe048922019-02-16 12:03:19 -0800494 }
495
Tom Cherry32228482018-01-18 16:14:25 -0800496 // sys.powerctl is a special property that is used to make the device reboot. We want to log
497 // any process that sets this property to be able to accurately blame the cause of a shutdown.
498 if (name == "sys.powerctl") {
499 std::string cmdline_path = StringPrintf("proc/%d/cmdline", cr.pid);
500 std::string process_cmdline;
501 std::string process_log_string;
502 if (ReadFileToString(cmdline_path, &process_cmdline)) {
503 // Since cmdline is null deliminated, .c_str() conveniently gives us just the process
504 // path.
505 process_log_string = StringPrintf(" (%s)", process_cmdline.c_str());
506 }
507 LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
508 << process_log_string;
Tom Cherry9174a9b2020-03-31 14:36:03 -0700509 if (!value.empty()) {
510 DebugRebootLogging();
511 }
Nikita Ioffe92116e42020-03-31 01:28:35 +0100512 if (value == "reboot,userspace" && !is_userspace_reboot_supported().value_or(false)) {
513 *error = "Userspace reboot is not supported by this device";
514 return PROP_ERROR_INVALID_VALUE;
515 }
Tom Cherry32228482018-01-18 16:14:25 -0800516 }
517
Tom Cherryfe815412019-04-23 15:11:07 -0700518 // If a process other than init is writing a non-empty value, it means that process is
519 // requesting that init performs a restorecon operation on the path specified by 'value'.
520 // We use a thread to do this restorecon operation to prevent holding up init, as it may take
521 // a long time to complete.
522 if (name == kRestoreconProperty && cr.pid != 1 && !value.empty()) {
Tom Cherry832f9f12020-03-10 11:47:24 -0700523 static AsyncRestorecon async_restorecon;
524 async_restorecon.TriggerRestorecon(value);
Tom Cherryfe815412019-04-23 15:11:07 -0700525 return PROP_SUCCESS;
Tom Cherry69d47aa2018-03-01 11:00:57 -0800526 }
527
528 return PropertySet(name, value, error);
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000529}
530
531static void handle_property_set_fd() {
532 static constexpr uint32_t kDefaultSocketTimeout = 2000; /* ms */
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800533
Robert Sesekca2da602017-01-25 08:08:51 -0500534 int s = accept4(property_set_fd, nullptr, nullptr, SOCK_CLOEXEC);
Elliott Hughes3dcfa3f2016-08-23 12:50:00 -0700535 if (s == -1) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800536 return;
537 }
538
Tom Cherry32228482018-01-18 16:14:25 -0800539 ucred cr;
Elliott Hughes3dcfa3f2016-08-23 12:50:00 -0700540 socklen_t cr_size = sizeof(cr);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800541 if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
542 close(s);
Elliott Hughesb005d902017-02-22 14:54:15 -0800543 PLOG(ERROR) << "sys_prop: unable to get SO_PEERCRED";
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800544 return;
545 }
546
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000547 SocketConnection socket(s, cr);
548 uint32_t timeout_ms = kDefaultSocketTimeout;
549
550 uint32_t cmd = 0;
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000551 if (!socket.RecvUint32(&cmd, &timeout_ms)) {
552 PLOG(ERROR) << "sys_prop: error while reading command from the socket";
553 socket.SendUint32(PROP_ERROR_READ_CMD);
JP Abgrall4515d812014-01-31 14:37:07 -0800554 return;
555 }
556
Elliott Hughesb005d902017-02-22 14:54:15 -0800557 switch (cmd) {
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000558 case PROP_MSG_SETPROP: {
559 char prop_name[PROP_NAME_MAX];
560 char prop_value[PROP_VALUE_MAX];
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800561
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000562 if (!socket.RecvChars(prop_name, PROP_NAME_MAX, &timeout_ms) ||
563 !socket.RecvChars(prop_value, PROP_VALUE_MAX, &timeout_ms)) {
564 PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP): error while reading name/value from the socket";
565 return;
Nick Kralevich69463612013-09-13 17:21:28 -0700566 }
567
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000568 prop_name[PROP_NAME_MAX-1] = 0;
569 prop_value[PROP_VALUE_MAX-1] = 0;
rpcraig63207cd2012-08-09 10:05:49 -0400570
Tom Cherry7f160af2019-04-22 13:28:28 -0700571 std::string source_context;
572 if (!socket.GetSourceContext(&source_context)) {
573 PLOG(ERROR) << "Unable to set property '" << prop_name << "': getpeercon() failed";
574 return;
575 }
576
Tom Cherry69d47aa2018-03-01 11:00:57 -0800577 const auto& cr = socket.cred();
578 std::string error;
Tom Cherry1ab3dfc2019-04-22 17:46:37 -0700579 uint32_t result =
580 HandlePropertySet(prop_name, prop_value, source_context, cr, nullptr, &error);
Tom Cherry69d47aa2018-03-01 11:00:57 -0800581 if (result != PROP_SUCCESS) {
Nick Kralevich9ca898f2019-04-04 10:10:01 -0700582 LOG(ERROR) << "Unable to set property '" << prop_name << "' from uid:" << cr.uid
583 << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
Tom Cherry69d47aa2018-03-01 11:00:57 -0800584 }
585
Dimitry Ivanovdee4bd22017-01-19 14:53:00 -0800586 break;
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000587 }
Dimitry Ivanov70c4ecf2017-01-24 18:38:09 +0000588
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000589 case PROP_MSG_SETPROP2: {
590 std::string name;
591 std::string value;
592 if (!socket.RecvString(&name, &timeout_ms) ||
593 !socket.RecvString(&value, &timeout_ms)) {
594 PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP2): error while reading name/value from the socket";
595 socket.SendUint32(PROP_ERROR_READ_DATA);
596 return;
597 }
598
Tom Cherry7f160af2019-04-22 13:28:28 -0700599 std::string source_context;
600 if (!socket.GetSourceContext(&source_context)) {
601 PLOG(ERROR) << "Unable to set property '" << name << "': getpeercon() failed";
602 socket.SendUint32(PROP_ERROR_PERMISSION_DENIED);
603 return;
604 }
605
Tom Cherry69d47aa2018-03-01 11:00:57 -0800606 const auto& cr = socket.cred();
607 std::string error;
Tom Cherry1ab3dfc2019-04-22 17:46:37 -0700608 uint32_t result = HandlePropertySet(name, value, source_context, cr, &socket, &error);
Tom Cherry69d47aa2018-03-01 11:00:57 -0800609 if (result != PROP_SUCCESS) {
Nick Kralevich9ca898f2019-04-04 10:10:01 -0700610 LOG(ERROR) << "Unable to set property '" << name << "' from uid:" << cr.uid
611 << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
Tom Cherry69d47aa2018-03-01 11:00:57 -0800612 }
Tom Cherryf4514262019-08-26 16:33:40 +0000613 socket.SendUint32(result);
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000614 break;
615 }
Elliott Hughesb005d902017-02-22 14:54:15 -0800616
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800617 default:
Elliott Hughesb005d902017-02-22 14:54:15 -0800618 LOG(ERROR) << "sys_prop: invalid command " << cmd;
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +0000619 socket.SendUint32(PROP_ERROR_INVALID_CMD);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800620 break;
621 }
622}
623
Tom Cherryc88d8f92019-08-19 15:21:25 -0700624uint32_t InitPropertySet(const std::string& name, const std::string& value) {
625 uint32_t result = 0;
626 ucred cr = {.pid = 1, .uid = 0, .gid = 0};
627 std::string error;
628 result = HandlePropertySet(name, value, kInitContext, cr, nullptr, &error);
629 if (result != PROP_SUCCESS) {
630 LOG(ERROR) << "Init cannot set '" << name << "' to '" << value << "': " << error;
631 }
632
633 return result;
634}
635
Inseob Kim946c9722022-05-23 16:37:44 +0900636static Result<void> load_properties_from_file(const char*, const char*,
637 std::map<std::string, std::string>*);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800638
Jeff Sharkeyf96b0442014-03-06 14:26:36 -0800639/*
640 * Filter is used to decide which properties to load: NULL loads all keys,
641 * "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match.
642 */
Tom Cherrybe048922019-02-16 12:03:19 -0800643static void LoadProperties(char* data, const char* filter, const char* filename,
644 std::map<std::string, std::string>* properties) {
Jeff Sharkeyf96b0442014-03-06 14:26:36 -0800645 char *key, *value, *eol, *sol, *tmp, *fn;
646 size_t flen = 0;
647
Yifan Hong9258f2e2020-07-15 17:04:43 -0700648 static constexpr const char* const kVendorPathPrefixes[4] = {
Tom Cherry14c24722019-09-18 13:47:19 -0700649 "/vendor",
650 "/odm",
Yifan Hong2ed3cda2020-06-24 18:29:22 -0700651 "/vendor_dlkm",
Yifan Hong9258f2e2020-07-15 17:04:43 -0700652 "/odm_dlkm",
Tom Cherry14c24722019-09-18 13:47:19 -0700653 };
654
655 const char* context = kInitContext;
Tom Cherry40acb372018-08-01 13:41:12 -0700656 if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_P__) {
Tom Cherry14c24722019-09-18 13:47:19 -0700657 for (const auto& vendor_path_prefix : kVendorPathPrefixes) {
658 if (StartsWith(filename, vendor_path_prefix)) {
659 context = kVendorContext;
Tom Cherrya1dbeb82018-04-11 15:50:00 -0700660 }
Tom Cherrydc375862018-02-28 10:39:01 -0800661 }
662 }
663
Jeff Sharkeyf96b0442014-03-06 14:26:36 -0800664 if (filter) {
665 flen = strlen(filter);
666 }
667
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800668 sol = data;
Jeff Sharkeyf96b0442014-03-06 14:26:36 -0800669 while ((eol = strchr(sol, '\n'))) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800670 key = sol;
671 *eol++ = 0;
672 sol = eol;
673
Jeff Sharkeyf96b0442014-03-06 14:26:36 -0800674 while (isspace(*key)) key++;
675 if (*key == '#') continue;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800676
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800677 tmp = eol - 2;
Jeff Sharkeyf96b0442014-03-06 14:26:36 -0800678 while ((tmp > key) && isspace(*tmp)) *tmp-- = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800679
Jeff Sharkeyf96b0442014-03-06 14:26:36 -0800680 if (!strncmp(key, "import ", 7) && flen == 0) {
681 fn = key + 7;
682 while (isspace(*fn)) fn++;
683
684 key = strchr(fn, ' ');
685 if (key) {
686 *key++ = 0;
687 while (isspace(*key)) key++;
688 }
689
Dongcheol Shina87c0f92019-06-12 09:31:35 +0900690 std::string raw_filename(fn);
Tom Cherryc5cf85d2019-07-31 13:59:15 -0700691 auto expanded_filename = ExpandProps(raw_filename);
692
Bernie Innocenticecebbb2020-02-06 03:49:33 +0900693 if (!expanded_filename.ok()) {
Tom Cherryc5cf85d2019-07-31 13:59:15 -0700694 LOG(ERROR) << "Could not expand filename ': " << expanded_filename.error();
Dongcheol Shina87c0f92019-06-12 09:31:35 +0900695 continue;
696 }
Jeff Sharkeyf96b0442014-03-06 14:26:36 -0800697
Inseob Kim946c9722022-05-23 16:37:44 +0900698 if (auto res = load_properties_from_file(expanded_filename->c_str(), key, properties);
699 !res.ok()) {
700 LOG(WARNING) << res.error();
701 }
Jeff Sharkeyf96b0442014-03-06 14:26:36 -0800702 } else {
703 value = strchr(key, '=');
704 if (!value) continue;
705 *value++ = 0;
706
707 tmp = value - 2;
708 while ((tmp > key) && isspace(*tmp)) *tmp-- = 0;
709
710 while (isspace(*value)) value++;
711
712 if (flen > 0) {
713 if (filter[flen - 1] == '*') {
Tom Cherry247ffbf2019-07-08 15:09:36 -0700714 if (strncmp(key, filter, flen - 1) != 0) continue;
Jeff Sharkeyf96b0442014-03-06 14:26:36 -0800715 } else {
Tom Cherry247ffbf2019-07-08 15:09:36 -0700716 if (strcmp(key, filter) != 0) continue;
Jeff Sharkeyf96b0442014-03-06 14:26:36 -0800717 }
718 }
719
Tom Cherrydc375862018-02-28 10:39:01 -0800720 if (StartsWith(key, "ctl.") || key == "sys.powerctl"s ||
Tom Cherryfe815412019-04-23 15:11:07 -0700721 std::string{key} == kRestoreconProperty) {
Tom Cherrydc375862018-02-28 10:39:01 -0800722 LOG(ERROR) << "Ignoring disallowed property '" << key
723 << "' with special meaning in prop file '" << filename << "'";
724 continue;
725 }
726
Tom Cherrydc375862018-02-28 10:39:01 -0800727 ucred cr = {.pid = 1, .uid = 0, .gid = 0};
728 std::string error;
Tom Cherrybe048922019-02-16 12:03:19 -0800729 if (CheckPermissions(key, value, context, cr, &error) == PROP_SUCCESS) {
730 auto it = properties->find(key);
731 if (it == properties->end()) {
732 (*properties)[key] = value;
733 } else if (it->second != value) {
Jiyong Parke714cde2020-06-11 19:41:54 +0900734 LOG(WARNING) << "Overriding previous property '" << key << "':'" << it->second
735 << "' with new value '" << value << "'";
Tom Cherrybe048922019-02-16 12:03:19 -0800736 it->second = value;
737 }
738 } else {
739 LOG(ERROR) << "Do not have permissions to set '" << key << "' to '" << value
Tom Cherrydc375862018-02-28 10:39:01 -0800740 << "' in property file '" << filename << "': " << error;
741 }
Jeff Sharkeyf96b0442014-03-06 14:26:36 -0800742 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800743 }
744}
745
Elliott Hughes5a7ad842016-09-30 14:12:33 -0700746// Filter is used to decide which properties to load: NULL loads all keys,
747// "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match.
Inseob Kim946c9722022-05-23 16:37:44 +0900748static Result<void> load_properties_from_file(const char* filename, const char* filter,
749 std::map<std::string, std::string>* properties) {
Elliott Hughesda40c002015-03-27 23:20:44 -0700750 Timer t;
Tom Cherry62ca6632017-08-03 12:54:07 -0700751 auto file_contents = ReadFile(filename);
Bernie Innocenticecebbb2020-02-06 03:49:33 +0900752 if (!file_contents.ok()) {
Inseob Kim946c9722022-05-23 16:37:44 +0900753 return Error() << "Couldn't load property file '" << filename
754 << "': " << file_contents.error();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800755 }
Tom Cherry62ca6632017-08-03 12:54:07 -0700756 file_contents->push_back('\n');
Tom Cherrydc375862018-02-28 10:39:01 -0800757
Tom Cherrybe048922019-02-16 12:03:19 -0800758 LoadProperties(file_contents->data(), filter, filename, properties);
Elliott Hughes331cf2f2016-11-29 19:20:58 +0000759 LOG(VERBOSE) << "(Loading properties from " << filename << " took " << t << ".)";
Inseob Kim946c9722022-05-23 16:37:44 +0900760 return {};
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800761}
762
Yifan Honga68ee762020-10-06 16:58:19 -0700763static void LoadPropertiesFromSecondStageRes(std::map<std::string, std::string>* properties) {
764 std::string prop = GetRamdiskPropForSecondStage();
765 if (access(prop.c_str(), R_OK) != 0) {
766 CHECK(errno == ENOENT) << "Cannot access " << prop << ": " << strerror(errno);
767 return;
768 }
Inseob Kim946c9722022-05-23 16:37:44 +0900769 if (auto res = load_properties_from_file(prop.c_str(), nullptr, properties); !res.ok()) {
770 LOG(WARNING) << res.error();
771 }
Yifan Honga68ee762020-10-06 16:58:19 -0700772}
773
Jaekyun Seok0cf3a072017-04-24 18:52:54 +0900774// persist.sys.usb.config values can't be combined on build-time when property
775// files are split into each partition.
776// So we need to apply the same rule of build/make/tools/post_process_props.py
777// on runtime.
778static void update_sys_usb_config() {
779 bool is_debuggable = android::base::GetBoolProperty("ro.debuggable", false);
780 std::string config = android::base::GetProperty("persist.sys.usb.config", "");
Howard Yenbb578202020-02-26 21:36:59 +0800781 // b/150130503, add (config == "none") condition here to prevent appending
782 // ",adb" if "none" is explicitly defined in default prop.
783 if (config.empty() || config == "none") {
Tom Cherryc88d8f92019-08-19 15:21:25 -0700784 InitPropertySet("persist.sys.usb.config", is_debuggable ? "adb" : "none");
Jaekyun Seok0cf3a072017-04-24 18:52:54 +0900785 } else if (is_debuggable && config.find("adb") == std::string::npos &&
786 config.length() + 4 < PROP_VALUE_MAX) {
787 config.append(",adb");
Tom Cherryc88d8f92019-08-19 15:21:25 -0700788 InitPropertySet("persist.sys.usb.config", config);
Jaekyun Seok0cf3a072017-04-24 18:52:54 +0900789 }
790}
791
Nick Kralevich32b90232012-09-19 11:15:24 -0700792static void load_override_properties() {
Elliott Hughesc0e919c2015-02-04 14:46:36 -0800793 if (ALLOW_LOCAL_PROP_OVERRIDE) {
Tom Cherrybe048922019-02-16 12:03:19 -0800794 std::map<std::string, std::string> properties;
795 load_properties_from_file("/data/local.prop", nullptr, &properties);
796 for (const auto& [name, value] : properties) {
797 std::string error;
798 if (PropertySet(name, value, &error) != PROP_SUCCESS) {
799 LOG(ERROR) << "Could not set '" << name << "' to '" << value
800 << "' in /data/local.prop: " << error;
801 }
802 }
Nick Kralevich32b90232012-09-19 11:15:24 -0700803 }
Nick Kralevich32b90232012-09-19 11:15:24 -0700804}
805
Steven Laver57a740e2019-01-29 20:19:05 -0800806// If the ro.product.[brand|device|manufacturer|model|name] properties have not been explicitly
807// set, derive them from ro.product.${partition}.* properties
808static void property_initialize_ro_product_props() {
809 const char* RO_PRODUCT_PROPS_PREFIX = "ro.product.";
810 const char* RO_PRODUCT_PROPS[] = {
811 "brand", "device", "manufacturer", "model", "name",
812 };
813 const char* RO_PRODUCT_PROPS_ALLOWED_SOURCES[] = {
Justin Yun7eaf9b52019-06-28 14:28:00 +0900814 "odm", "product", "system_ext", "system", "vendor",
Steven Laver57a740e2019-01-29 20:19:05 -0800815 };
Justin Yun7eaf9b52019-06-28 14:28:00 +0900816 const char* RO_PRODUCT_PROPS_DEFAULT_SOURCE_ORDER = "product,odm,vendor,system_ext,system";
Steven Laver57a740e2019-01-29 20:19:05 -0800817 const std::string EMPTY = "";
818
819 std::string ro_product_props_source_order =
820 GetProperty("ro.product.property_source_order", EMPTY);
821
822 if (!ro_product_props_source_order.empty()) {
823 // Verify that all specified sources are valid
824 for (const auto& source : Split(ro_product_props_source_order, ",")) {
825 // Verify that the specified source is valid
826 bool is_allowed_source = false;
827 for (const auto& allowed_source : RO_PRODUCT_PROPS_ALLOWED_SOURCES) {
828 if (source == allowed_source) {
829 is_allowed_source = true;
830 break;
831 }
832 }
833 if (!is_allowed_source) {
834 LOG(ERROR) << "Found unexpected source in ro.product.property_source_order; "
835 "using the default property source order";
836 ro_product_props_source_order = RO_PRODUCT_PROPS_DEFAULT_SOURCE_ORDER;
837 break;
838 }
839 }
840 } else {
841 ro_product_props_source_order = RO_PRODUCT_PROPS_DEFAULT_SOURCE_ORDER;
842 }
843
844 for (const auto& ro_product_prop : RO_PRODUCT_PROPS) {
845 std::string base_prop(RO_PRODUCT_PROPS_PREFIX);
846 base_prop += ro_product_prop;
847
848 std::string base_prop_val = GetProperty(base_prop, EMPTY);
849 if (!base_prop_val.empty()) {
850 continue;
851 }
852
853 for (const auto& source : Split(ro_product_props_source_order, ",")) {
854 std::string target_prop(RO_PRODUCT_PROPS_PREFIX);
855 target_prop += source;
856 target_prop += '.';
857 target_prop += ro_product_prop;
858
859 std::string target_prop_val = GetProperty(target_prop, EMPTY);
860 if (!target_prop_val.empty()) {
861 LOG(INFO) << "Setting product property " << base_prop << " to '" << target_prop_val
862 << "' (from " << target_prop << ")";
863 std::string error;
864 uint32_t res = PropertySet(base_prop, target_prop_val, &error);
865 if (res != PROP_SUCCESS) {
866 LOG(ERROR) << "Error setting product property " << base_prop << ": err=" << res
867 << " (" << error << ")";
868 }
869 break;
870 }
871 }
872 }
873}
874
Tianjiebecfa772021-05-05 17:23:46 -0700875static void property_initialize_build_id() {
876 std::string build_id = GetProperty(ID_PROP, "");
877 if (!build_id.empty()) {
Steven Laver57a740e2019-01-29 20:19:05 -0800878 return;
879 }
880
Tianjiebecfa772021-05-05 17:23:46 -0700881 std::string legacy_build_id = GetProperty(LEGACY_ID_PROP, "");
882 std::string vbmeta_digest = GetProperty(VBMETA_DIGEST_PROP, "");
883 if (vbmeta_digest.size() < DIGEST_SIZE_USED) {
884 LOG(ERROR) << "vbmeta digest size too small " << vbmeta_digest;
885 // Still try to set the id field in the unexpected case.
886 build_id = legacy_build_id;
887 } else {
888 // Derive the ro.build.id by appending the vbmeta digest to the base value.
889 build_id = legacy_build_id + "." + vbmeta_digest.substr(0, DIGEST_SIZE_USED);
890 }
891
892 std::string error;
893 auto res = PropertySet(ID_PROP, build_id, &error);
894 if (res != PROP_SUCCESS) {
895 LOG(ERROR) << "Failed to set " << ID_PROP << " to " << build_id;
896 }
897}
898
899static std::string ConstructBuildFingerprint(bool legacy) {
Steven Laver57a740e2019-01-29 20:19:05 -0800900 const std::string UNKNOWN = "unknown";
Tianjiebecfa772021-05-05 17:23:46 -0700901 std::string build_fingerprint = GetProperty("ro.product.brand", UNKNOWN);
Steven Laver57a740e2019-01-29 20:19:05 -0800902 build_fingerprint += '/';
903 build_fingerprint += GetProperty("ro.product.name", UNKNOWN);
904 build_fingerprint += '/';
905 build_fingerprint += GetProperty("ro.product.device", UNKNOWN);
906 build_fingerprint += ':';
Colin Crossb519c712020-10-13 12:38:48 -0700907 build_fingerprint += GetProperty("ro.build.version.release_or_codename", UNKNOWN);
Steven Laver57a740e2019-01-29 20:19:05 -0800908 build_fingerprint += '/';
Tianjiebecfa772021-05-05 17:23:46 -0700909
910 std::string build_id =
911 legacy ? GetProperty(LEGACY_ID_PROP, UNKNOWN) : GetProperty(ID_PROP, UNKNOWN);
912 build_fingerprint += build_id;
Steven Laver57a740e2019-01-29 20:19:05 -0800913 build_fingerprint += '/';
914 build_fingerprint += GetProperty("ro.build.version.incremental", UNKNOWN);
915 build_fingerprint += ':';
916 build_fingerprint += GetProperty("ro.build.type", UNKNOWN);
917 build_fingerprint += '/';
918 build_fingerprint += GetProperty("ro.build.tags", UNKNOWN);
919
Tianjiebecfa772021-05-05 17:23:46 -0700920 return build_fingerprint;
921}
922
923// Derive the legacy build fingerprint if we overwrite the build id at runtime.
924static void property_derive_legacy_build_fingerprint() {
925 std::string legacy_build_fingerprint = GetProperty(LEGACY_FINGERPRINT_PROP, "");
926 if (!legacy_build_fingerprint.empty()) {
927 return;
928 }
929
930 // The device doesn't have a legacy build id, skipping the legacy fingerprint.
931 std::string legacy_build_id = GetProperty(LEGACY_ID_PROP, "");
932 if (legacy_build_id.empty()) {
933 return;
934 }
935
936 legacy_build_fingerprint = ConstructBuildFingerprint(true /* legacy fingerprint */);
937 LOG(INFO) << "Setting property '" << LEGACY_FINGERPRINT_PROP << "' to '"
938 << legacy_build_fingerprint << "'";
Steven Laver57a740e2019-01-29 20:19:05 -0800939
940 std::string error;
Tianjiebecfa772021-05-05 17:23:46 -0700941 uint32_t res = PropertySet(LEGACY_FINGERPRINT_PROP, legacy_build_fingerprint, &error);
Steven Laver57a740e2019-01-29 20:19:05 -0800942 if (res != PROP_SUCCESS) {
Tianjiebecfa772021-05-05 17:23:46 -0700943 LOG(ERROR) << "Error setting property '" << LEGACY_FINGERPRINT_PROP << "': err=" << res
944 << " (" << error << ")";
945 }
946}
947
948// If the ro.build.fingerprint property has not been set, derive it from constituent pieces
949static void property_derive_build_fingerprint() {
950 std::string build_fingerprint = GetProperty("ro.build.fingerprint", "");
951 if (!build_fingerprint.empty()) {
952 return;
953 }
954
955 build_fingerprint = ConstructBuildFingerprint(false /* legacy fingerprint */);
956 LOG(INFO) << "Setting property '" << FINGERPRINT_PROP << "' to '" << build_fingerprint << "'";
957
958 std::string error;
959 uint32_t res = PropertySet(FINGERPRINT_PROP, build_fingerprint, &error);
960 if (res != PROP_SUCCESS) {
961 LOG(ERROR) << "Error setting property '" << FINGERPRINT_PROP << "': err=" << res << " ("
962 << error << ")";
Steven Laver57a740e2019-01-29 20:19:05 -0800963 }
964}
965
SzuWei Lin0061d4d2020-12-31 16:52:39 +0800966// If the ro.product.cpu.abilist* properties have not been explicitly
967// set, derive them from ro.${partition}.product.cpu.abilist* properties.
968static void property_initialize_ro_cpu_abilist() {
969 // From high to low priority.
970 const char* kAbilistSources[] = {
971 "product",
972 "odm",
973 "vendor",
974 "system",
975 };
976 const std::string EMPTY = "";
977 const char* kAbilistProp = "ro.product.cpu.abilist";
978 const char* kAbilist32Prop = "ro.product.cpu.abilist32";
979 const char* kAbilist64Prop = "ro.product.cpu.abilist64";
980
981 // If the properties are defined explicitly, just use them.
982 if (GetProperty(kAbilistProp, EMPTY) != EMPTY) {
983 return;
984 }
985
986 // Find the first source defining these properties by order.
987 std::string abilist32_prop_val;
988 std::string abilist64_prop_val;
989 for (const auto& source : kAbilistSources) {
990 const auto abilist32_prop = std::string("ro.") + source + ".product.cpu.abilist32";
991 const auto abilist64_prop = std::string("ro.") + source + ".product.cpu.abilist64";
992 abilist32_prop_val = GetProperty(abilist32_prop, EMPTY);
993 abilist64_prop_val = GetProperty(abilist64_prop, EMPTY);
994 // The properties could be empty on 32-bit-only or 64-bit-only devices,
995 // but we cannot identify a property is empty or undefined by GetProperty().
996 // So, we assume both of these 2 properties are empty as undefined.
997 if (abilist32_prop_val != EMPTY || abilist64_prop_val != EMPTY) {
998 break;
999 }
1000 }
1001
1002 // Merge ABI lists for ro.product.cpu.abilist
1003 auto abilist_prop_val = abilist64_prop_val;
1004 if (abilist32_prop_val != EMPTY) {
1005 if (abilist_prop_val != EMPTY) {
1006 abilist_prop_val += ",";
1007 }
1008 abilist_prop_val += abilist32_prop_val;
1009 }
1010
1011 // Set these properties
1012 const std::pair<const char*, const std::string&> set_prop_list[] = {
1013 {kAbilistProp, abilist_prop_val},
1014 {kAbilist32Prop, abilist32_prop_val},
1015 {kAbilist64Prop, abilist64_prop_val},
1016 };
1017 for (const auto& [prop, prop_val] : set_prop_list) {
1018 LOG(INFO) << "Setting property '" << prop << "' to '" << prop_val << "'";
1019
1020 std::string error;
1021 uint32_t res = PropertySet(prop, prop_val, &error);
1022 if (res != PROP_SUCCESS) {
1023 LOG(ERROR) << "Error setting property '" << prop << "': err=" << res << " (" << error
1024 << ")";
1025 }
1026 }
1027}
1028
Justin Yun4446a852021-10-13 18:13:28 +09001029static int read_api_level_props(const std::vector<std::string>& api_level_props) {
1030 int api_level = API_LEVEL_CURRENT;
1031 for (const auto& api_level_prop : api_level_props) {
1032 api_level = android::base::GetIntProperty(api_level_prop, API_LEVEL_CURRENT);
1033 if (api_level != API_LEVEL_CURRENT) {
1034 break;
1035 }
1036 }
1037 return api_level;
1038}
1039
Justin Yundfbdd932021-09-29 15:37:27 +09001040static void property_initialize_ro_vendor_api_level() {
1041 // ro.vendor.api_level shows the api_level that the vendor images (vendor, odm, ...) are
1042 // required to support.
1043 constexpr auto VENDOR_API_LEVEL_PROP = "ro.vendor.api_level";
Justin Yundfbdd932021-09-29 15:37:27 +09001044
Justin Yun4446a852021-10-13 18:13:28 +09001045 // Api level properties of the board. The order of the properties must be kept.
Justin Yund1e4f7d2022-02-11 09:44:31 +09001046 std::vector<std::string> BOARD_API_LEVEL_PROPS = {"ro.board.api_level",
1047 "ro.board.first_api_level"};
Justin Yun4446a852021-10-13 18:13:28 +09001048 // Api level properties of the device. The order of the properties must be kept.
1049 std::vector<std::string> DEVICE_API_LEVEL_PROPS = {"ro.product.first_api_level",
1050 "ro.build.version.sdk"};
1051
1052 int api_level = std::min(read_api_level_props(BOARD_API_LEVEL_PROPS),
1053 read_api_level_props(DEVICE_API_LEVEL_PROPS));
1054 std::string error;
1055 uint32_t res = PropertySet(VENDOR_API_LEVEL_PROP, std::to_string(api_level), &error);
1056 if (res != PROP_SUCCESS) {
1057 LOG(ERROR) << "Failed to set " << VENDOR_API_LEVEL_PROP << " with " << api_level << ": "
1058 << error << "(" << res << ")";
Justin Yundfbdd932021-09-29 15:37:27 +09001059 }
Justin Yundfbdd932021-09-29 15:37:27 +09001060}
1061
Tom Cherryc88d8f92019-08-19 15:21:25 -07001062void PropertyLoadBootDefaults() {
Tom Cherrybe048922019-02-16 12:03:19 -08001063 // We read the properties and their values into a map, in order to always allow properties
1064 // loaded in the later property files to override the properties in loaded in the earlier
1065 // property files, regardless of if they are "ro." properties or not.
1066 std::map<std::string, std::string> properties;
Jiyong Parkc068d0e2020-05-11 16:47:05 +09001067
1068 if (IsRecoveryMode()) {
Inseob Kim946c9722022-05-23 16:37:44 +09001069 if (auto res = load_properties_from_file("/prop.default", nullptr, &properties);
1070 !res.ok()) {
1071 LOG(ERROR) << res.error();
1072 }
Jiyong Park3b316ee2019-01-13 02:42:31 +09001073 }
Jiyong Parkc068d0e2020-05-11 16:47:05 +09001074
Jiyong Park8178c5f2020-06-29 10:42:03 +09001075 // /<part>/etc/build.prop is the canonical location of the build-time properties since S.
1076 // Falling back to /<part>/defalt.prop and /<part>/build.prop only when legacy path has to
1077 // be supported, which is controlled by the support_legacy_path_until argument.
1078 const auto load_properties_from_partition = [&properties](const std::string& partition,
1079 int support_legacy_path_until) {
1080 auto path = "/" + partition + "/etc/build.prop";
Inseob Kim946c9722022-05-23 16:37:44 +09001081 if (load_properties_from_file(path.c_str(), nullptr, &properties).ok()) {
Jiyong Park8178c5f2020-06-29 10:42:03 +09001082 return;
1083 }
1084 // To read ro.<partition>.build.version.sdk, temporarily load the legacy paths into a
1085 // separate map. Then by comparing its value with legacy_version, we know that if the
1086 // partition is old enough so that we need to respect the legacy paths.
1087 std::map<std::string, std::string> temp;
1088 auto legacy_path1 = "/" + partition + "/default.prop";
1089 auto legacy_path2 = "/" + partition + "/build.prop";
1090 load_properties_from_file(legacy_path1.c_str(), nullptr, &temp);
1091 load_properties_from_file(legacy_path2.c_str(), nullptr, &temp);
1092 bool support_legacy_path = false;
1093 auto version_prop_name = "ro." + partition + ".build.version.sdk";
1094 auto it = temp.find(version_prop_name);
1095 if (it == temp.end()) {
1096 // This is embarassing. Without the prop, we can't determine how old the partition is.
1097 // Let's be conservative by assuming it is very very old.
1098 support_legacy_path = true;
1099 } else if (int value;
1100 ParseInt(it->second.c_str(), &value) && value <= support_legacy_path_until) {
1101 support_legacy_path = true;
1102 }
1103 if (support_legacy_path) {
1104 // We don't update temp into properties directly as it might skip any (future) logic
1105 // for resolving duplicates implemented in load_properties_from_file. Instead, read
1106 // the files again into the properties map.
1107 load_properties_from_file(legacy_path1.c_str(), nullptr, &properties);
1108 load_properties_from_file(legacy_path2.c_str(), nullptr, &properties);
1109 } else {
1110 LOG(FATAL) << legacy_path1 << " and " << legacy_path2 << " were not loaded "
1111 << "because " << version_prop_name << "(" << it->second << ") is newer "
1112 << "than " << support_legacy_path_until;
1113 }
1114 };
1115
1116 // Order matters here. The more the partition is specific to a product, the higher its
1117 // precedence is.
Yifan Honga68ee762020-10-06 16:58:19 -07001118 LoadPropertiesFromSecondStageRes(&properties);
Inseob Kim946c9722022-05-23 16:37:44 +09001119
1120 // system should have build.prop, unlike the other partitions
1121 if (auto res = load_properties_from_file("/system/build.prop", nullptr, &properties);
1122 !res.ok()) {
1123 LOG(WARNING) << res.error();
1124 }
1125
Jiyong Park8178c5f2020-06-29 10:42:03 +09001126 load_properties_from_partition("system_ext", /* support_legacy_path_until */ 30);
Ramji Jiyani84313282022-01-28 02:34:29 +00001127 load_properties_from_file("/system_dlkm/etc/build.prop", nullptr, &properties);
Jiyong Park8178c5f2020-06-29 10:42:03 +09001128 // TODO(b/117892318): uncomment the following condition when vendor.imgs for aosp_* targets are
1129 // all updated.
1130 // if (SelinuxGetVendorAndroidVersion() <= __ANDROID_API_R__) {
1131 load_properties_from_file("/vendor/default.prop", nullptr, &properties);
1132 // }
Tom Cherrybe048922019-02-16 12:03:19 -08001133 load_properties_from_file("/vendor/build.prop", nullptr, &properties);
Yifan Hong2ed3cda2020-06-24 18:29:22 -07001134 load_properties_from_file("/vendor_dlkm/etc/build.prop", nullptr, &properties);
Yifan Hong9258f2e2020-07-15 17:04:43 -07001135 load_properties_from_file("/odm_dlkm/etc/build.prop", nullptr, &properties);
Jiyong Park8178c5f2020-06-29 10:42:03 +09001136 load_properties_from_partition("odm", /* support_legacy_path_until */ 28);
1137 load_properties_from_partition("product", /* support_legacy_path_until */ 30);
Jiyong Park85695522020-05-11 15:59:44 +09001138
Tom Cherryc88d8f92019-08-19 15:21:25 -07001139 if (access(kDebugRamdiskProp, R_OK) == 0) {
Bowgo Tsai30afda72019-04-11 23:57:24 +08001140 LOG(INFO) << "Loading " << kDebugRamdiskProp;
Inseob Kim946c9722022-05-23 16:37:44 +09001141 if (auto res = load_properties_from_file(kDebugRamdiskProp, nullptr, &properties);
1142 !res.ok()) {
1143 LOG(WARNING) << res.error();
1144 }
Bowgo Tsai1dacd422019-03-04 17:53:34 +08001145 }
1146
Tom Cherrybe048922019-02-16 12:03:19 -08001147 for (const auto& [name, value] : properties) {
1148 std::string error;
1149 if (PropertySet(name, value, &error) != PROP_SUCCESS) {
1150 LOG(ERROR) << "Could not set '" << name << "' to '" << value
1151 << "' while loading .prop files" << error;
1152 }
1153 }
Jiyong Park3b316ee2019-01-13 02:42:31 +09001154
Steven Laver57a740e2019-01-29 20:19:05 -08001155 property_initialize_ro_product_props();
Tianjiebecfa772021-05-05 17:23:46 -07001156 property_initialize_build_id();
Steven Laver57a740e2019-01-29 20:19:05 -08001157 property_derive_build_fingerprint();
Tianjiebecfa772021-05-05 17:23:46 -07001158 property_derive_legacy_build_fingerprint();
SzuWei Lin0061d4d2020-12-31 16:52:39 +08001159 property_initialize_ro_cpu_abilist();
Justin Yundfbdd932021-09-29 15:37:27 +09001160 property_initialize_ro_vendor_api_level();
Steven Laver57a740e2019-01-29 20:19:05 -08001161
Jiyong Park3b316ee2019-01-13 02:42:31 +09001162 update_sys_usb_config();
Riley Andrewse4b7b292014-06-16 15:06:21 -07001163}
1164
Tom Cherry2ae2f602017-12-14 01:58:17 +00001165bool LoadPropertyInfoFromFile(const std::string& filename,
1166 std::vector<PropertyInfoEntry>* property_infos) {
1167 auto file_contents = std::string();
1168 if (!ReadFileToString(filename, &file_contents)) {
1169 PLOG(ERROR) << "Could not read properties from '" << filename << "'";
1170 return false;
1171 }
1172
Tom Cherry919458c2018-01-03 14:39:28 -08001173 auto errors = std::vector<std::string>{};
Tom Cherry4b077c52019-12-11 07:56:51 -08001174 bool require_prefix_or_exact = SelinuxGetVendorAndroidVersion() >= __ANDROID_API_R__;
1175 ParsePropertyInfoFile(file_contents, require_prefix_or_exact, property_infos, &errors);
Tom Cherry919458c2018-01-03 14:39:28 -08001176 // Individual parsing errors are reported but do not cause a failed boot, which is what
1177 // returning false would do here.
1178 for (const auto& error : errors) {
1179 LOG(ERROR) << "Could not read line from '" << filename << "': " << error;
Tom Cherry2ae2f602017-12-14 01:58:17 +00001180 }
Tom Cherry919458c2018-01-03 14:39:28 -08001181
Tom Cherry2ae2f602017-12-14 01:58:17 +00001182 return true;
1183}
1184
1185void CreateSerializedPropertyInfo() {
1186 auto property_infos = std::vector<PropertyInfoEntry>();
1187 if (access("/system/etc/selinux/plat_property_contexts", R_OK) != -1) {
1188 if (!LoadPropertyInfoFromFile("/system/etc/selinux/plat_property_contexts",
1189 &property_infos)) {
1190 return;
1191 }
Tom Cherry2d451662020-07-27 11:20:29 -07001192 // Don't check for failure here, since we don't always have all of these partitions.
Tom Cherry2ae2f602017-12-14 01:58:17 +00001193 // E.g. In case of recovery, the vendor partition will not have mounted and we
1194 // still need the system / platform properties to function.
Jeffrey Vander Stoepbaeece62022-02-08 12:42:33 +00001195 if (access("/dev/selinux/apex_property_contexts", R_OK) != -1) {
1196 LoadPropertyInfoFromFile("/dev/selinux/apex_property_contexts", &property_infos);
1197 }
Bowgo Tsai1a191bf2019-10-02 16:23:32 +08001198 if (access("/system_ext/etc/selinux/system_ext_property_contexts", R_OK) != -1) {
1199 LoadPropertyInfoFromFile("/system_ext/etc/selinux/system_ext_property_contexts",
1200 &property_infos);
1201 }
Jeff Vander Stoep5effda42021-11-05 09:03:11 +01001202 if (access("/vendor/etc/selinux/vendor_property_contexts", R_OK) != -1) {
1203 LoadPropertyInfoFromFile("/vendor/etc/selinux/vendor_property_contexts",
Bowgo Tsai36cf3532017-12-07 16:05:25 +08001204 &property_infos);
1205 }
Jinguang Dongf42e08d2019-02-15 16:56:28 +08001206 if (access("/product/etc/selinux/product_property_contexts", R_OK) != -1) {
1207 LoadPropertyInfoFromFile("/product/etc/selinux/product_property_contexts",
1208 &property_infos);
1209 }
1210 if (access("/odm/etc/selinux/odm_property_contexts", R_OK) != -1) {
1211 LoadPropertyInfoFromFile("/odm/etc/selinux/odm_property_contexts", &property_infos);
1212 }
Tom Cherry2ae2f602017-12-14 01:58:17 +00001213 } else {
1214 if (!LoadPropertyInfoFromFile("/plat_property_contexts", &property_infos)) {
1215 return;
1216 }
Bowgo Tsai1a191bf2019-10-02 16:23:32 +08001217 LoadPropertyInfoFromFile("/system_ext_property_contexts", &property_infos);
Jeff Vander Stoep5effda42021-11-05 09:03:11 +01001218 LoadPropertyInfoFromFile("/vendor_property_contexts", &property_infos);
Jinguang Dongf42e08d2019-02-15 16:56:28 +08001219 LoadPropertyInfoFromFile("/product_property_contexts", &property_infos);
1220 LoadPropertyInfoFromFile("/odm_property_contexts", &property_infos);
Jeffrey Vander Stoepbaeece62022-02-08 12:42:33 +00001221 LoadPropertyInfoFromFile("/dev/selinux/apex_property_contexts", &property_infos);
Tom Cherry2ae2f602017-12-14 01:58:17 +00001222 }
Tom Cherry927c5d52017-12-11 01:40:07 -08001223
Tom Cherry2ae2f602017-12-14 01:58:17 +00001224 auto serialized_contexts = std::string();
1225 auto error = std::string();
Tom Cherry927c5d52017-12-11 01:40:07 -08001226 if (!BuildTrie(property_infos, "u:object_r:default_prop:s0", "string", &serialized_contexts,
Tom Cherry2ae2f602017-12-14 01:58:17 +00001227 &error)) {
1228 LOG(ERROR) << "Unable to serialize property contexts: " << error;
1229 return;
1230 }
1231
1232 constexpr static const char kPropertyInfosPath[] = "/dev/__properties__/property_info";
1233 if (!WriteStringToFile(serialized_contexts, kPropertyInfosPath, 0444, 0, 0, false)) {
1234 PLOG(ERROR) << "Unable to write serialized property infos to file";
1235 }
1236 selinux_android_restorecon(kPropertyInfosPath, 0);
1237}
1238
Tom Cherryc88d8f92019-08-19 15:21:25 -07001239static void ExportKernelBootProps() {
1240 constexpr const char* UNSET = "";
1241 struct {
1242 const char* src_prop;
1243 const char* dst_prop;
1244 const char* default_value;
1245 } prop_map[] = {
1246 // clang-format off
1247 { "ro.boot.serialno", "ro.serialno", UNSET, },
1248 { "ro.boot.mode", "ro.bootmode", "unknown", },
1249 { "ro.boot.baseband", "ro.baseband", "unknown", },
1250 { "ro.boot.bootloader", "ro.bootloader", "unknown", },
1251 { "ro.boot.hardware", "ro.hardware", "unknown", },
1252 { "ro.boot.revision", "ro.revision", "0", },
1253 // clang-format on
1254 };
1255 for (const auto& prop : prop_map) {
1256 std::string value = GetProperty(prop.src_prop, prop.default_value);
1257 if (value != UNSET) InitPropertySet(prop.dst_prop, value);
1258 }
1259}
1260
1261static void ProcessKernelDt() {
1262 if (!is_android_dt_value_expected("compatible", "android,firmware")) {
1263 return;
1264 }
1265
1266 std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(get_android_dt_dir().c_str()), closedir);
1267 if (!dir) return;
1268
1269 std::string dt_file;
1270 struct dirent* dp;
1271 while ((dp = readdir(dir.get())) != NULL) {
1272 if (dp->d_type != DT_REG || !strcmp(dp->d_name, "compatible") ||
1273 !strcmp(dp->d_name, "name")) {
1274 continue;
1275 }
1276
1277 std::string file_name = get_android_dt_dir() + dp->d_name;
1278
1279 android::base::ReadFileToString(file_name, &dt_file);
1280 std::replace(dt_file.begin(), dt_file.end(), ',', '.');
1281
1282 InitPropertySet("ro.boot."s + dp->d_name, dt_file);
1283 }
1284}
1285
Roman Kiryanovccc15c52021-03-09 13:20:36 -08001286constexpr auto ANDROIDBOOT_PREFIX = "androidboot."sv;
1287
Tom Cherryc88d8f92019-08-19 15:21:25 -07001288static void ProcessKernelCmdline() {
Tom Cherryc88d8f92019-08-19 15:21:25 -07001289 ImportKernelCmdline([&](const std::string& key, const std::string& value) {
Roman Kiryanov1a705d42021-03-09 18:19:23 -08001290 if (StartsWith(key, ANDROIDBOOT_PREFIX)) {
Roman Kiryanovccc15c52021-03-09 13:20:36 -08001291 InitPropertySet("ro.boot." + key.substr(ANDROIDBOOT_PREFIX.size()), value);
Tom Cherryc88d8f92019-08-19 15:21:25 -07001292 }
1293 });
Tom Cherryc88d8f92019-08-19 15:21:25 -07001294}
1295
Roman Kiryanov6e20ff82021-04-28 15:15:44 -07001296
Devin Moorea4ef15b2020-12-15 16:14:37 -08001297static void ProcessBootconfig() {
1298 ImportBootconfig([&](const std::string& key, const std::string& value) {
Roman Kiryanovccc15c52021-03-09 13:20:36 -08001299 if (StartsWith(key, ANDROIDBOOT_PREFIX)) {
1300 InitPropertySet("ro.boot." + key.substr(ANDROIDBOOT_PREFIX.size()), value);
Devin Moorea4ef15b2020-12-15 16:14:37 -08001301 }
1302 });
1303}
1304
Tom Cherryc88d8f92019-08-19 15:21:25 -07001305void PropertyInit() {
1306 selinux_callback cb;
1307 cb.func_audit = PropertyAuditCallback;
1308 selinux_set_callback(SELINUX_CB_AUDIT, cb);
1309
1310 mkdir("/dev/__properties__", S_IRWXU | S_IXGRP | S_IXOTH);
1311 CreateSerializedPropertyInfo();
1312 if (__system_property_area_init()) {
1313 LOG(FATAL) << "Failed to initialize property area";
1314 }
1315 if (!property_info_area.LoadDefaultPath()) {
1316 LOG(FATAL) << "Failed to load serialized property info file";
1317 }
1318
1319 // If arguments are passed both on the command line and in DT,
1320 // properties set in DT always have priority over the command-line ones.
1321 ProcessKernelDt();
1322 ProcessKernelCmdline();
Devin Moorea4ef15b2020-12-15 16:14:37 -08001323 ProcessBootconfig();
Tom Cherryc88d8f92019-08-19 15:21:25 -07001324
1325 // Propagate the kernel variables to internal variables
1326 // used by init as well as the current required properties.
1327 ExportKernelBootProps();
1328
1329 PropertyLoadBootDefaults();
1330}
1331
Tom Cherry1ab3dfc2019-04-22 17:46:37 -07001332static void HandleInitSocket() {
1333 auto message = ReadMessage(init_socket);
Bernie Innocenticecebbb2020-02-06 03:49:33 +09001334 if (!message.ok()) {
Tom Cherry1ab3dfc2019-04-22 17:46:37 -07001335 LOG(ERROR) << "Could not read message from init_dedicated_recv_socket: " << message.error();
1336 return;
1337 }
1338
1339 auto init_message = InitMessage{};
1340 if (!init_message.ParseFromString(*message)) {
1341 LOG(ERROR) << "Could not parse message from init";
1342 return;
1343 }
1344
1345 switch (init_message.msg_case()) {
1346 case InitMessage::kLoadPersistentProperties: {
1347 load_override_properties();
1348 // Read persistent properties after all default values have been loaded.
1349 auto persistent_properties = LoadPersistentProperties();
1350 for (const auto& persistent_property_record : persistent_properties.properties()) {
1351 InitPropertySet(persistent_property_record.name(),
1352 persistent_property_record.value());
1353 }
Yi-Yo Chiang70c53f52022-06-08 19:11:43 +08001354 // Apply debug ramdisk special settings after persistent properties are loaded.
1355 if (android::base::GetBoolProperty("ro.force.debuggable", false)) {
1356 // Always enable usb adb if device is booted with debug ramdisk.
1357 update_sys_usb_config();
1358 }
Tom Cherry1ab3dfc2019-04-22 17:46:37 -07001359 InitPropertySet("ro.persistent_properties.ready", "true");
1360 persistent_properties_loaded = true;
1361 break;
1362 }
Tom Cherry1ab3dfc2019-04-22 17:46:37 -07001363 default:
1364 LOG(ERROR) << "Unknown message type from init: " << init_message.msg_case();
1365 }
1366}
1367
1368static void PropertyServiceThread() {
1369 Epoll epoll;
Bernie Innocenticecebbb2020-02-06 03:49:33 +09001370 if (auto result = epoll.Open(); !result.ok()) {
Tom Cherry1ab3dfc2019-04-22 17:46:37 -07001371 LOG(FATAL) << result.error();
1372 }
1373
Bernie Innocenticecebbb2020-02-06 03:49:33 +09001374 if (auto result = epoll.RegisterHandler(property_set_fd, handle_property_set_fd);
1375 !result.ok()) {
Tom Cherry1ab3dfc2019-04-22 17:46:37 -07001376 LOG(FATAL) << result.error();
1377 }
1378
Bernie Innocenticecebbb2020-02-06 03:49:33 +09001379 if (auto result = epoll.RegisterHandler(init_socket, HandleInitSocket); !result.ok()) {
Tom Cherry1ab3dfc2019-04-22 17:46:37 -07001380 LOG(FATAL) << result.error();
1381 }
1382
Tom Cherry832f9f12020-03-10 11:47:24 -07001383 while (true) {
Tom Cherry1ab3dfc2019-04-22 17:46:37 -07001384 auto pending_functions = epoll.Wait(std::nullopt);
Bernie Innocenticecebbb2020-02-06 03:49:33 +09001385 if (!pending_functions.ok()) {
Tom Cherry1ab3dfc2019-04-22 17:46:37 -07001386 LOG(ERROR) << pending_functions.error();
1387 } else {
1388 for (const auto& function : *pending_functions) {
1389 (*function)();
1390 }
1391 }
1392 }
1393}
1394
1395void StartPropertyService(int* epoll_socket) {
Tom Cherryc88d8f92019-08-19 15:21:25 -07001396 InitPropertySet("ro.property_service.version", "2");
Dimitry Ivanovc9bb0332017-01-24 20:43:58 +00001397
Tom Cherry1ab3dfc2019-04-22 17:46:37 -07001398 int sockets[2];
1399 if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockets) != 0) {
1400 PLOG(FATAL) << "Failed to socketpair() between property_service and init";
1401 }
Tom Cherry802864c2020-03-12 14:29:25 -07001402 *epoll_socket = from_init_socket = sockets[0];
Tom Cherry1ab3dfc2019-04-22 17:46:37 -07001403 init_socket = sockets[1];
Tom Cherry802864c2020-03-12 14:29:25 -07001404 StartSendingMessages();
Tom Cherry1ab3dfc2019-04-22 17:46:37 -07001405
Tom Cherry3da2ba62019-08-28 17:47:49 +00001406 if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
Bernie Innocenticecebbb2020-02-06 03:49:33 +09001407 false, 0666, 0, 0, {});
1408 result.ok()) {
Tom Cherry2e4c85f2019-07-09 13:33:36 -07001409 property_set_fd = *result;
1410 } else {
Tom Cherry1ab3dfc2019-04-22 17:46:37 -07001411 LOG(FATAL) << "start_property_service socket creation failed: " << result.error();
Elliott Hughesc6c26ed2015-04-24 18:50:30 -07001412 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001413
Elliott Hughesc6c26ed2015-04-24 18:50:30 -07001414 listen(property_set_fd, 8);
Colin Crossd11beb22010-04-13 19:33:37 -07001415
Tom Cherry802864c2020-03-12 14:29:25 -07001416 auto new_thread = std::thread{PropertyServiceThread};
1417 property_service_thread.swap(new_thread);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001418}
Tom Cherry81f5d3e2017-06-22 12:53:17 -07001419
1420} // namespace init
1421} // namespace android