Add UID permission check to update_engine
Test: th
Bug: 302761914
Change-Id: I72a4169b79c70210ae8573abad2e8e181597cfe3
diff --git a/aosp/binder_service_android.cc b/aosp/binder_service_android.cc
index 37df9a5..a89655f 100644
--- a/aosp/binder_service_android.cc
+++ b/aosp/binder_service_android.cc
@@ -22,8 +22,10 @@
#include <base/logging.h>
#include <binderwrapper/binder_wrapper.h>
#include <utils/String8.h>
+#include <android-base/stringprintf.h>
#include "update_engine/aosp/binder_service_android_common.h"
+#include "update_engine/aosp/permission.h"
using android::binder::Status;
using android::os::IUpdateEngineCallback;
@@ -34,6 +36,7 @@
namespace chromeos_update_engine {
+
BinderUpdateEngineAndroidService::BinderUpdateEngineAndroidService(
ServiceDelegateAndroidInterface* service_delegate)
: service_delegate_(service_delegate) {}
@@ -56,6 +59,9 @@
Status BinderUpdateEngineAndroidService::bind(
const android::sp<IUpdateEngineCallback>& callback, bool* return_value) {
+ if (const auto status = CheckCallingUid(); !status.isOk()) {
+ return status;
+ }
// Send an status update on connection (except when no update sent so far).
// Even though the status update is oneway, it still returns an erroneous
// status in case of a selinux denial. We should at least check this status
@@ -85,6 +91,9 @@
Status BinderUpdateEngineAndroidService::unbind(
const android::sp<IUpdateEngineCallback>& callback, bool* return_value) {
+ if (const auto status = CheckCallingUid(); !status.isOk()) {
+ return status;
+ }
const android::sp<IBinder>& callback_binder =
IUpdateEngineCallback::asBinder(callback);
auto binder_wrapper = android::BinderWrapper::Get();
@@ -99,6 +108,9 @@
int64_t payload_offset,
int64_t payload_size,
const vector<android::String16>& header_kv_pairs) {
+ if (const auto status = CheckCallingUid(); !status.isOk()) {
+ return status;
+ }
const string payload_url{android::String8{url}.c_str()};
vector<string> str_headers = ToVecString(header_kv_pairs);
@@ -115,6 +127,9 @@
int64_t payload_offset,
int64_t payload_size,
const vector<android::String16>& header_kv_pairs) {
+ if (const auto status = CheckCallingUid(); !status.isOk()) {
+ return status;
+ }
vector<string> str_headers = ToVecString(header_kv_pairs);
Error error;
@@ -126,6 +141,9 @@
}
Status BinderUpdateEngineAndroidService::suspend() {
+ if (const auto status = CheckCallingUid(); !status.isOk()) {
+ return status;
+ }
Error error;
if (!service_delegate_->SuspendUpdate(&error))
return ErrorPtrToStatus(error);
@@ -133,6 +151,9 @@
}
Status BinderUpdateEngineAndroidService::resume() {
+ if (const auto status = CheckCallingUid(); !status.isOk()) {
+ return status;
+ }
Error error;
if (!service_delegate_->ResumeUpdate(&error))
return ErrorPtrToStatus(error);
@@ -140,6 +161,9 @@
}
Status BinderUpdateEngineAndroidService::cancel() {
+ if (const auto status = CheckCallingUid(); !status.isOk()) {
+ return status;
+ }
Error error;
if (!service_delegate_->CancelUpdate(&error))
return ErrorPtrToStatus(error);
@@ -147,6 +171,9 @@
}
Status BinderUpdateEngineAndroidService::resetStatus() {
+ if (const auto status = CheckCallingUid(); !status.isOk()) {
+ return status;
+ }
Error error;
if (!service_delegate_->ResetStatus(&error))
return ErrorPtrToStatus(error);
@@ -155,6 +182,9 @@
Status BinderUpdateEngineAndroidService::setShouldSwitchSlotOnReboot(
const android::String16& metadata_filename) {
+ if (const auto status = CheckCallingUid(); !status.isOk()) {
+ return status;
+ }
Error error;
if (!service_delegate_->setShouldSwitchSlotOnReboot(
android::String8(metadata_filename).c_str(), &error)) {
@@ -164,6 +194,9 @@
}
Status BinderUpdateEngineAndroidService::resetShouldSwitchSlotOnReboot() {
+ if (const auto status = CheckCallingUid(); !status.isOk()) {
+ return status;
+ }
Error error;
if (!service_delegate_->resetShouldSwitchSlotOnReboot(&error)) {
return ErrorPtrToStatus(error);
@@ -173,6 +206,9 @@
Status BinderUpdateEngineAndroidService::verifyPayloadApplicable(
const android::String16& metadata_filename, bool* return_value) {
+ if (const auto status = CheckCallingUid(); !status.isOk()) {
+ return status;
+ }
const std::string payload_metadata{
android::String8{metadata_filename}.c_str()};
LOG(INFO) << "Received a request of verifying payload metadata in "
@@ -204,6 +240,9 @@
const android::String16& metadata_filename,
const vector<android::String16>& header_kv_pairs,
int64_t* return_value) {
+ if (const auto status = CheckCallingUid(); !status.isOk()) {
+ return status;
+ }
const std::string payload_metadata{
android::String8{metadata_filename}.c_str()};
vector<string> str_headers = ToVecString(header_kv_pairs);
@@ -246,6 +285,9 @@
Status BinderUpdateEngineAndroidService::cleanupSuccessfulUpdate(
const android::sp<IUpdateEngineCallback>& callback) {
+ if (const auto status = CheckCallingUid(); !status.isOk()) {
+ return status;
+ }
Error error;
service_delegate_->CleanupSuccessfulUpdate(
std::make_unique<CleanupSuccessfulUpdateCallback>(callback), &error);
diff --git a/aosp/permission.cc b/aosp/permission.cc
new file mode 100644
index 0000000..6f13b03
--- /dev/null
+++ b/aosp/permission.cc
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#include <update_engine/aosp/permission.h>
+
+#include <array>
+#include <algorithm>
+#include <android-base/stringprintf.h>
+#include <android-base/logging.h>
+
+namespace chromeos_update_engine {
+
+android::binder::Status CheckCallingUid() {
+ const auto calling_uid = android::BinderWrapper::Get()->GetCallingUid();
+ if (!Contains(kAllowedUids, calling_uid)) {
+ LOG(ERROR) << "Calling UID " << calling_uid
+ << " is not allowed to access update_engine APIs";
+ auto message =
+ android::base::StringPrintf("UID %d is not allowed", calling_uid);
+ return android::binder::Status::fromExceptionCode(
+ android::binder::Status::EX_SECURITY,
+ android::String8(message.c_str()));
+ }
+ return android::binder::Status::ok();
+}
+
+} // namespace chromeos_update_engine
diff --git a/aosp/permission.h b/aosp/permission.h
new file mode 100644
index 0000000..46eaad0
--- /dev/null
+++ b/aosp/permission.h
@@ -0,0 +1,40 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef UPDATE_ENGINE_COMMON_PERMISSION_H_
+#define UPDATE_ENGINE_COMMON_PERMISSION_H_
+
+#include <binder/Status.h>
+#include <binderwrapper/binder_wrapper.h>
+#ifdef __ANDROID__
+#include <array>
+#include <private/android_filesystem_config.h>
+#include <algorithm>
+
+namespace chromeos_update_engine {
+static constexpr std::array<uid_t, 2> kAllowedUids = {AID_ROOT, AID_SYSTEM};
+
+template <typename Container, typename T>
+bool Contains(const Container& container, const T& t) {
+ return std::find(container.begin(), container.end(), t) != container.end();
+}
+
+android::binder::Status CheckCallingUid();
+
+} // namespace chromeos_update_engine
+#endif // __ANDROID__
+
+#endif // UPDATE_ENGINE_COMMON_PERMISSION_H_