diff --git a/init/Android.bp b/init/Android.bp index 66a3172c0..3233cc310 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -128,7 +128,6 @@ cc_library_static { "persistent_properties.cpp", "persistent_properties.proto", "property_service.cpp", - "property_service.proto", "property_type.cpp", "reboot.cpp", "reboot_utils.cpp", diff --git a/init/builtins.cpp b/init/builtins.cpp index 707692644..e17e8993c 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -80,7 +80,6 @@ using namespace std::literals::string_literals; using android::base::Basename; -using android::base::StartsWith; using android::base::unique_fd; using android::fs_mgr::Fstab; using android::fs_mgr::ReadFstabFromFile; @@ -688,15 +687,6 @@ static Result do_swapon_all(const BuiltinArguments& args) { } static Result do_setprop(const BuiltinArguments& args) { - if (StartsWith(args[1], "ctl.")) { - return Error() - << "Cannot set ctl. properties from init; call the Service functions directly"; - } - if (args[1] == kRestoreconProperty) { - return Error() << "Cannot set '" << kRestoreconProperty - << "' from init; use the restorecon builtin directly"; - } - property_set(args[1], args[2]); return {}; } @@ -1012,20 +1002,7 @@ static Result do_loglevel(const BuiltinArguments& args) { } static Result do_load_persist_props(const BuiltinArguments& args) { - // Devices with FDE have load_persist_props called twice; the first time when the temporary - // /data partition is mounted and then again once /data is truly mounted. We do not want to - // read persistent properties from the temporary /data partition or mark persistent properties - // as having been loaded during the first call, so we return in that case. - std::string crypto_state = android::base::GetProperty("ro.crypto.state", ""); - std::string crypto_type = android::base::GetProperty("ro.crypto.type", ""); - if (crypto_state == "encrypted" && crypto_type == "block") { - static size_t num_calls = 0; - if (++num_calls == 1) return {}; - } - - SendLoadPersistentPropertiesMessage(); - - start_waiting_for_property("ro.persistent_properties.ready", "true"); + load_persist_props(); return {}; } diff --git a/init/init.cpp b/init/init.cpp index e8eb571b8..18fb0c3ee 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -61,7 +61,6 @@ #include "mount_handler.h" #include "mount_namespace.h" #include "property_service.h" -#include "proto_utils.h" #include "reboot.h" #include "reboot_utils.h" #include "security.h" @@ -70,7 +69,6 @@ #include "service.h" #include "service_parser.h" #include "sigchld_handler.h" -#include "system/core/init/property_service.pb.h" #include "util.h" using namespace std::chrono_literals; @@ -92,7 +90,6 @@ static int property_triggers_enabled = 0; static char qemu[32]; static int signal_fd = -1; -static int property_fd = -1; static std::unique_ptr waiting_for_prop(nullptr); static std::string wait_prop_name; @@ -616,54 +613,6 @@ static void RecordStageBoottimes(const boot_clock::time_point& second_stage_star selinux_start_time_ns)); } -void SendLoadPersistentPropertiesMessage() { - auto init_message = InitMessage{}; - init_message.set_load_persistent_properties(true); - if (auto result = SendMessage(property_fd, init_message); !result) { - LOG(ERROR) << "Failed to send load persistent properties message: " << result.error(); - } -} - -static void HandlePropertyFd() { - auto message = ReadMessage(property_fd); - if (!message) { - LOG(ERROR) << "Could not read message from property service: " << message.error(); - return; - } - - auto property_message = PropertyMessage{}; - if (!property_message.ParseFromString(*message)) { - LOG(ERROR) << "Could not parse message from property service"; - return; - } - - switch (property_message.msg_case()) { - case PropertyMessage::kControlMessage: { - auto& control_message = property_message.control_message(); - bool response = HandleControlMessage(control_message.msg(), control_message.name(), - control_message.pid()); - - auto init_message = InitMessage{}; - auto* control_response = init_message.mutable_control_response(); - - control_response->set_result(response); - - if (auto result = SendMessage(property_fd, init_message); !result) { - LOG(ERROR) << "Failed to send control response: " << result.error(); - } - break; - } - case PropertyMessage::kChangedMessage: { - auto& changed_message = property_message.changed_message(); - property_changed(changed_message.name(), changed_message.value()); - break; - } - default: - LOG(ERROR) << "Unknown message type from property service: " - << property_message.msg_case(); - } -} - int SecondStageMain(int argc, char** argv) { if (REBOOT_BOOTLOADER_ON_PANIC) { InstallRebootSignalHandlers(); @@ -735,12 +684,7 @@ int SecondStageMain(int argc, char** argv) { UmountDebugRamdisk(); fs_mgr_vendor_overlay_mount_all(); export_oem_lock_status(); - - StartPropertyService(&property_fd); - if (auto result = epoll.RegisterHandler(property_fd, HandlePropertyFd); !result) { - LOG(FATAL) << "Could not register epoll handler for property fd: " << result.error(); - } - + StartPropertyService(&epoll); MountHandler mount_handler(&epoll); set_usb_controller(); diff --git a/init/init.h b/init/init.h index 832ce3f0b..cfc28f1be 100644 --- a/init/init.h +++ b/init/init.h @@ -31,14 +31,16 @@ namespace init { Parser CreateParser(ActionManager& action_manager, ServiceList& service_list); Parser CreateServiceOnlyParser(ServiceList& service_list); +bool HandleControlMessage(const std::string& msg, const std::string& arg, pid_t pid); + +void property_changed(const std::string& name, const std::string& value); + bool start_waiting_for_property(const char *name, const char *value); void DumpState(); void ResetWaitForProp(); -void SendLoadPersistentPropertiesMessage(); - int SecondStageMain(int argc, char** argv); } // namespace init diff --git a/init/property_service.cpp b/init/property_service.cpp index b7d5743f9..3408ff3be 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -42,7 +42,6 @@ #include #include #include -#include #include #include #include @@ -64,10 +63,8 @@ #include "init.h" #include "persistent_properties.h" #include "property_type.h" -#include "proto_utils.h" #include "selinux.h" #include "subcontext.h" -#include "system/core/init/property_service.pb.h" #include "util.h" using namespace std::literals; @@ -79,7 +76,6 @@ using android::base::StartsWith; using android::base::StringPrintf; using android::base::Timer; using android::base::Trim; -using android::base::unique_fd; using android::base::WriteStringToFile; using android::properties::BuildTrie; using android::properties::ParsePropertyInfoFile; @@ -89,15 +85,14 @@ using android::properties::PropertyInfoEntry; namespace android { namespace init { +static constexpr const char kRestoreconProperty[] = "selinux.restorecon_recursive"; + static bool persistent_properties_loaded = false; static int property_set_fd = -1; -static int init_socket = -1; static PropertyInfoAreaFile property_info_area; -uint32_t HandlePropertySet(const std::string& name, const std::string& value, - const std::string& source_context, const ucred& cr, std::string* error); uint32_t InitPropertySet(const std::string& name, const std::string& value); uint32_t (*property_set)(const std::string& name, const std::string& value) = InitPropertySet; @@ -169,17 +164,6 @@ static bool CheckMacPerms(const std::string& name, const char* target_context, return has_access; } -static void SendPropertyChanged(const std::string& name, const std::string& value) { - auto property_msg = PropertyMessage{}; - auto* changed_message = property_msg.mutable_changed_message(); - changed_message->set_name(name); - changed_message->set_value(value); - - if (auto result = SendMessage(init_socket, property_msg); !result) { - LOG(ERROR) << "Failed to send property changed message: " << result.error(); - } -} - static uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error) { size_t valuelen = value.size(); @@ -215,11 +199,7 @@ static uint32_t PropertySet(const std::string& name, const std::string& value, s if (persistent_properties_loaded && StartsWith(name, "persist.")) { WritePersistentProperty(name, value); } - // If init hasn't started its main loop, then it won't be handling property changed messages - // anyway, so there's no need to try to send them. - if (init_socket != -1) { - SendPropertyChanged(name, value); - } + property_changed(name, value); return PROP_SUCCESS; } @@ -260,6 +240,17 @@ class AsyncRestorecon { }; uint32_t InitPropertySet(const std::string& name, const std::string& value) { + if (StartsWith(name, "ctl.")) { + LOG(ERROR) << "InitPropertySet: Do not set ctl. properties from init; call the Service " + "functions directly"; + return PROP_ERROR_INVALID_NAME; + } + if (name == kRestoreconProperty) { + LOG(ERROR) << "InitPropertySet: Do not set '" << kRestoreconProperty + << "' from init; use the restorecon builtin directly"; + return PROP_ERROR_INVALID_NAME; + } + uint32_t result = 0; ucred cr = {.pid = 1, .uid = 0, .gid = 0}; std::string error; @@ -275,6 +266,8 @@ class SocketConnection { public: SocketConnection(int socket, const ucred& cred) : socket_(socket), cred_(cred) {} + ~SocketConnection() { close(socket_); } + bool RecvUint32(uint32_t* value, uint32_t* timeout_ms) { return RecvFully(value, sizeof(*value), timeout_ms); } @@ -396,62 +389,12 @@ class SocketConnection { return bytes_left == 0; } - unique_fd socket_; + int socket_; ucred cred_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(SocketConnection); }; -// Init responds with whether or not the control message was successful. However, init may set -// properties in the process of handling the control message, particularly when starting services. -// Therefore we cannot block in SendControlMessage() to wait for init's response. Instead, we store -// the SocketConnection for the socket that sent the control message. We then return to the main -// poll loop and handle messages until we get the response from init. -// -// Note that this is a queue, since it is possible for more control messages to come while init is -// handling the first. Both init and property service will handle these in order. -// -// Also note that the 1st version of the property service does not expect a result to be sent, so -// we have a nullopt as a placeholder in the queue to keep track of which control messages have been -// responded to. -static std::queue> pending_control_message_results; - -static uint32_t SendControlMessage(const std::string& msg, const std::string& name, pid_t pid, - std::string* error) { - auto property_msg = PropertyMessage{}; - auto* control_message = property_msg.mutable_control_message(); - control_message->set_msg(msg); - control_message->set_name(name); - control_message->set_pid(pid); - - if (auto result = SendMessage(init_socket, property_msg); !result) { - *error = "Failed to send control message: " + result.error().message(); - return PROP_ERROR_HANDLE_CONTROL_MESSAGE; - } - - return PROP_SUCCESS; -} - -void HandleControlResponse(const InitMessage& init_message) { - if (pending_control_message_results.empty()) { - LOG(ERROR) << "Got a control response without pending control messages"; - return; - } - - if (!pending_control_message_results.front().has_value()) { - pending_control_message_results.pop(); - return; - } - - if (!pending_control_message_results.front().has_value()) { - return; - } - - auto& control_response = init_message.control_response(); - uint32_t response = - control_response.result() ? PROP_SUCCESS : PROP_ERROR_HANDLE_CONTROL_MESSAGE; - pending_control_message_results.front()->SendUint32(response); - pending_control_message_results.pop(); -} - bool CheckControlPropertyPerms(const std::string& name, const std::string& value, const std::string& source_context, const ucred& cr) { // We check the legacy method first but these properties are dontaudit, so we only log an audit @@ -525,7 +468,9 @@ uint32_t HandlePropertySet(const std::string& name, const std::string& value, } if (StartsWith(name, "ctl.")) { - return SendControlMessage(name.c_str() + 4, value, cr.pid, error); + return HandleControlMessage(name.c_str() + 4, value, cr.pid) + ? PROP_SUCCESS + : PROP_ERROR_HANDLE_CONTROL_MESSAGE; } // sys.powerctl is a special property that is used to make the device reboot. We want to log @@ -610,10 +555,6 @@ static void handle_property_set_fd() { << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error; } - if (result == PROP_SUCCESS && StartsWith(prop_name, "ctl.")) { - pending_control_message_results.emplace(std::nullopt); - } - break; } @@ -641,12 +582,7 @@ static void handle_property_set_fd() { LOG(ERROR) << "Unable to set property '" << name << "' from uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error; } - - if (result == PROP_SUCCESS && StartsWith(name, "ctl.")) { - pending_control_message_results.emplace(std::move(socket)); - } else { - socket.SendUint32(result); - } + socket.SendUint32(result); break; } @@ -805,6 +741,33 @@ static void load_override_properties() { } } +/* When booting an encrypted system, /data is not mounted when the + * property service is started, so any properties stored there are + * not loaded. Vold triggers init to load these properties once it + * has mounted /data. + */ +void load_persist_props(void) { + // Devices with FDE have load_persist_props called twice; the first time when the temporary + // /data partition is mounted and then again once /data is truly mounted. We do not want to + // read persistent properties from the temporary /data partition or mark persistent properties + // as having been loaded during the first call, so we return in that case. + std::string crypto_state = android::base::GetProperty("ro.crypto.state", ""); + std::string crypto_type = android::base::GetProperty("ro.crypto.type", ""); + if (crypto_state == "encrypted" && crypto_type == "block") { + static size_t num_calls = 0; + if (++num_calls == 1) return; + } + + load_override_properties(); + /* Read persistent properties after all default values have been loaded. */ + auto persistent_properties = LoadPersistentProperties(); + for (const auto& persistent_property_record : persistent_properties.properties()) { + property_set(persistent_property_record.name(), persistent_property_record.value()); + } + persistent_properties_loaded = true; + property_set("ro.persistent_properties.ready", "true"); +} + // If the ro.product.[brand|device|manufacturer|model|name] properties have not been explicitly // set, derive them from ro.product.${partition}.* properties static void property_initialize_ro_product_props() { @@ -1022,87 +985,21 @@ void CreateSerializedPropertyInfo() { selinux_android_restorecon(kPropertyInfosPath, 0); } -static void HandleInitSocket() { - auto message = ReadMessage(init_socket); - if (!message) { - LOG(ERROR) << "Could not read message from init_dedicated_recv_socket: " << message.error(); - return; - } - - auto init_message = InitMessage{}; - if (!init_message.ParseFromString(*message)) { - LOG(ERROR) << "Could not parse message from init"; - return; - } - - switch (init_message.msg_case()) { - case InitMessage::kControlResponse: { - HandleControlResponse(init_message); - break; - } - case InitMessage::kLoadPersistentProperties: { - load_override_properties(); - // Read persistent properties after all default values have been loaded. - auto persistent_properties = LoadPersistentProperties(); - for (const auto& persistent_property_record : persistent_properties.properties()) { - InitPropertySet(persistent_property_record.name(), - persistent_property_record.value()); - } - InitPropertySet("ro.persistent_properties.ready", "true"); - persistent_properties_loaded = true; - break; - } - default: - LOG(ERROR) << "Unknown message type from init: " << init_message.msg_case(); - } -} - -static void PropertyServiceThread() { - Epoll epoll; - if (auto result = epoll.Open(); !result) { - LOG(FATAL) << result.error(); - } - - if (auto result = epoll.RegisterHandler(property_set_fd, handle_property_set_fd); !result) { - LOG(FATAL) << result.error(); - } - - if (auto result = epoll.RegisterHandler(init_socket, HandleInitSocket); !result) { - LOG(FATAL) << result.error(); - } - - while (true) { - if (auto result = epoll.Wait(std::nullopt); !result) { - LOG(ERROR) << result.error(); - } - } -} - -void StartPropertyService(int* epoll_socket) { +void StartPropertyService(Epoll* epoll) { property_set("ro.property_service.version", "2"); - int sockets[2]; - if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockets) != 0) { - PLOG(FATAL) << "Failed to socketpair() between property_service and init"; - } - *epoll_socket = sockets[0]; - init_socket = sockets[1]; - - if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC, false, 0666, 0, 0, - {})) { + if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, + false, 0666, 0, 0, {})) { property_set_fd = *result; } else { - LOG(FATAL) << "start_property_service socket creation failed: " << result.error(); + PLOG(FATAL) << "start_property_service socket creation failed: " << result.error(); } listen(property_set_fd, 8); - std::thread{PropertyServiceThread}.detach(); - - property_set = [](const std::string& key, const std::string& value) -> uint32_t { - android::base::SetProperty(key, value); - return 0; - }; + if (auto result = epoll->RegisterHandler(property_set_fd, handle_property_set_fd); !result) { + PLOG(FATAL) << result.error(); + } } } // namespace init diff --git a/init/property_service.h b/init/property_service.h index 8f7d8d96e..7f9f84422 100644 --- a/init/property_service.h +++ b/init/property_service.h @@ -25,15 +25,17 @@ namespace android { namespace init { -static constexpr const char kRestoreconProperty[] = "selinux.restorecon_recursive"; - bool CanReadProperty(const std::string& source_context, const std::string& name); extern uint32_t (*property_set)(const std::string& name, const std::string& value); +uint32_t HandlePropertySet(const std::string& name, const std::string& value, + const std::string& source_context, const ucred& cr, std::string* error); + void property_init(); void property_load_boot_defaults(bool load_debug_prop); -void StartPropertyService(int* epoll_socket); +void load_persist_props(); +void StartPropertyService(Epoll* epoll); } // namespace init } // namespace android diff --git a/init/property_service.proto b/init/property_service.proto deleted file mode 100644 index 894fa137c..000000000 --- a/init/property_service.proto +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -syntax = "proto2"; -option optimize_for = LITE_RUNTIME; - -message PropertyMessage { - message ControlMessage { - optional string msg = 1; - optional string name = 2; - optional int32 pid = 3; - } - - message ChangedMessage { - optional string name = 1; - optional string value = 2; - } - - oneof msg { - ControlMessage control_message = 1; - ChangedMessage changed_message = 2; - }; -} - -message InitMessage { - message ControlResponse { optional bool result = 1; } - - oneof msg { - ControlResponse control_response = 1; - bool load_persistent_properties = 2; - }; -} diff --git a/init/proto_utils.h b/init/proto_utils.h deleted file mode 100644 index 93a7d57a8..000000000 --- a/init/proto_utils.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -#include - -#include "result.h" - -namespace android { -namespace init { - -constexpr size_t kBufferSize = 4096; - -inline Result ReadMessage(int socket) { - char buffer[kBufferSize] = {}; - auto result = TEMP_FAILURE_RETRY(recv(socket, buffer, sizeof(buffer), 0)); - if (result == 0) { - return Error(); - } else if (result < 0) { - return ErrnoError(); - } - return std::string(buffer, result); -} - -template -Result SendMessage(int socket, const T& message) { - std::string message_string; - if (!message.SerializeToString(&message_string)) { - return Error() << "Unable to serialize message"; - } - - if (message_string.size() > kBufferSize) { - return Error() << "Serialized message too long to send"; - } - - if (auto result = - TEMP_FAILURE_RETRY(send(socket, message_string.c_str(), message_string.size(), 0)); - result != static_cast(message_string.size())) { - return ErrnoError() << "send() failed to send message contents"; - } - return {}; -} - -} // namespace init -} // namespace android diff --git a/init/subcontext.cpp b/init/subcontext.cpp index ec93b5837..00f91d830 100644 --- a/init/subcontext.cpp +++ b/init/subcontext.cpp @@ -18,17 +18,16 @@ #include #include +#include #include #include #include -#include #include #include #include "action.h" #include "builtins.h" -#include "proto_utils.h" #include "util.h" #if defined(__ANDROID__) @@ -60,6 +59,45 @@ const char* const paths_and_secontexts[2][2] = { namespace { +constexpr size_t kBufferSize = 4096; + +Result ReadMessage(int socket) { + char buffer[kBufferSize] = {}; + auto result = TEMP_FAILURE_RETRY(recv(socket, buffer, sizeof(buffer), 0)); + if (result == 0) { + return Error(); + } else if (result < 0) { + return ErrnoError(); + } + return std::string(buffer, result); +} + +template +Result SendMessage(int socket, const T& message) { + std::string message_string; + if (!message.SerializeToString(&message_string)) { + return Error() << "Unable to serialize message"; + } + + if (message_string.size() > kBufferSize) { + return Error() << "Serialized message too long to send"; + } + + if (auto result = + TEMP_FAILURE_RETRY(send(socket, message_string.c_str(), message_string.size(), 0)); + result != static_cast(message_string.size())) { + return ErrnoError() << "send() failed to send message contents"; + } + return {}; +} + +std::vector> properties_to_set; + +uint32_t SubcontextPropertySet(const std::string& name, const std::string& value) { + properties_to_set.emplace_back(name, value); + return 0; +} + class SubcontextProcess { public: SubcontextProcess(const BuiltinFunctionMap* function_map, std::string context, int init_fd) @@ -93,6 +131,14 @@ void SubcontextProcess::RunCommand(const SubcontextCommand::ExecuteCommand& exec result = RunBuiltinFunction(map_result->function, args, context_); } + for (const auto& [name, value] : properties_to_set) { + auto property = reply->add_properties_to_set(); + property->set_name(name); + property->set_value(value); + } + + properties_to_set.clear(); + if (result) { reply->set_success(true); } else { @@ -178,10 +224,7 @@ int SubcontextMain(int argc, char** argv, const BuiltinFunctionMap* function_map SelabelInitialize(); - property_set = [](const std::string& key, const std::string& value) -> uint32_t { - android::base::SetProperty(key, value); - return 0; - }; + property_set = SubcontextPropertySet; auto subcontext_process = SubcontextProcess(function_map, context, init_fd); subcontext_process.MainLoop(); @@ -268,6 +311,15 @@ Result Subcontext::Execute(const std::vector& args) { return subcontext_reply.error(); } + for (const auto& property : subcontext_reply->properties_to_set()) { + ucred cr = {.pid = pid_, .uid = 0, .gid = 0}; + std::string error; + if (HandlePropertySet(property.name(), property.value(), context_, cr, &error) != 0) { + LOG(ERROR) << "Subcontext init could not set '" << property.name() << "' to '" + << property.value() << "': " << error; + } + } + if (subcontext_reply->reply_case() == SubcontextReply::kFailure) { auto& failure = subcontext_reply->failure(); return ResultError(failure.error_string(), failure.error_errno()); diff --git a/init/subcontext.proto b/init/subcontext.proto index e68115e0e..c31f4fb68 100644 --- a/init/subcontext.proto +++ b/init/subcontext.proto @@ -38,4 +38,10 @@ message SubcontextReply { Failure failure = 2; ExpandArgsReply expand_args_reply = 3; } + + message PropertyToSet { + optional string name = 1; + optional string value = 2; + } + repeated PropertyToSet properties_to_set = 4; } \ No newline at end of file