• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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