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 "private/bionic_macros.h"
49
50 static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME;
51 static const char* kServiceVersionPropertyName = "ro.property_service.version";
52
53 class PropertyServiceConnection {
54 public:
PropertyServiceConnection()55 PropertyServiceConnection() : last_error_(0) {
56 socket_ = ::socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
57 if (socket_ == -1) {
58 last_error_ = errno;
59 return;
60 }
61
62 const size_t namelen = strlen(property_service_socket);
63 sockaddr_un addr;
64 memset(&addr, 0, sizeof(addr));
65 strlcpy(addr.sun_path, property_service_socket, sizeof(addr.sun_path));
66 addr.sun_family = AF_LOCAL;
67 socklen_t alen = namelen + offsetof(sockaddr_un, sun_path) + 1;
68
69 if (TEMP_FAILURE_RETRY(connect(socket_, reinterpret_cast<sockaddr*>(&addr), alen)) == -1) {
70 last_error_ = errno;
71 close(socket_);
72 socket_ = -1;
73 }
74 }
75
IsValid()76 bool IsValid() {
77 return socket_ != -1;
78 }
79
GetLastError()80 int GetLastError() {
81 return last_error_;
82 }
83
RecvInt32(int32_t * value)84 bool RecvInt32(int32_t* value) {
85 int result = TEMP_FAILURE_RETRY(recv(socket_, value, sizeof(*value), MSG_WAITALL));
86 return CheckSendRecvResult(result, sizeof(*value));
87 }
88
socket()89 int socket() {
90 return socket_;
91 }
92
~PropertyServiceConnection()93 ~PropertyServiceConnection() {
94 if (socket_ != -1) {
95 close(socket_);
96 }
97 }
98
99 private:
CheckSendRecvResult(int result,int expected_len)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
112 int socket_;
113 int last_error_;
114
115 friend class SocketWriter;
116 };
117
118 class SocketWriter {
119 public:
SocketWriter(PropertyServiceConnection * connection)120 explicit SocketWriter(PropertyServiceConnection* connection)
121 : connection_(connection), iov_index_(0), uint_buf_index_(0) {
122 }
123
WriteUint32(uint32_t value)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
WriteString(const char * value)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
Send()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
174 BIONIC_DISALLOW_IMPLICIT_CONSTRUCTORS(SocketWriter);
175 };
176
177 struct prop_msg {
178 unsigned cmd;
179 char name[PROP_NAME_MAX];
180 char value[PROP_VALUE_MAX];
181 };
182
send_prop_msg(const prop_msg * msg)183 static int send_prop_msg(const prop_msg* msg) {
184 PropertyServiceConnection connection;
185 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.
217 // TODO: fix the system properties design.
218 async_safe_format_log(ANDROID_LOG_WARN, "libc",
219 "Property service has timed out while trying to set \"%s\" to \"%s\"",
220 msg->name, msg->value);
221 result = 0;
222 }
223 }
224
225 return result;
226 }
227
228 static constexpr uint32_t kProtocolVersion1 = 1;
229 static constexpr uint32_t kProtocolVersion2 = 2; // current
230
231 static atomic_uint_least32_t g_propservice_protocol_version = 0;
232
detect_protocol_version()233 static void detect_protocol_version() {
234 char value[PROP_VALUE_MAX];
235 if (__system_property_get(kServiceVersionPropertyName, value) == 0) {
236 g_propservice_protocol_version = kProtocolVersion1;
237 async_safe_format_log(ANDROID_LOG_WARN, "libc",
238 "Using old property service protocol (\"%s\" is not set)",
239 kServiceVersionPropertyName);
240 } else {
241 uint32_t version = static_cast<uint32_t>(atoll(value));
242 if (version >= kProtocolVersion2) {
243 g_propservice_protocol_version = kProtocolVersion2;
244 } else {
245 async_safe_format_log(ANDROID_LOG_WARN, "libc",
246 "Using old property service protocol (\"%s\"=\"%s\")",
247 kServiceVersionPropertyName, value);
248 g_propservice_protocol_version = kProtocolVersion1;
249 }
250 }
251 }
252
253 __BIONIC_WEAK_FOR_NATIVE_BRIDGE
__system_property_set(const char * key,const char * value)254 int __system_property_set(const char* key, const char* value) {
255 if (key == nullptr) return -1;
256 if (value == nullptr) value = "";
257
258 if (g_propservice_protocol_version == 0) {
259 detect_protocol_version();
260 }
261
262 if (g_propservice_protocol_version == kProtocolVersion1) {
263 // Old protocol does not support long names or values
264 if (strlen(key) >= PROP_NAME_MAX) return -1;
265 if (strlen(value) >= PROP_VALUE_MAX) return -1;
266
267 prop_msg msg;
268 memset(&msg, 0, sizeof msg);
269 msg.cmd = PROP_MSG_SETPROP;
270 strlcpy(msg.name, key, sizeof msg.name);
271 strlcpy(msg.value, value, sizeof msg.value);
272
273 return send_prop_msg(&msg);
274 } else {
275 // New protocol only allows long values for ro. properties only.
276 if (strlen(value) >= PROP_VALUE_MAX && strncmp(key, "ro.", 3) != 0) return -1;
277 // Use proper protocol
278 PropertyServiceConnection connection;
279 if (!connection.IsValid()) {
280 errno = connection.GetLastError();
281 async_safe_format_log(
282 ANDROID_LOG_WARN, "libc",
283 "Unable to set property \"%s\" to \"%s\": connection failed; errno=%d (%s)", key, value,
284 errno, strerror(errno));
285 return -1;
286 }
287
288 SocketWriter writer(&connection);
289 if (!writer.WriteUint32(PROP_MSG_SETPROP2).WriteString(key).WriteString(value).Send()) {
290 errno = connection.GetLastError();
291 async_safe_format_log(ANDROID_LOG_WARN, "libc",
292 "Unable to set property \"%s\" to \"%s\": write failed; errno=%d (%s)",
293 key, value, errno, strerror(errno));
294 return -1;
295 }
296
297 int result = -1;
298 if (!connection.RecvInt32(&result)) {
299 errno = connection.GetLastError();
300 async_safe_format_log(ANDROID_LOG_WARN, "libc",
301 "Unable to set property \"%s\" to \"%s\": recv failed; errno=%d (%s)",
302 key, value, errno, strerror(errno));
303 return -1;
304 }
305
306 if (result != PROP_SUCCESS) {
307 async_safe_format_log(ANDROID_LOG_WARN, "libc",
308 "Unable to set property \"%s\" to \"%s\": error code: 0x%x", key, value,
309 result);
310 return -1;
311 }
312
313 return 0;
314 }
315 }
316