Merge "String16: remove integer overflows"
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index e5666bc..31cb853 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -77,6 +77,7 @@
 
 static void intentionally_leak() {
     void* p = ::operator new(1);
+    // The analyzer is upset about this leaking. NOLINTNEXTLINE
     LOG(INFO) << "leaking pointer " << p;
 }
 
diff --git a/init/Android.bp b/init/Android.bp
index 60394ef..31c8efb 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -201,7 +201,7 @@
     name: "generated_stub_builtin_function_map",
     out: ["generated_stub_builtin_function_map.h"],
     srcs: ["builtins.cpp"],
-    cmd: "sed -n '/Builtin-function-map start/{:a;n;/Builtin-function-map end/q;p;ba}' $(in) | sed -e 's/do_[^}]*/do_stub/g' > $(out)"
+    cmd: "sed -n '/Builtin-function-map start/{:a;n;/Builtin-function-map end/q;p;ba}' $(in) | sed -e 's/do_[^}]*/do_stub/g' > $(out)",
 }
 
 cc_binary {
@@ -247,6 +247,14 @@
         type: "lite",
     },
     generated_headers: ["generated_stub_builtin_function_map"],
+    target: {
+        android: {
+            enabled: false,
+        },
+        darwin: {
+            enabled: false,
+        },
+    },
 }
 
 subdirs = ["*"]
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 51c2c9b..fc74dda 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -285,8 +285,11 @@
 
     if (e4crypt_is_native()) {
         if (e4crypt_set_directory_policy(args[1].c_str())) {
-            reboot_into_recovery(
-                {"--prompt_and_wipe_data", "--reason=set_policy_failed:"s + args[1]});
+            const std::vector<std::string> options = {
+                "--prompt_and_wipe_data",
+                "--reason=set_policy_failed:"s + args[1]};
+            reboot_into_recovery(options);
+            return Success();
         }
     }
     return Success();
@@ -984,24 +987,6 @@
     return android::base::GetProperty("ro.crypto.type", "") == "file";
 }
 
-static Result<Success> ExecWithRebootOnFailure(const std::string& reboot_reason,
-                                               const std::vector<std::string>& args) {
-    auto service = Service::MakeTemporaryOneshotService(args);
-    if (!service) {
-        return Error() << "Could not create exec service";
-    }
-    service->AddReapCallback([reboot_reason](const siginfo_t& siginfo) {
-        if (siginfo.si_code != CLD_EXITED || siginfo.si_status != 0) {
-            reboot_into_recovery({"--prompt_and_wipe_data", "--reason="s + reboot_reason});
-        }
-    });
-    if (auto result = service->ExecStart(); !result) {
-        return Error() << "Could not start exec service: " << result.error();
-    }
-    ServiceList::GetInstance().AddService(std::move(service));
-    return Success();
-}
-
 static Result<Success> do_installkey(const BuiltinArguments& args) {
     if (!is_file_crypto()) return Success();
 
@@ -1009,13 +994,15 @@
     if (!make_dir(unencrypted_dir, 0700) && errno != EEXIST) {
         return ErrnoError() << "Failed to create " << unencrypted_dir;
     }
-    return ExecWithRebootOnFailure("enablefilecrypto_failed", {"exec", "/system/bin/vdc", "--wait",
-                                                               "cryptfs", "enablefilecrypto"});
+    std::vector<std::string> exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs",
+                                          "enablefilecrypto"};
+    return do_exec({std::move(exec_args), args.context});
 }
 
 static Result<Success> do_init_user0(const BuiltinArguments& args) {
-    return ExecWithRebootOnFailure("init_user0_failed",
-                                   {"exec", "/system/bin/vdc", "--wait", "cryptfs", "init_user0"});
+    std::vector<std::string> exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs",
+                                          "init_user0"};
+    return do_exec({std::move(exec_args), args.context});
 }
 
 // Builtin-function-map start
diff --git a/init/host_init_stubs.cpp b/init/host_init_stubs.cpp
index cde747d..e6cc08a 100644
--- a/init/host_init_stubs.cpp
+++ b/init/host_init_stubs.cpp
@@ -43,8 +43,8 @@
 
 // property_service.h
 uint32_t (*property_set)(const std::string& name, const std::string& value) = nullptr;
