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