blob: bde0c1002fb7a628ccc6b46046bbbb130bc085af [file] [log] [blame]
Tom Cherrye275d6d2017-12-11 23:31:33 -08001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <errno.h>
30#include <poll.h>
31#include <stdatomic.h>
32#include <stddef.h>
33#include <stdint.h>
34#include <stdlib.h>
35#include <string.h>
36#include <sys/socket.h>
37#include <sys/types.h>
38#include <sys/uio.h>
39#include <sys/un.h>
40#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
41#include <sys/_system_properties.h>
42#include <unistd.h>
43
Chienyuan Huangf2b4a972020-08-20 08:42:31 +000044#include <async_safe/log.h>
Bowgo Tsai61a5a832021-07-15 10:13:33 +000045#include <async_safe/CHECK.h>
Tom Cherrye275d6d2017-12-11 23:31:33 -080046
Bowgo Tsai61a5a832021-07-15 10:13:33 +000047#include "private/bionic_defs.h"
Josh Gao4956c372019-12-19 16:35:51 -080048#include "platform/bionic/macros.h"
Elliott Hughes6cb70ad2019-10-31 15:37:32 -070049#include "private/ScopedFd.h"
Tom Cherrye275d6d2017-12-11 23:31:33 -080050
51static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME;
Paul Lawrence24839a62023-01-20 15:10:35 -080052static const char property_service_for_system_socket[] =
53 "/dev/socket/" PROP_SERVICE_FOR_SYSTEM_NAME;
Tom Cherrye275d6d2017-12-11 23:31:33 -080054static const char* kServiceVersionPropertyName = "ro.property_service.version";
55
56class PropertyServiceConnection {
57 public:
Paul Lawrenced1076eb2023-07-11 09:06:15 -070058 PropertyServiceConnection() : last_error_(0) {
Elliott Hughes6cb70ad2019-10-31 15:37:32 -070059 socket_.reset(::socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0));
60 if (socket_.get() == -1) {
Tom Cherrye275d6d2017-12-11 23:31:33 -080061 last_error_ = errno;
62 return;
63 }
64
Paul Lawrenced1076eb2023-07-11 09:06:15 -070065 const char* socket = access(property_service_for_system_socket, W_OK) == 0
66 ? property_service_for_system_socket
67 : property_service_socket;
Paul Lawrence24839a62023-01-20 15:10:35 -080068 const size_t namelen = strlen(socket);
Tom Cherrye275d6d2017-12-11 23:31:33 -080069 sockaddr_un addr;
70 memset(&addr, 0, sizeof(addr));
Paul Lawrence24839a62023-01-20 15:10:35 -080071 strlcpy(addr.sun_path, socket, sizeof(addr.sun_path));
Tom Cherrye275d6d2017-12-11 23:31:33 -080072 addr.sun_family = AF_LOCAL;
73 socklen_t alen = namelen + offsetof(sockaddr_un, sun_path) + 1;
74
Elliott Hughes6cb70ad2019-10-31 15:37:32 -070075 if (TEMP_FAILURE_RETRY(connect(socket_.get(),
76 reinterpret_cast<sockaddr*>(&addr), alen)) == -1) {
Tom Cherrye275d6d2017-12-11 23:31:33 -080077 last_error_ = errno;
Elliott Hughes6cb70ad2019-10-31 15:37:32 -070078 socket_.reset();
Tom Cherrye275d6d2017-12-11 23:31:33 -080079 }
80 }
81
82 bool IsValid() {
Elliott Hughes6cb70ad2019-10-31 15:37:32 -070083 return socket_.get() != -1;
Tom Cherrye275d6d2017-12-11 23:31:33 -080084 }
85
86 int GetLastError() {
87 return last_error_;
88 }
89
90 bool RecvInt32(int32_t* value) {
Elliott Hughes6cb70ad2019-10-31 15:37:32 -070091 int result = TEMP_FAILURE_RETRY(recv(socket_.get(), value, sizeof(*value), MSG_WAITALL));
Tom Cherrye275d6d2017-12-11 23:31:33 -080092 return CheckSendRecvResult(result, sizeof(*value));
93 }
94
95 int socket() {
Elliott Hughes6cb70ad2019-10-31 15:37:32 -070096 return socket_.get();
Tom Cherrye275d6d2017-12-11 23:31:33 -080097 }
98
99 private:
100 bool CheckSendRecvResult(int result, int expected_len) {
101 if (result == -1) {
102 last_error_ = errno;
103 } else if (result != expected_len) {
104 last_error_ = -1;
105 } else {
106 last_error_ = 0;
107 }
108
109 return last_error_ == 0;
110 }
111
Elliott Hughes6cb70ad2019-10-31 15:37:32 -0700112 ScopedFd socket_;
Tom Cherrye275d6d2017-12-11 23:31:33 -0800113 int last_error_;
114
115 friend class SocketWriter;
116};
117
118class SocketWriter {
119 public:
120 explicit SocketWriter(PropertyServiceConnection* connection)
121 : connection_(connection), iov_index_(0), uint_buf_index_(0) {
122 }
123
124 SocketWriter& WriteUint32(uint32_t value) {
125 CHECK(uint_buf_index_ < kUintBufSize);
126 CHECK(iov_index_ < kIovSize);
127 uint32_t* ptr = uint_buf_ + uint_buf_index_;
128 uint_buf_[uint_buf_index_++] = value;
129 iov_[iov_index_].iov_base = ptr;
130 iov_[iov_index_].iov_len = sizeof(*ptr);
131 ++iov_index_;
132 return *this;
133 }
134
135 SocketWriter& WriteString(const char* value) {
136 uint32_t valuelen = strlen(value);
137 WriteUint32(valuelen);
138 if (valuelen == 0) {
139 return *this;
140 }
141
142 CHECK(iov_index_ < kIovSize);
143 iov_[iov_index_].iov_base = const_cast<char*>(value);
144 iov_[iov_index_].iov_len = valuelen;
145 ++iov_index_;
146
147 return *this;
148 }
149
150 bool Send() {
151 if (!connection_->IsValid()) {
152 return false;
153 }
154
155 if (writev(connection_->socket(), iov_, iov_index_) == -1) {
156 connection_->last_error_ = errno;
157 return false;
158 }
159
160 iov_index_ = uint_buf_index_ = 0;
161 return true;
162 }
163
164 private:
165 static constexpr size_t kUintBufSize = 8;
166 static constexpr size_t kIovSize = 8;
167
168 PropertyServiceConnection* connection_;
169 iovec iov_[kIovSize];
170 size_t iov_index_;
171 uint32_t uint_buf_[kUintBufSize];
172 size_t uint_buf_index_;
173
Elliott Hughes5e62b342018-10-25 11:00:00 -0700174 BIONIC_DISALLOW_IMPLICIT_CONSTRUCTORS(SocketWriter);
Tom Cherrye275d6d2017-12-11 23:31:33 -0800175};
176
177struct prop_msg {
178 unsigned cmd;
179 char name[PROP_NAME_MAX];
180 char value[PROP_VALUE_MAX];
181};
182
183static int send_prop_msg(const prop_msg* msg) {
Paul Lawrenced1076eb2023-07-11 09:06:15 -0700184 PropertyServiceConnection connection;
Tom Cherrye275d6d2017-12-11 23:31:33 -0800185 if (!connection.IsValid()) {
186 return connection.GetLastError();
187 }
188
189 int result = -1;
190 int s = connection.socket();
191
192 const int num_bytes = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg), 0));
193 if (num_bytes == sizeof(prop_msg)) {
194 // We successfully wrote to the property server but now we
195 // wait for the property server to finish its work. It
196 // acknowledges its completion by closing the socket so we
197 // poll here (on nothing), waiting for the socket to close.
198 // If you 'adb shell setprop foo bar' you'll see the POLLHUP
199 // once the socket closes. Out of paranoia we cap our poll
200 // at 250 ms.
201 pollfd pollfds[1];
202 pollfds[0].fd = s;
203 pollfds[0].events = 0;
204 const int poll_result = TEMP_FAILURE_RETRY(poll(pollfds, 1, 250 /* ms */));
205 if (poll_result == 1 && (pollfds[0].revents & POLLHUP) != 0) {
206 result = 0;
207 } else {
208 // Ignore the timeout and treat it like a success anyway.
209 // The init process is single-threaded and its property
210 // service is sometimes slow to respond (perhaps it's off
211 // starting a child process or something) and thus this
212 // times out and the caller thinks it failed, even though
213 // it's still getting around to it. So we fake it here,
214 // mostly for ctl.* properties, but we do try and wait 250
215 // ms so callers who do read-after-write can reliably see
216 // what they've written. Most of the time.
Tom Cherrye275d6d2017-12-11 23:31:33 -0800217 async_safe_format_log(ANDROID_LOG_WARN, "libc",
218 "Property service has timed out while trying to set \"%s\" to \"%s\"",
219 msg->name, msg->value);
220 result = 0;
221 }
222 }
223
224 return result;
225}
226
227static constexpr uint32_t kProtocolVersion1 = 1;
228static constexpr uint32_t kProtocolVersion2 = 2; // current
229
230static atomic_uint_least32_t g_propservice_protocol_version = 0;
231
232static void detect_protocol_version() {
233 char value[PROP_VALUE_MAX];
234 if (__system_property_get(kServiceVersionPropertyName, value) == 0) {
235 g_propservice_protocol_version = kProtocolVersion1;
236 async_safe_format_log(ANDROID_LOG_WARN, "libc",
237 "Using old property service protocol (\"%s\" is not set)",
238 kServiceVersionPropertyName);
239 } else {
240 uint32_t version = static_cast<uint32_t>(atoll(value));
241 if (version >= kProtocolVersion2) {
242 g_propservice_protocol_version = kProtocolVersion2;
243 } else {
244 async_safe_format_log(ANDROID_LOG_WARN, "libc",
245 "Using old property service protocol (\"%s\"=\"%s\")",
246 kServiceVersionPropertyName, value);
247 g_propservice_protocol_version = kProtocolVersion1;
248 }
249 }
250}
251
252__BIONIC_WEAK_FOR_NATIVE_BRIDGE
253int __system_property_set(const char* key, const char* value) {
254 if (key == nullptr) return -1;
255 if (value == nullptr) value = "";
256
Tom Cherrye275d6d2017-12-11 23:31:33 -0800257 if (g_propservice_protocol_version == 0) {
258 detect_protocol_version();
259 }
260
261 if (g_propservice_protocol_version == kProtocolVersion1) {
262 // Old protocol does not support long names or values
263 if (strlen(key) >= PROP_NAME_MAX) return -1;
264 if (strlen(value) >= PROP_VALUE_MAX) return -1;
265
266 prop_msg msg;
267 memset(&msg, 0, sizeof msg);
268 msg.cmd = PROP_MSG_SETPROP;
269 strlcpy(msg.name, key, sizeof msg.name);
270 strlcpy(msg.value, value, sizeof msg.value);
271
272 return send_prop_msg(&msg);
273 } else {
274 // New protocol only allows long values for ro. properties only.
275 if (strlen(value) >= PROP_VALUE_MAX && strncmp(key, "ro.", 3) != 0) return -1;
276 // Use proper protocol
Paul Lawrenced1076eb2023-07-11 09:06:15 -0700277 PropertyServiceConnection connection;
Tom Cherrye275d6d2017-12-11 23:31:33 -0800278 if (!connection.IsValid()) {
279 errno = connection.GetLastError();
280 async_safe_format_log(
281 ANDROID_LOG_WARN, "libc",
282 "Unable to set property \"%s\" to \"%s\": connection failed; errno=%d (%s)", key, value,
283 errno, strerror(errno));
284 return -1;
285 }
286
287 SocketWriter writer(&connection);
288 if (!writer.WriteUint32(PROP_MSG_SETPROP2).WriteString(key).WriteString(value).Send()) {
289 errno = connection.GetLastError();
290 async_safe_format_log(ANDROID_LOG_WARN, "libc",
291 "Unable to set property \"%s\" to \"%s\": write failed; errno=%d (%s)",
292 key, value, errno, strerror(errno));
293 return -1;
294 }
295
296 int result = -1;
297 if (!connection.RecvInt32(&result)) {
298 errno = connection.GetLastError();
299 async_safe_format_log(ANDROID_LOG_WARN, "libc",
300 "Unable to set property \"%s\" to \"%s\": recv failed; errno=%d (%s)",
301 key, value, errno, strerror(errno));
302 return -1;
303 }
304
305 if (result != PROP_SUCCESS) {
306 async_safe_format_log(ANDROID_LOG_WARN, "libc",
307 "Unable to set property \"%s\" to \"%s\": error code: 0x%x", key, value,
308 result);
309 return -1;
310 }
311
312 return 0;
313 }
314}