-uint32_t HandlePropertySet(const std::string&, const std::string&, const std::string&,
-                           const ucred&) {
+uint32_t HandlePropertySet(const std::string&, const std::string&, const std::string&, const ucred&,
+                           std::string*) {
     return 0;
 }
 
diff --git a/init/host_init_stubs.h b/init/host_init_stubs.h
index af96aea..f31ece6 100644
--- a/init/host_init_stubs.h
+++ b/init/host_init_stubs.h
@@ -48,7 +48,7 @@
 // property_service.h
 extern uint32_t (*property_set)(const std::string& name, const std::string& value);
 uint32_t HandlePropertySet(const std::string& name, const std::string& value,
-                           const std::string& source_context, const ucred& cr);
+                           const std::string& source_context, const ucred& cr, std::string* error);
 
 // selinux.h
 void SelabelInitialize();
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 338c05a..95ef35c 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -59,8 +59,11 @@
 #include "init.h"
 #include "persistent_properties.h"
 #include "property_type.h"
+#include "subcontext.h"
 #include "util.h"
 
+using namespace std::literals;
+
 using android::base::ReadFileToString;
 using android::base::Split;
 using android::base::StartsWith;
@@ -117,23 +120,21 @@
     return has_access;
 }
 
-static uint32_t PropertySetImpl(const std::string& name, const std::string& value) {
+static uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error) {
     size_t valuelen = value.size();
 
     if (!IsLegalPropertyName(name)) {
-        LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: bad name";
+        *error = "Illegal property name";
         return PROP_ERROR_INVALID_NAME;
     }
 
     if (valuelen >= PROP_VALUE_MAX && !StartsWith(name, "ro.")) {
-        LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "
-                   << "value too long";
+        *error = "Property value too long";
         return PROP_ERROR_INVALID_VALUE;
     }
 
     if (mbstowcs(nullptr, value.data(), 0) == static_cast<std::size_t>(-1)) {
-        LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "
-                   << "value not a UTF8 encoded string";
+        *error = "Value is not a UTF8 encoded string";
         return PROP_ERROR_INVALID_VALUE;
     }
 
@@ -141,8 +142,7 @@
     if (pi != nullptr) {
         // ro.* properties are actually "write-once".
         if (StartsWith(name, "ro.")) {
-            LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "
-                       << "property already set";
+            *error = "Read-only property was already set";
             return PROP_ERROR_READ_ONLY_PROPERTY;
         }
 
@@ -150,8 +150,7 @@
     } else {
         int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen);
         if (rc < 0) {
-            LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "
-                       << "__system_property_add failed";
+            *error = "__system_property_add failed";
             return PROP_ERROR_SET_FAILED;
         }
     }
@@ -205,8 +204,10 @@
     if (info.pid != pid) {
         return false;
     }
