blob: 6823b6aab2269db6340345a2eb5ca43d9fa110cf [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
Elliott Hughes3019d782019-02-13 12:39:07 -080044#include <async_safe/CHECK.h>
Bowgo Tsai26970c32020-04-13 13:07:43 +080045#include <async_safe/log.h>
46#include <system_properties/prop_trace.h>
Tom Cherrye275d6d2017-12-11 23:31:33 -080047
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"
Bowgo Tsai26970c32020-04-13 13:07:43 +080050#include "private/bionic_defs.h"
Tom Cherrye275d6d2017-12-11 23:31:33 -080051
52static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME;
53static const char* kServiceVersionPropertyName = "ro.property_service.version";
54
55class PropertyServiceConnection {
56 public:
57 PropertyServiceConnection() : last_error_(0) {
Elliott Hughes6cb70ad2019-10-31 15:37:32 -070058 socket_.reset(::socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0));
59 if (socket_.get() == -1) {
Tom Cherrye275d6d2017-12-11 23:31:33 -080060 last_error_ = errno;
61 return;
62 }
63
64 const size_t namelen = strlen(property_service_socket);
65 sockaddr_un addr;
66 memset(&addr, 0, sizeof(addr));
67 strlcpy(addr.sun_path, property_service_socket, sizeof(addr.sun_path));
68 addr.sun_family = AF_LOCAL;
69 socklen_t alen = namelen + offsetof(sockaddr_un, sun_path) + 1;
70
Elliott Hughes6cb70ad2019-10-31 15:37:32 -070071 if (TEMP_FAILURE_RETRY(connect(socket_.get(),
72 reinterpret_cast<sockaddr*>(&addr), alen)) == -1) {
Tom Cherrye275d6d2017-12-11 23:31:33 -080073 last_error_ = errno;
Elliott Hughes6cb70ad2019-10-31 15:37:32 -070074 socket_.reset();
Tom Cherrye275d6d2017-12-11 23:31:33 -080075 }
76 }
77
78 bool IsValid() {
Elliott Hughes6cb70ad2019-10-31 15:37:32 -070079 return socket_.get() != -1;
Tom Cherrye275d6d2017-12-11 23:31:33 -080080 }
81
82 int GetLastError() {
83 return last_error_;
84 }
85
86 bool RecvInt32(int32_t* value) {
Elliott Hughes6cb70ad2019-10-31 15:37:32 -070087 int result = TEMP_FAILURE_RETRY(recv(socket_.get(), value, sizeof(*value), MSG_WAITALL));
Tom Cherrye275d6d2017-12-11 23:31:33 -080088 return CheckSendRecvResult(result, sizeof(*value));
89 }
90
91 int socket() {
Elliott Hughes6cb70ad2019-10-31 15:37:32 -070092 return socket_.get();
Tom Cherrye275d6d2017-12-11 23:31:33 -080093 }
94
95 private:
96 bool CheckSendRecvResult(int result, int expected_len) {
97 if (result == -1) {
98 last_error_ = errno;
99 } else if (result != expected_len) {
100 last_error_ = -1;
101 } else {
102 last_error_ = 0;
103 }
104
105 return last_error_ == 0;
106 }
107
Elliott Hughes6cb70ad2019-10-31 15:37:32 -0700108 ScopedFd socket_;
Tom Cherrye275d6d2017-12-11 23:31:33 -0800109 int last_error_;
110
111 friend class SocketWriter;
112};
113
114class SocketWriter {
115 public:
116 explicit SocketWriter(PropertyServiceConnection* connection)
117 : connection_(connection), iov_index_(0), uint_buf_index_(0) {
118 }
119
120 SocketWriter& WriteUint32(uint32_t value) {
121 CHECK(uint_buf_index_ < kUintBufSize);
122 CHECK(iov_index_ < kIovSize);
123 uint32_t* ptr = uint_buf_ + uint_buf_index_;
124 uint_buf_[uint_buf_index_++] = value;
125 iov_[iov_index_].iov_base = ptr;
126 iov_[iov_index_].iov_len = sizeof(*ptr);
127 ++iov_index_;
128 return *this;
129 }
130
131 SocketWriter& WriteString(const char* value) {
132 uint32_t valuelen = strlen(value);
133 WriteUint32(valuelen);
134 if (valuelen == 0) {
135 return *this;
136 }
137
138 CHECK(iov_index_ < kIovSize);
139 iov_[iov_index_].iov_base = const_cast<char*>(value);
140 iov_[iov_index_].iov_len = valuelen;
141 ++iov_index_;
142
143 return *this;
144 }
145
146 bool Send() {
147 if (!connection_->IsValid()) {
148 return false;
149 }
150
151 if (writev(connection_->socket(), iov_, iov_index_) == -1) {
152 connection_->last_error_ = errno;
153 return false;
154 }
155
156 iov_index_ = uint_buf_index_ = 0;
157 return true;
158 }
159
160 private:
161 static constexpr size_t kUintBufSize = 8;
162 static constexpr size_t kIovSize = 8;
163
164 PropertyServiceConnection* connection_;
165 iovec iov_[kIovSize];
166 size_t iov_index_;
167 uint32_t uint_buf_[kUintBufSize];
168 size_t uint_buf_index_;
169
Elliott Hughes5e62b342018-10-25 11:00:00 -0700170 BIONIC_DISALLOW_IMPLICIT_CONSTRUCTORS(SocketWriter);
Tom Cherrye275d6d2017-12-11 23:31:33 -0800171};
172
173struct prop_msg {
174 unsigned cmd;
175 char name[PROP_NAME_MAX];
176 char value[PROP_VALUE_MAX];
177};
178
179static int send_prop_msg(const prop_msg* msg) {
180 PropertyServiceConnection connection;
181 if (!connection.IsValid()) {
182 return connection.GetLastError();
183 }
184
185 int result = -1;
186 int s = connection.socket();
187
188 const int num_bytes = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg), 0));
189 if (num_bytes == sizeof(prop_msg)) {
190 // We successfully wrote to the property server but now we
191 // wait for the property server to finish its work. It
192 // acknowledges its completion by closing the socket so we
193 // poll here (on nothing), waiting for the socket to close.
194 // If you 'adb shell setprop foo bar' you'll see the POLLHUP
195 // once the socket closes. Out of paranoia we cap our poll
196 // at 250 ms.
197 pollfd pollfds[1];
198 pollfds[0].fd = s;
199 pollfds[0].events = 0;
200 const int poll_result = TEMP_FAILURE_RETRY(poll(pollfds, 1, 250 /* ms */));
201 if (poll_result == 1 && (pollfds[0].revents & POLLHUP) != 0) {
202 result = 0;
203 } else {
204 // Ignore the timeout and treat it like a success anyway.
205 // The init process is single-threaded and its property
206 // service is sometimes slow to respond (perhaps it's off
207 // starting a child process or something) and thus this
208 // times out and the caller thinks it failed, even though
209 // it's still getting around to it. So we fake it here,
210 // mostly for ctl.* properties, but we do try and wait 250
211 // ms so callers who do read-after-write can reliably see
212 // what they've written. Most of the time.
Tom Cherrye275d6d2017-12-11 23:31:33 -0800213 async_safe_format_log(ANDROID_LOG_WARN, "libc",
214 "Property service has timed out while trying to set \"%s\" to \"%s\"",
215 msg->name, msg->value);
216 result = 0;
217 }
218 }
219
220 return result;
221}
222
223static constexpr uint32_t kProtocolVersion1 = 1;
224static constexpr uint32_t kProtocolVersion2 = 2; // current
225
226static atomic_uint_least32_t g_propservice_protocol_version = 0;
227
228static void detect_protocol_version() {
229 char value[PROP_VALUE_MAX];
230 if (__system_property_get(kServiceVersionPropertyName, value) == 0) {
231 g_propservice_protocol_version = kProtocolVersion1;
232 async_safe_format_log(ANDROID_LOG_WARN, "libc",
233 "Using old property service protocol (\"%s\" is not set)",
234 kServiceVersionPropertyName);
235 } else {
236 uint32_t version = static_cast<uint32_t>(atoll(value));
237 if (version >= kProtocolVersion2) {
238 g_propservice_protocol_version = kProtocolVersion2;
239 } else {
240 async_safe_format_log(ANDROID_LOG_WARN, "libc",
241 "Using old property service protocol (\"%s\"=\"%s\")",
242 kServiceVersionPropertyName, value);
243 g_propservice_protocol_version = kProtocolVersion1;
244 }
245 }
246}
247
248__BIONIC_WEAK_FOR_NATIVE_BRIDGE
249int __system_property_set(const char* key, const char* value) {
250 if (key == nullptr) return -1;
251 if (value == nullptr) value = "";
252
Bowgo Tsai26970c32020-04-13 13:07:43 +0800253 SyspropTrace trace(key, value, nullptr /* prop_info */, PropertyAction::kPropertySet);
254
Tom Cherrye275d6d2017-12-11 23:31:33 -0800255 if (g_propservice_protocol_version == 0) {
256 detect_protocol_version();
257 }
258
259 if (g_propservice_protocol_version == kProtocolVersion1) {
260 // Old protocol does not support long names or values
261 if (strlen(key) >= PROP_NAME_MAX) return -1;
262 if (strlen(value) >= PROP_VALUE_MAX) return -1;
263
264 prop_msg msg;
265 memset(&msg, 0, sizeof msg);
266 msg.cmd = PROP_MSG_SETPROP;
267 strlcpy(msg.name, key, sizeof msg.name);
268 strlcpy(msg.value, value, sizeof msg.value);
269
270 return send_prop_msg(&msg);
271 } else {
272 // New protocol only allows long values for ro. properties only.
273 if (strlen(value) >= PROP_VALUE_MAX && strncmp(key, "ro.", 3) != 0) return -1;
274 // Use proper protocol
275 PropertyServiceConnection connection;
276 if (!connection.IsValid()) {
277 errno = connection.GetLastError();
278 async_safe_format_log(
279 ANDROID_LOG_WARN, "libc",
280 "Unable to set property \"%s\" to \"%s\": connection failed; errno=%d (%s)", key, value,
281 errno, strerror(errno));
282 return -1;
283 }
284
285 SocketWriter writer(&connection);
286 if (!writer.WriteUint32(PROP_MSG_SETPROP2).WriteString(key).WriteString(value).Send()) {
287 errno = connection.GetLastError();
288 async_safe_format_log(ANDROID_LOG_WARN, "libc",
289 "Unable to set property \"%s\" to \"%s\": write failed; errno=%d (%s)",
290 key, value, errno, strerror(errno));
291 return -1;
292 }
293
294 int result = -1;
295 if (!connection.RecvInt32(&result)) {
296 errno = connection.GetLastError();
297 async_safe_format_log(ANDROID_LOG_WARN, "libc",
298 "Unable to set property \"%s\" to \"%s\": recv failed; errno=%d (%s)",
299 key, value, errno, strerror(errno));
300 return -1;
301 }
302
303 if (result != PROP_SUCCESS) {
304 async_safe_format_log(ANDROID_LOG_WARN, "libc",
305 "Unable to set property \"%s\" to \"%s\": error code: 0x%x", key, value,
306 result);
307 return -1;
308 }
309
310 return 0;
311 }
312}