Loading init/builtins.cpp +1 −3 Original line number Diff line number Diff line Loading @@ -1039,9 +1039,7 @@ const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const { {"restorecon_recursive", {1, kMax, {true, do_restorecon_recursive}}}, {"rm", {1, 1, {true, do_rm}}}, {"rmdir", {1, 1, {true, do_rmdir}}}, // TODO: setprop should be run in the subcontext, but property service needs to be split // out from init before that is possible. {"setprop", {2, 2, {false, do_setprop}}}, {"setprop", {2, 2, {true, do_setprop}}}, {"setrlimit", {3, 3, {false, do_setrlimit}}}, {"start", {1, 1, {false, do_start}}}, {"stop", {1, 1, {false, do_stop}}}, Loading init/property_service.cpp +186 −179 Original line number Diff line number Diff line Loading @@ -84,6 +84,10 @@ static int property_set_fd = -1; static PropertyInfoAreaFile property_info_area; uint32_t InitPropertySet(const std::string& name, const std::string& value); uint32_t (*property_set)(const std::string& name, const std::string& value) = InitPropertySet; void CreateSerializedPropertyInfo(); void property_init() { Loading @@ -97,7 +101,7 @@ void property_init() { } } static bool CheckMacPerms(const std::string& name, const char* target_context, const char* source_context, struct ucred* cr) { const char* source_context, const ucred& cr) { if (!target_context || !source_context) { return false; } Loading @@ -105,7 +109,7 @@ static bool CheckMacPerms(const std::string& name, const char* target_context, property_audit_data audit_data; audit_data.name = name.c_str(); audit_data.cr = cr; audit_data.cr = &cr; bool has_access = (selinux_check_access(source_context, target_context, "property_service", "set", &audit_data) == 0); Loading Loading @@ -257,7 +261,7 @@ static int RestoreconRecursiveAsync(const std::string& name, const std::string& return selinux_android_restorecon(value.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE); } uint32_t property_set(const std::string& name, const std::string& value) { uint32_t PropertySet(const std::string& name, const std::string& value) { if (name == "selinux.restorecon_recursive") { return PropertySetAsync(name, value, RestoreconRecursiveAsync); } Loading @@ -265,14 +269,29 @@ uint32_t property_set(const std::string& name, const std::string& value) { return PropertySetImpl(name, value); } uint32_t InitPropertySet(const std::string& name, const std::string& value) { if (StartsWith(name, "ctl.")) { LOG(ERROR) << "Do not set ctl. properties from init; call the Service functions directly"; return PROP_ERROR_INVALID_NAME; } const char* type = nullptr; property_info_area->GetPropertyInfo(name.c_str(), nullptr, &type); if (type == nullptr || !CheckType(type, value)) { LOG(ERROR) << "property_set: name: '" << name << "' type check failed, type: '" << (type ?: "(null)") << "' value: '" << value << "'"; return PROP_ERROR_INVALID_VALUE; } return PropertySet(name, value); } class SocketConnection { public: SocketConnection(int socket, const struct ucred& cred) : socket_(socket), cred_(cred) {} SocketConnection(int socket, const ucred& cred) : socket_(socket), cred_(cred) {} ~SocketConnection() { close(socket_); } ~SocketConnection() { close(socket_); } bool RecvUint32(uint32_t* value, uint32_t* timeout_ms) { return RecvFully(value, sizeof(*value), timeout_ms); Loading Loading @@ -314,12 +333,16 @@ class SocketConnection { return result == sizeof(value); } int socket() { return socket_; } int socket() { return socket_; } const struct ucred& cred() { return cred_; const ucred& cred() { return cred_; } std::string source_context() const { char* source_context = nullptr; getpeercon(socket_, &source_context); std::string result = source_context; freecon(source_context); return result; } private: Loading @@ -332,7 +355,8 @@ class SocketConnection { auto start_time = std::chrono::steady_clock::now(); int nr = poll(ufds, 1, *timeout_ms); auto now = std::chrono::steady_clock::now(); auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time); auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time); uint64_t millis = time_elapsed.count(); *timeout_ms = (millis > *timeout_ms) ? 0 : *timeout_ms - millis; Loading @@ -346,7 +370,8 @@ class SocketConnection { } if (nr < 0 && errno != EINTR) { PLOG(ERROR) << "sys_prop: error waiting for uid " << cred_.uid << " to send property message"; PLOG(ERROR) << "sys_prop: error waiting for uid " << cred_.uid << " to send property message"; return false; } else { // errno == EINTR // Timer rounds milliseconds down in case of EINTR we want it to be rounded up Loading @@ -357,7 +382,8 @@ class SocketConnection { } } LOG(ERROR) << "sys_prop: timeout waiting for uid " << cred_.uid << " to send property message."; LOG(ERROR) << "sys_prop: timeout waiting for uid " << cred_.uid << " to send property message."; return false; } Loading @@ -382,70 +408,53 @@ class SocketConnection { } int socket_; struct ucred cred_; ucred cred_; DISALLOW_IMPLICIT_CONSTRUCTORS(SocketConnection); }; static void handle_property_set(SocketConnection& socket, const std::string& name, const std::string& value, bool legacy_protocol) { const char* cmd_name = legacy_protocol ? "PROP_MSG_SETPROP" : "PROP_MSG_SETPROP2"; // This returns one of the enum of PROP_SUCCESS or PROP_ERROR*. uint32_t HandlePropertySet(const std::string& name, const std::string& value, const std::string& source_context, const ucred& cr) { if (!is_legal_property_name(name)) { LOG(ERROR) << "sys_prop(" << cmd_name << "): illegal property name \"" << name << "\""; socket.SendUint32(PROP_ERROR_INVALID_NAME); return; LOG(ERROR) << "PropertySet: illegal property name \"" << name << "\""; return PROP_ERROR_INVALID_NAME; } struct ucred cr = socket.cred(); char* source_ctx = nullptr; getpeercon(socket.socket(), &source_ctx); std::string source_context = source_ctx; freecon(source_ctx); if (StartsWith(name, "ctl.")) { // ctl. properties have their name ctl.<action> and their value is the name of the service to // apply that action to. Permissions for these actions are based on the service, so we must // create a fake name of ctl.<service> to check permissions. // ctl. properties have their name ctl.<action> and their value is the name of the service // to apply that action to. Permissions for these actions are based on the service, so we // must create a fake name of ctl.<service> to check permissions. auto control_string = "ctl." + value; const char* target_context = nullptr; const char* type = nullptr; property_info_area->GetPropertyInfo(control_string.c_str(), &target_context, &type); if (!CheckMacPerms(control_string, target_context, source_context.c_str(), &cr)) { LOG(ERROR) << "sys_prop(" << cmd_name << "): Unable to " << (name.c_str() + 4) << " service ctl [" << value << "]" if (!CheckMacPerms(control_string, target_context, source_context.c_str(), cr)) { LOG(ERROR) << "PropertySet: Unable to " << (name.c_str() + 4) << " service ctl [" << value << "]" << " uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid; if (!legacy_protocol) { socket.SendUint32(PROP_ERROR_HANDLE_CONTROL_MESSAGE); } return; return PROP_ERROR_HANDLE_CONTROL_MESSAGE; } handle_control_message(name.c_str() + 4, value.c_str()); if (!legacy_protocol) { socket.SendUint32(PROP_SUCCESS); return PROP_SUCCESS; } } else { const char* target_context = nullptr; const char* type = nullptr; property_info_area->GetPropertyInfo(name.c_str(), &target_context, &type); if (!CheckMacPerms(name, target_context, source_context.c_str(), &cr)) { LOG(ERROR) << "sys_prop(" << cmd_name << "): permission denied uid:" << cr.uid << " name:" << name; if (!legacy_protocol) { socket.SendUint32(PROP_ERROR_PERMISSION_DENIED); } return; if (!CheckMacPerms(name, target_context, source_context.c_str(), cr)) { LOG(ERROR) << "PropertySet: permission denied uid:" << cr.uid << " name:" << name; return PROP_ERROR_PERMISSION_DENIED; } if (type == nullptr || !CheckType(type, value)) { LOG(ERROR) << "sys_prop(" << cmd_name << "): type check failed, type: '" LOG(ERROR) << "PropertySet: name: '" << name << "' type check failed, type: '" << (type ?: "(null)") << "' value: '" << value << "'"; if (!legacy_protocol) { socket.SendUint32(PROP_ERROR_INVALID_VALUE); } return; return PROP_ERROR_INVALID_VALUE; } // sys.powerctl is a special property that is used to make the device reboot. We want to log // any process that sets this property to be able to accurately blame the cause of a shutdown. if (name == "sys.powerctl") { Loading @@ -453,18 +462,15 @@ static void handle_property_set(SocketConnection& socket, std::string process_cmdline; std::string process_log_string; if (ReadFileToString(cmdline_path, &process_cmdline)) { // Since cmdline is null deliminated, .c_str() conveniently gives us just the process path. // Since cmdline is null deliminated, .c_str() conveniently gives us just the process // path. process_log_string = StringPrintf(" (%s)", process_cmdline.c_str()); } LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid << process_log_string; } uint32_t result = property_set(name, value); if (!legacy_protocol) { socket.SendUint32(result); } } return PropertySet(name, value); } static void handle_property_set_fd() { Loading @@ -475,7 +481,7 @@ static void handle_property_set_fd() { return; } struct ucred cr; ucred cr; socklen_t cr_size = sizeof(cr); if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) { close(s); Loading Loading @@ -507,7 +513,7 @@ static void handle_property_set_fd() { prop_name[PROP_NAME_MAX-1] = 0; prop_value[PROP_VALUE_MAX-1] = 0; handle_property_set(socket, prop_value, prop_value, true); HandlePropertySet(prop_value, prop_value, socket.source_context(), socket.cred()); break; } Loading @@ -521,7 +527,8 @@ static void handle_property_set_fd() { return; } handle_property_set(socket, name, value, false); auto result = HandlePropertySet(name, value, socket.source_context(), socket.cred()); socket.SendUint32(result); break; } Loading init/property_service.h +6 −2 Original line number Diff line number Diff line Loading @@ -25,10 +25,15 @@ namespace android { namespace init { struct property_audit_data { ucred *cr; const ucred* cr; const char* 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); extern bool PropertyChildReap(pid_t pid); void property_init(void); Loading @@ -36,7 +41,6 @@ void property_load_boot_defaults(void); void load_persist_props(void); void load_system_props(void); void start_property_service(void); uint32_t property_set(const std::string& name, const std::string& value); bool is_legal_property_name(const std::string& name); } // namespace init Loading init/subcontext.cpp +37 −4 Original line number Diff line number Diff line Loading @@ -27,9 +27,13 @@ #include <selinux/android.h> #include "action.h" #include "property_service.h" #include "selinux.h" #include "util.h" #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ #include <sys/_system_properties.h> using android::base::GetExecutablePath; using android::base::Join; using android::base::Socketpair; Loading Loading @@ -75,6 +79,13 @@ Result<Success> SendMessage(int socket, const T& message) { return Success(); } std::vector<std::pair<std::string, std::string>> properties_to_set; uint32_t SubcontextPropertySet(const std::string& name, const std::string& value) { properties_to_set.emplace_back(name, value); return PROP_SUCCESS; } class SubcontextProcess { public: SubcontextProcess(const KeywordFunctionMap* function_map, std::string context, int init_fd) Loading Loading @@ -108,6 +119,14 @@ void SubcontextProcess::RunCommand(const SubcontextCommand::ExecuteCommand& exec result = RunBuiltinFunction(map_result->second, 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 { Loading Loading @@ -186,6 +205,9 @@ int SubcontextMain(int argc, char** argv, const KeywordFunctionMap* function_map auto init_fd = std::atoi(argv[3]); SelabelInitialize(); property_set = SubcontextPropertySet; auto subcontext_process = SubcontextProcess(function_map, context, init_fd); subcontext_process.MainLoop(); return 0; Loading Loading @@ -257,10 +279,6 @@ Result<SubcontextReply> Subcontext::TransmitMessage(const SubcontextCommand& sub Restart(); return Error() << "Unable to parse message from subcontext"; } if (subcontext_reply.reply_case() == SubcontextReply::kFailure) { auto& failure = subcontext_reply.failure(); return ResultError(failure.error_string(), failure.error_errno()); } return subcontext_reply; } Loading @@ -275,6 +293,16 @@ Result<Success> Subcontext::Execute(const std::vector<std::string>& args) { return subcontext_reply.error(); } for (const auto& property : subcontext_reply->properties_to_set()) { ucred cr = {.pid = pid_, .uid = 0, .gid = 0}; HandlePropertySet(property.name(), property.value(), context_, cr); } if (subcontext_reply->reply_case() == SubcontextReply::kFailure) { auto& failure = subcontext_reply->failure(); return ResultError(failure.error_string(), failure.error_errno()); } if (subcontext_reply->reply_case() != SubcontextReply::kSuccess) { return Error() << "Unexpected message type from subcontext: " << subcontext_reply->reply_case(); Loading @@ -294,6 +322,11 @@ Result<std::vector<std::string>> Subcontext::ExpandArgs(const std::vector<std::s return subcontext_reply.error(); } if (subcontext_reply->reply_case() == SubcontextReply::kFailure) { auto& failure = subcontext_reply->failure(); return ResultError(failure.error_string(), failure.error_errno()); } if (subcontext_reply->reply_case() != SubcontextReply::kExpandArgsReply) { return Error() << "Unexpected message type from subcontext: " << subcontext_reply->reply_case(); Loading init/subcontext.proto +6 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
init/builtins.cpp +1 −3 Original line number Diff line number Diff line Loading @@ -1039,9 +1039,7 @@ const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const { {"restorecon_recursive", {1, kMax, {true, do_restorecon_recursive}}}, {"rm", {1, 1, {true, do_rm}}}, {"rmdir", {1, 1, {true, do_rmdir}}}, // TODO: setprop should be run in the subcontext, but property service needs to be split // out from init before that is possible. {"setprop", {2, 2, {false, do_setprop}}}, {"setprop", {2, 2, {true, do_setprop}}}, {"setrlimit", {3, 3, {false, do_setrlimit}}}, {"start", {1, 1, {false, do_start}}}, {"stop", {1, 1, {false, do_stop}}}, Loading
init/property_service.cpp +186 −179 Original line number Diff line number Diff line Loading @@ -84,6 +84,10 @@ static int property_set_fd = -1; static PropertyInfoAreaFile property_info_area; uint32_t InitPropertySet(const std::string& name, const std::string& value); uint32_t (*property_set)(const std::string& name, const std::string& value) = InitPropertySet; void CreateSerializedPropertyInfo(); void property_init() { Loading @@ -97,7 +101,7 @@ void property_init() { } } static bool CheckMacPerms(const std::string& name, const char* target_context, const char* source_context, struct ucred* cr) { const char* source_context, const ucred& cr) { if (!target_context || !source_context) { return false; } Loading @@ -105,7 +109,7 @@ static bool CheckMacPerms(const std::string& name, const char* target_context, property_audit_data audit_data; audit_data.name = name.c_str(); audit_data.cr = cr; audit_data.cr = &cr; bool has_access = (selinux_check_access(source_context, target_context, "property_service", "set", &audit_data) == 0); Loading Loading @@ -257,7 +261,7 @@ static int RestoreconRecursiveAsync(const std::string& name, const std::string& return selinux_android_restorecon(value.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE); } uint32_t property_set(const std::string& name, const std::string& value) { uint32_t PropertySet(const std::string& name, const std::string& value) { if (name == "selinux.restorecon_recursive") { return PropertySetAsync(name, value, RestoreconRecursiveAsync); } Loading @@ -265,14 +269,29 @@ uint32_t property_set(const std::string& name, const std::string& value) { return PropertySetImpl(name, value); } uint32_t InitPropertySet(const std::string& name, const std::string& value) { if (StartsWith(name, "ctl.")) { LOG(ERROR) << "Do not set ctl. properties from init; call the Service functions directly"; return PROP_ERROR_INVALID_NAME; } const char* type = nullptr; property_info_area->GetPropertyInfo(name.c_str(), nullptr, &type); if (type == nullptr || !CheckType(type, value)) { LOG(ERROR) << "property_set: name: '" << name << "' type check failed, type: '" << (type ?: "(null)") << "' value: '" << value << "'"; return PROP_ERROR_INVALID_VALUE; } return PropertySet(name, value); } class SocketConnection { public: SocketConnection(int socket, const struct ucred& cred) : socket_(socket), cred_(cred) {} SocketConnection(int socket, const ucred& cred) : socket_(socket), cred_(cred) {} ~SocketConnection() { close(socket_); } ~SocketConnection() { close(socket_); } bool RecvUint32(uint32_t* value, uint32_t* timeout_ms) { return RecvFully(value, sizeof(*value), timeout_ms); Loading Loading @@ -314,12 +333,16 @@ class SocketConnection { return result == sizeof(value); } int socket() { return socket_; } int socket() { return socket_; } const struct ucred& cred() { return cred_; const ucred& cred() { return cred_; } std::string source_context() const { char* source_context = nullptr; getpeercon(socket_, &source_context); std::string result = source_context; freecon(source_context); return result; } private: Loading @@ -332,7 +355,8 @@ class SocketConnection { auto start_time = std::chrono::steady_clock::now(); int nr = poll(ufds, 1, *timeout_ms); auto now = std::chrono::steady_clock::now(); auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time); auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time); uint64_t millis = time_elapsed.count(); *timeout_ms = (millis > *timeout_ms) ? 0 : *timeout_ms - millis; Loading @@ -346,7 +370,8 @@ class SocketConnection { } if (nr < 0 && errno != EINTR) { PLOG(ERROR) << "sys_prop: error waiting for uid " << cred_.uid << " to send property message"; PLOG(ERROR) << "sys_prop: error waiting for uid " << cred_.uid << " to send property message"; return false; } else { // errno == EINTR // Timer rounds milliseconds down in case of EINTR we want it to be rounded up Loading @@ -357,7 +382,8 @@ class SocketConnection { } } LOG(ERROR) << "sys_prop: timeout waiting for uid " << cred_.uid << " to send property message."; LOG(ERROR) << "sys_prop: timeout waiting for uid " << cred_.uid << " to send property message."; return false; } Loading @@ -382,70 +408,53 @@ class SocketConnection { } int socket_; struct ucred cred_; ucred cred_; DISALLOW_IMPLICIT_CONSTRUCTORS(SocketConnection); }; static void handle_property_set(SocketConnection& socket, const std::string& name, const std::string& value, bool legacy_protocol) { const char* cmd_name = legacy_protocol ? "PROP_MSG_SETPROP" : "PROP_MSG_SETPROP2"; // This returns one of the enum of PROP_SUCCESS or PROP_ERROR*. uint32_t HandlePropertySet(const std::string& name, const std::string& value, const std::string& source_context, const ucred& cr) { if (!is_legal_property_name(name)) { LOG(ERROR) << "sys_prop(" << cmd_name << "): illegal property name \"" << name << "\""; socket.SendUint32(PROP_ERROR_INVALID_NAME); return; LOG(ERROR) << "PropertySet: illegal property name \"" << name << "\""; return PROP_ERROR_INVALID_NAME; } struct ucred cr = socket.cred(); char* source_ctx = nullptr; getpeercon(socket.socket(), &source_ctx); std::string source_context = source_ctx; freecon(source_ctx); if (StartsWith(name, "ctl.")) { // ctl. properties have their name ctl.<action> and their value is the name of the service to // apply that action to. Permissions for these actions are based on the service, so we must // create a fake name of ctl.<service> to check permissions. // ctl. properties have their name ctl.<action> and their value is the name of the service // to apply that action to. Permissions for these actions are based on the service, so we // must create a fake name of ctl.<service> to check permissions. auto control_string = "ctl." + value; const char* target_context = nullptr; const char* type = nullptr; property_info_area->GetPropertyInfo(control_string.c_str(), &target_context, &type); if (!CheckMacPerms(control_string, target_context, source_context.c_str(), &cr)) { LOG(ERROR) << "sys_prop(" << cmd_name << "): Unable to " << (name.c_str() + 4) << " service ctl [" << value << "]" if (!CheckMacPerms(control_string, target_context, source_context.c_str(), cr)) { LOG(ERROR) << "PropertySet: Unable to " << (name.c_str() + 4) << " service ctl [" << value << "]" << " uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid; if (!legacy_protocol) { socket.SendUint32(PROP_ERROR_HANDLE_CONTROL_MESSAGE); } return; return PROP_ERROR_HANDLE_CONTROL_MESSAGE; } handle_control_message(name.c_str() + 4, value.c_str()); if (!legacy_protocol) { socket.SendUint32(PROP_SUCCESS); return PROP_SUCCESS; } } else { const char* target_context = nullptr; const char* type = nullptr; property_info_area->GetPropertyInfo(name.c_str(), &target_context, &type); if (!CheckMacPerms(name, target_context, source_context.c_str(), &cr)) { LOG(ERROR) << "sys_prop(" << cmd_name << "): permission denied uid:" << cr.uid << " name:" << name; if (!legacy_protocol) { socket.SendUint32(PROP_ERROR_PERMISSION_DENIED); } return; if (!CheckMacPerms(name, target_context, source_context.c_str(), cr)) { LOG(ERROR) << "PropertySet: permission denied uid:" << cr.uid << " name:" << name; return PROP_ERROR_PERMISSION_DENIED; } if (type == nullptr || !CheckType(type, value)) { LOG(ERROR) << "sys_prop(" << cmd_name << "): type check failed, type: '" LOG(ERROR) << "PropertySet: name: '" << name << "' type check failed, type: '" << (type ?: "(null)") << "' value: '" << value << "'"; if (!legacy_protocol) { socket.SendUint32(PROP_ERROR_INVALID_VALUE); } return; return PROP_ERROR_INVALID_VALUE; } // sys.powerctl is a special property that is used to make the device reboot. We want to log // any process that sets this property to be able to accurately blame the cause of a shutdown. if (name == "sys.powerctl") { Loading @@ -453,18 +462,15 @@ static void handle_property_set(SocketConnection& socket, std::string process_cmdline; std::string process_log_string; if (ReadFileToString(cmdline_path, &process_cmdline)) { // Since cmdline is null deliminated, .c_str() conveniently gives us just the process path. // Since cmdline is null deliminated, .c_str() conveniently gives us just the process // path. process_log_string = StringPrintf(" (%s)", process_cmdline.c_str()); } LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid << process_log_string; } uint32_t result = property_set(name, value); if (!legacy_protocol) { socket.SendUint32(result); } } return PropertySet(name, value); } static void handle_property_set_fd() { Loading @@ -475,7 +481,7 @@ static void handle_property_set_fd() { return; } struct ucred cr; ucred cr; socklen_t cr_size = sizeof(cr); if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) { close(s); Loading Loading @@ -507,7 +513,7 @@ static void handle_property_set_fd() { prop_name[PROP_NAME_MAX-1] = 0; prop_value[PROP_VALUE_MAX-1] = 0; handle_property_set(socket, prop_value, prop_value, true); HandlePropertySet(prop_value, prop_value, socket.source_context(), socket.cred()); break; } Loading @@ -521,7 +527,8 @@ static void handle_property_set_fd() { return; } handle_property_set(socket, name, value, false); auto result = HandlePropertySet(name, value, socket.source_context(), socket.cred()); socket.SendUint32(result); break; } Loading
init/property_service.h +6 −2 Original line number Diff line number Diff line Loading @@ -25,10 +25,15 @@ namespace android { namespace init { struct property_audit_data { ucred *cr; const ucred* cr; const char* 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); extern bool PropertyChildReap(pid_t pid); void property_init(void); Loading @@ -36,7 +41,6 @@ void property_load_boot_defaults(void); void load_persist_props(void); void load_system_props(void); void start_property_service(void); uint32_t property_set(const std::string& name, const std::string& value); bool is_legal_property_name(const std::string& name); } // namespace init Loading
init/subcontext.cpp +37 −4 Original line number Diff line number Diff line Loading @@ -27,9 +27,13 @@ #include <selinux/android.h> #include "action.h" #include "property_service.h" #include "selinux.h" #include "util.h" #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ #include <sys/_system_properties.h> using android::base::GetExecutablePath; using android::base::Join; using android::base::Socketpair; Loading Loading @@ -75,6 +79,13 @@ Result<Success> SendMessage(int socket, const T& message) { return Success(); } std::vector<std::pair<std::string, std::string>> properties_to_set; uint32_t SubcontextPropertySet(const std::string& name, const std::string& value) { properties_to_set.emplace_back(name, value); return PROP_SUCCESS; } class SubcontextProcess { public: SubcontextProcess(const KeywordFunctionMap* function_map, std::string context, int init_fd) Loading Loading @@ -108,6 +119,14 @@ void SubcontextProcess::RunCommand(const SubcontextCommand::ExecuteCommand& exec result = RunBuiltinFunction(map_result->second, 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 { Loading Loading @@ -186,6 +205,9 @@ int SubcontextMain(int argc, char** argv, const KeywordFunctionMap* function_map auto init_fd = std::atoi(argv[3]); SelabelInitialize(); property_set = SubcontextPropertySet; auto subcontext_process = SubcontextProcess(function_map, context, init_fd); subcontext_process.MainLoop(); return 0; Loading Loading @@ -257,10 +279,6 @@ Result<SubcontextReply> Subcontext::TransmitMessage(const SubcontextCommand& sub Restart(); return Error() << "Unable to parse message from subcontext"; } if (subcontext_reply.reply_case() == SubcontextReply::kFailure) { auto& failure = subcontext_reply.failure(); return ResultError(failure.error_string(), failure.error_errno()); } return subcontext_reply; } Loading @@ -275,6 +293,16 @@ Result<Success> Subcontext::Execute(const std::vector<std::string>& args) { return subcontext_reply.error(); } for (const auto& property : subcontext_reply->properties_to_set()) { ucred cr = {.pid = pid_, .uid = 0, .gid = 0}; HandlePropertySet(property.name(), property.value(), context_, cr); } if (subcontext_reply->reply_case() == SubcontextReply::kFailure) { auto& failure = subcontext_reply->failure(); return ResultError(failure.error_string(), failure.error_errno()); } if (subcontext_reply->reply_case() != SubcontextReply::kSuccess) { return Error() << "Unexpected message type from subcontext: " << subcontext_reply->reply_case(); Loading @@ -294,6 +322,11 @@ Result<std::vector<std::string>> Subcontext::ExpandArgs(const std::vector<std::s return subcontext_reply.error(); } if (subcontext_reply->reply_case() == SubcontextReply::kFailure) { auto& failure = subcontext_reply->failure(); return ResultError(failure.error_string(), failure.error_errno()); } if (subcontext_reply->reply_case() != SubcontextReply::kExpandArgsReply) { return Error() << "Unexpected message type from subcontext: " << subcontext_reply->reply_case(); Loading
init/subcontext.proto +6 −0 Original line number Diff line number Diff line Loading @@ -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