-    if (PropertySetImpl(info.name, info.value) != PROP_SUCCESS) {
-        LOG(ERROR) << "Failed to set async property " << info.name;
+    std::string error;
+    if (PropertySet(info.name, info.value, &error) != PROP_SUCCESS) {
+        LOG(ERROR) << "Failed to set async property " << info.name << " to " << info.value << ": "
+                   << error;
     }
     property_children.pop();
     if (!property_children.empty()) {
@@ -216,9 +217,9 @@
 }
 
 static uint32_t PropertySetAsync(const std::string& name, const std::string& value,
-                                 PropertyAsyncFunc func) {
+                                 PropertyAsyncFunc func, std::string* error) {
     if (value.empty()) {
-        return PropertySetImpl(name, value);
+        return PropertySet(name, value, error);
     }
 
     PropertyChildInfo info;
@@ -236,30 +237,27 @@
     return selinux_android_restorecon(value.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE);
 }
 
-uint32_t PropertySet(const std::string& name, const std::string& value) {
-    if (name == "selinux.restorecon_recursive") {
-        return PropertySetAsync(name, value, RestoreconRecursiveAsync);
-    }
-
-    return PropertySetImpl(name, value);
-}
-
 uint32_t InitPropertySet(const std::string& name, const std::string& value) {
     if (StartsWith(name, "ctl.")) {
-        LOG(ERROR) << "Do not set ctl. properties from init; call the Service functions directly";
+        LOG(ERROR) << "InitPropertySet: Do not set ctl. properties from init; call the Service "
+                      "functions directly";
+        return PROP_ERROR_INVALID_NAME;
+    }
+    if (name == "selinux.restorecon_recursive") {
+        LOG(ERROR) << "InitPropertySet: Do not set selinux.restorecon_recursive from init; use the "
+                      "restorecon builtin directly";
         return PROP_ERROR_INVALID_NAME;
     }
 
-    const char* type = nullptr;
-    property_info_area->GetPropertyInfo(name.c_str(), nullptr, &type);
-
-    if (type == nullptr || !CheckType(type, value)) {
-        LOG(ERROR) << "property_set: name: '" << name << "' type check failed, type: '"
-                   << (type ?: "(null)") << "' value: '" << value << "'";
-        return PROP_ERROR_INVALID_VALUE;
+    uint32_t result = 0;
+    ucred cr = {.pid = 1, .uid = 0, .gid = 0};
+    std::string error;
+    result = HandlePropertySet(name, value, kInitContext.c_str(), cr, &error);
+    if (result != PROP_SUCCESS) {
+        LOG(ERROR) << "Init cannot set '" << name << "' to '" << value << "': " << error;
     }
 
-    return PropertySet(name, value);
+    return result;
 }
 
 class SocketConnection {
@@ -390,9 +388,9 @@
 
 // This returns one of the enum of PROP_SUCCESS or PROP_ERROR*.
 uint32_t HandlePropertySet(const std::string& name, const std::string& value,
-                           const std::string& source_context, const ucred& cr) {
+                           const std::string& source_context, const ucred& cr, std::string* error) {
     if (!IsLegalPropertyName(name)) {
-        LOG(ERROR) << "PropertySet: illegal property name \"" << name << "\"";
+        *error = "Illegal property name";
         return PROP_ERROR_INVALID_NAME;
     }
 
@@ -405,9 +403,7 @@
         const char* type = nullptr;
         property_info_area->GetPropertyInfo(control_string.c_str(), &target_context, &type);
         if (!CheckMacPerms(control_string, target_context, source_context.c_str(), cr)) {
-            LOG(ERROR) << "PropertySet: Unable to " << (name.c_str() + 4) << " service ctl ["
-                       << value << "]"
-                       << " uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid;
+            *error = StringPrintf("Unable to '%s' service %s", name.c_str() + 4, value.c_str());
             return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
         }
 
@@ -420,13 +416,13 @@
     property_info_area->GetPropertyInfo(name.c_str(), &target_context, &type);
 
     if (!CheckMacPerms(name, target_context, source_context.c_str(), cr)) {
-        LOG(ERROR) << "PropertySet: permission denied uid:" << cr.uid << " name:" << name;
+        *error = "SELinux permission check failed";
         return PROP_ERROR_PERMISSION_DENIED;
     }
 
     if (type == nullptr || !CheckType(type, value)) {
-        LOG(ERROR) << "PropertySet: name: '" << name << "' type check failed, type: '"
-                   << (type ?: "(null)") << "' value: '" << value << "'";
+        *error = StringPrintf("Property type check failed, value doesn't match expected type '%s'",
+                              (type ?: "(null)"));
         return PROP_ERROR_INVALID_VALUE;
     }
 
@@ -445,7 +441,11 @@
                   << process_log_string;
     }
 
-    return PropertySet(name, value);
+    if (name == "selinux.restorecon_recursive") {
+        return PropertySetAsync(name, value, RestoreconRecursiveAsync, error);
+    }
+
+    return PropertySet(name, value, error);
 }
 
 static void handle_property_set_fd() {
@@ -488,7 +488,16 @@
         prop_name[PROP_NAME_MAX-1] = 0;
         prop_value[PROP_VALUE_MAX-1] = 0;
 
-        HandlePropertySet(prop_value, prop_value, socket.source_context(), socket.cred());
+        const auto& cr = socket.cred();
+        std::string error;
+        uint32_t result =
+            HandlePropertySet(prop_name, prop_value, socket.source_context(), cr, &error);
+        if (result != PROP_SUCCESS) {
+            LOG(ERROR) << "Unable to set property '" << prop_name << "' to '" << prop_value
+                       << "' from uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid << ": "
+                       << error;
+        }
+
         break;
       }
 
@@ -502,7 +511,14 @@
           return;
         }
 
-        auto result = HandlePropertySet(name, value, socket.source_context(), socket.cred());
+        const auto& cr = socket.cred();
+        std::string error;
+        uint32_t result = HandlePropertySet(name, value, socket.source_context(), cr, &error);
+        if (result != PROP_SUCCESS) {
+            LOG(ERROR) << "Unable to set property '" << name << "' to '" << value
+                       << "' from uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid << ": "
+                       << error;
+        }
         socket.SendUint32(result);
         break;
       }
