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