Fix deadlock caused by two-threaded property controls
Two threaded property controls were introduced in ag/21063815 to prevent
DOS for power controls. However, this causes deadlocks, so limit the
second thread to just sys.powerctl messages.
Bug: 273785601
Test: Boots, power messages work
Ignore-AOSP-First: Security fix
Change-Id: I6d2bd566781ed712b41eb711360471fc0d030e54
diff --git a/libc/bionic/system_property_set.cpp b/libc/bionic/system_property_set.cpp
index bde0c10..845ff27 100644
--- a/libc/bionic/system_property_set.cpp
+++ b/libc/bionic/system_property_set.cpp
@@ -55,16 +55,24 @@
class PropertyServiceConnection {
public:
- PropertyServiceConnection() : last_error_(0) {
+ PropertyServiceConnection(const char* name) : last_error_(0) {
socket_.reset(::socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0));
if (socket_.get() == -1) {
last_error_ = errno;
return;
}
- const char* socket = access(property_service_for_system_socket, W_OK) == 0
- ? property_service_for_system_socket
- : property_service_socket;
+ // If we're trying to set "sys.powerctl" from a privileged process, use the special
+ // socket. Because this socket is only accessible to privileged processes, it can't
+ // be DoSed directly by malicious apps. (The shell user should be able to reboot,
+ // though, so we don't just always use the special socket for "sys.powerctl".)
+ // See b/262237198 for context
+ const char* socket = property_service_socket;
+ if (strcmp(name, "sys.powerctl") == 0 &&
+ access(property_service_for_system_socket, W_OK) == 0) {
+ socket = property_service_for_system_socket;
+ }
+
const size_t namelen = strlen(socket);
sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
@@ -181,7 +189,7 @@
};
static int send_prop_msg(const prop_msg* msg) {
- PropertyServiceConnection connection;
+ PropertyServiceConnection connection(msg->name);
if (!connection.IsValid()) {
return connection.GetLastError();
}
@@ -274,7 +282,7 @@
// New protocol only allows long values for ro. properties only.
if (strlen(value) >= PROP_VALUE_MAX && strncmp(key, "ro.", 3) != 0) return -1;
// Use proper protocol
- PropertyServiceConnection connection;
+ PropertyServiceConnection connection(key);
if (!connection.IsValid()) {
errno = connection.GetLastError();
async_safe_format_log(