@@ -520,11 +536,17 @@
  * Filter is used to decide which properties to load: NULL loads all keys,
  * "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match.
  */
-static void load_properties(char *data, const char *filter)
-{
+static void LoadProperties(char* data, const char* filter, const char* filename) {
     char *key, *value, *eol, *sol, *tmp, *fn;
     size_t flen = 0;
 
+    const char* context = kInitContext.c_str();
+    for (const auto& [path_prefix, secontext] : paths_and_secontexts) {
+        if (StartsWith(filename, path_prefix)) {
+            context = secontext;
+        }
+    }
+
     if (filter) {
         flen = strlen(filter);
     }
@@ -571,7 +593,21 @@
                 }
             }
 
-            property_set(key, value);
+            if (StartsWith(key, "ctl.") || key == "sys.powerctl"s ||
+                key == "selinux.restorecon_recursive"s) {
+                LOG(ERROR) << "Ignoring disallowed property '" << key
+                           << "' with special meaning in prop file '" << filename << "'";
+                continue;
+            }
+
+            uint32_t result = 0;
+            ucred cr = {.pid = 1, .uid = 0, .gid = 0};
+            std::string error;
+            result = HandlePropertySet(key, value, context, cr, &error);
+            if (result != PROP_SUCCESS) {
+                LOG(ERROR) << "Unable to set property '" << key << "' to '" << value
+                           << "' in property file '" << filename << "': " << error;
+            }
         }
     }
 }
@@ -587,7 +623,8 @@
         return false;
     }
     file_contents->push_back('\n');
-    load_properties(file_contents->data(), filter);
+
+    LoadProperties(file_contents->data(), filter, filename);
     LOG(VERBOSE) << "(Loading properties from " << filename << " took " << t << ".)";
     return true;
 }
diff --git a/init/property_service.h b/init/property_service.h
index d4973fc..29eaaa9 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -32,7 +32,7 @@
 extern uint32_t (*property_set)(const std::string& name, const std::string& value);
 
 uint32_t HandlePropertySet(const std::string& name, const std::string& value,
-                           const std::string& source_context, const ucred& cr);
+                           const std::string& source_context, const ucred& cr, std::string* error);
 
 extern bool PropertyChildReap(pid_t pid);
 
diff --git a/init/service.cpp b/init/service.cpp
index 09d8dae..8130e73 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -303,7 +303,7 @@
     }
 }
 
-void Service::Reap(const siginfo_t& siginfo) {
+void Service::Reap() {
     if (!(flags_ & SVC_ONESHOT) || (flags_ & SVC_RESTART)) {
         KillProcessGroup(SIGKILL);
     }
@@ -312,10 +312,6 @@
     std::for_each(descriptors_.begin(), descriptors_.end(),
                   std::bind(&DescriptorInfo::Clean, std::placeholders::_1));
 
-    for (const auto& f : reap_callbacks_) {
-        f(siginfo);
-    }
-
     if (flags_ & SVC_EXEC) UnSetExec();
 
     if (flags_ & SVC_TEMPORARY) return;
diff --git a/init/service.h b/init/service.h
index bcf1943..d46a413 100644
--- a/init/service.h
+++ b/init/service.h
@@ -17,7 +17,6 @@
 #ifndef _INIT_SERVICE_H
 #define _INIT_SERVICE_H
 
-#include <signal.h>
 #include <sys/resource.h>
 #include <sys/types.h>
 
@@ -82,7 +81,7 @@
     void Stop();
     void Terminate();
     void Restart();
-    void Reap(const siginfo_t& siginfo);
+    void Reap();
     void DumpState() const;
     void SetShutdownCritical() { flags_ |= SVC_SHUTDOWN_CRITICAL; }
     bool IsShutdownCritical() const { return (flags_ & SVC_SHUTDOWN_CRITICAL) != 0; }
@@ -90,9 +89,6 @@
         is_exec_service_running_ = false;
         flags_ &= ~SVC_EXEC;
     }
-    void AddReapCallback(std::function<void(const siginfo_t& siginfo)> callback) {
-        reap_callbacks_.emplace_back(std::move(callback));
-    }
 
     static bool is_exec_service_running() { return is_exec_service_running_; }
 
@@ -214,8 +210,6 @@
     std::vector<std::pair<int, rlimit>> rlimits_;
 
     std::vector<std::string> args_;
-
-    std::vector<std::function<void(const siginfo_t& siginfo)>> reap_callbacks_;
 };
 
 class ServiceList {
diff --git a/init/sigchld_handler.cpp b/init/sigchld_handler.cpp
index badacaf..072a0fb 100644
--- a/init/sigchld_handler.cpp
+++ b/init/sigchld_handler.cpp
@@ -84,15 +84,16 @@
         }
     }
 
