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