-    if (siginfo.si_code == CLD_EXITED) {
-        LOG(INFO) << name << " exited with status " << siginfo.si_status << wait_string;
-    } else {
-        LOG(INFO) << name << " received signal " << siginfo.si_status << wait_string;
+    auto status = siginfo.si_status;
+    if (WIFEXITED(status)) {
+        LOG(INFO) << name << " exited with status " << WEXITSTATUS(status) << wait_string;
+    } else if (WIFSIGNALED(status)) {
+        LOG(INFO) << name << " killed by signal " << WTERMSIG(status) << wait_string;
     }
 
     if (!service) return true;
 
-    service->Reap(siginfo);
+    service->Reap();
 
     if (service->flags() & SVC_TEMPORARY) {
         ServiceList::GetInstance().RemoveService(*service);
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index faab368..c1846f7 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -49,6 +49,11 @@
 const std::string kInitContext = "u:r:init:s0";
 const std::string kVendorContext = "u:r:vendor_init:s0";
 
+const char* const paths_and_secontexts[2][2] = {
+    {"/vendor", kVendorContext.c_str()},
+    {"/odm", kVendorContext.c_str()},
+};
+
 namespace {
 
 constexpr size_t kBufferSize = 4096;
@@ -297,7 +302,11 @@
 
     for (const auto& property : subcontext_reply->properties_to_set()) {
         ucred cr = {.pid = pid_, .uid = 0, .gid = 0};
-        HandlePropertySet(property.name(), property.value(), context_, cr);
+        std::string error;
+        if (HandlePropertySet(property.name(), property.value(), context_, cr, &error) != 0) {
+            LOG(ERROR) << "Subcontext init could not set '" << property.name() << "' to '"
+                       << property.value() << "': " << error;
+        }
     }
 
     if (subcontext_reply->reply_case() == SubcontextReply::kFailure) {
@@ -345,9 +354,6 @@
 static std::vector<Subcontext> subcontexts;
 
 std::vector<Subcontext>* InitializeSubcontexts() {
-    static const char* const paths_and_secontexts[][2] = {
-        {"/vendor", kVendorContext.c_str()},
-    };
     for (const auto& [path_prefix, secontext] : paths_and_secontexts) {
         subcontexts.emplace_back(path_prefix, secontext);
     }
diff --git a/init/subcontext.h b/init/subcontext.h
index 5601b80..22d7d43 100644
--- a/init/subcontext.h
+++ b/init/subcontext.h
@@ -33,6 +33,7 @@
 
 extern const std::string kInitContext;
 extern const std::string kVendorContext;
+extern const char* const paths_and_secontexts[2][2];
 
 class Subcontext {
   public:
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index f9f8c73..5e5e7af 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -224,7 +224,9 @@
     return kInvalidOffset;
   }
   if (eocd->num_records == 0) {
+#if defined(__ANDROID__)
     ALOGW("Zip: empty archive?");
+#endif
     return kEmptyArchive;
   }
 
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 560f490..b8af2f0 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -198,7 +198,7 @@
 
 int LogBuffer::log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
                    pid_t tid, const char* msg, unsigned short len) {
-    if ((log_id >= LOG_ID_MAX) || (log_id < 0)) {
+    if (log_id >= LOG_ID_MAX) {
         return -EINVAL;
     }