diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-04-28 19:53:29 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-04-28 19:53:29 +0000 |
commit | d52ead2a03b7f62bd03bfaaed1ffbf9360258763 (patch) | |
tree | 564b27298c1ad70c065d6e0f5d1c4501ddb0c061 | |
parent | 3c3ce834241e30ea68bea901a7ae1c14b4490697 (diff) | |
parent | 8c6abf187fd1b233a2774b9776640262d0cf54b5 (diff) | |
download | security-d52ead2a03b7f62bd03bfaaed1ffbf9360258763.tar.gz |
Snap for 8505378 from 8c6abf187fd1b233a2774b9776640262d0cf54b5 to mainline-go-permission-release
Change-Id: I1a907b3f971239756c5d782bec787b6de400d85a
-rw-r--r-- | identity/Android.bp | 2 | ||||
-rw-r--r-- | keystore/tests/fuzzer/Android.bp | 4 | ||||
-rw-r--r-- | keystore2/Android.bp | 1 | ||||
-rw-r--r-- | keystore2/src/km_compat/km_compat.cpp | 2 | ||||
-rw-r--r-- | keystore2/src/remote_provisioning.rs | 24 | ||||
-rw-r--r-- | keystore2/src/security_level.rs | 15 | ||||
-rw-r--r-- | keystore2/src/service.rs | 25 | ||||
-rw-r--r-- | keystore2/src/utils.rs | 17 | ||||
-rw-r--r-- | keystore2/tests/legacy_blobs/Android.bp | 9 | ||||
-rw-r--r-- | ondevice-signing/Android.bp | 1 | ||||
-rw-r--r-- | ondevice-signing/StatsReporter.cpp | 67 | ||||
-rw-r--r-- | ondevice-signing/StatsReporter.h | 44 | ||||
-rw-r--r-- | ondevice-signing/odsign_main.cpp | 25 |
13 files changed, 203 insertions, 33 deletions
diff --git a/identity/Android.bp b/identity/Android.bp index c69ead11..b3b704fb 100644 --- a/identity/Android.bp +++ b/identity/Android.bp @@ -59,7 +59,7 @@ cc_binary { ], static_libs: [ "android.hardware.identity-V4-cpp", - "android.hardware.keymaster-V4-cpp", + "android.hardware.keymaster-V3-cpp", "libcppbor_external", ], } diff --git a/keystore/tests/fuzzer/Android.bp b/keystore/tests/fuzzer/Android.bp index 589cef7a..4116ae14 100644 --- a/keystore/tests/fuzzer/Android.bp +++ b/keystore/tests/fuzzer/Android.bp @@ -31,12 +31,12 @@ cc_fuzz { ], static_libs: [ "libkeystore-wifi-hidl", - "libutils", ], shared_libs: [ "android.system.wifi.keystore@1.0", "libhidlbase", "liblog", + "libutils", ], fuzz_config: { cc: [ @@ -51,13 +51,13 @@ cc_defaults { static_libs: [ "libkeystore-attestation-application-id", "liblog", - "libutils", "libbase", "libhidlbase", ], shared_libs: [ "libbinder", "libcrypto", + "libutils", ], fuzz_config: { cc: [ diff --git a/keystore2/Android.bp b/keystore2/Android.bp index e7c27521..e6cb4fb5 100644 --- a/keystore2/Android.bp +++ b/keystore2/Android.bp @@ -178,4 +178,5 @@ rust_binary { "liblegacykeystore-rust", "librusqlite", ], + afdo: true, } diff --git a/keystore2/src/km_compat/km_compat.cpp b/keystore2/src/km_compat/km_compat.cpp index 192f4455..6d0630b4 100644 --- a/keystore2/src/km_compat/km_compat.cpp +++ b/keystore2/src/km_compat/km_compat.cpp @@ -126,7 +126,7 @@ bool isKeyCreationParameter(const KMV1::KeyParameter& param) { case Tag::TRUSTED_CONFIRMATION_REQUIRED: case Tag::UNLOCKED_DEVICE_REQUIRED: case Tag::CREATION_DATETIME: - case Tag::UNIQUE_ID: + case Tag::INCLUDE_UNIQUE_ID: case Tag::IDENTITY_CREDENTIAL_KEY: case Tag::STORAGE_KEY: case Tag::MAC_LENGTH: diff --git a/keystore2/src/remote_provisioning.rs b/keystore2/src/remote_provisioning.rs index be23ae5b..b47b3731 100644 --- a/keystore2/src/remote_provisioning.rs +++ b/keystore2/src/remote_provisioning.rs @@ -78,11 +78,27 @@ impl RemProvState { self.km_uuid } + fn is_rkp_only(&self) -> bool { + let default_value = false; + + let property_name = match self.security_level { + SecurityLevel::STRONGBOX => "remote_provisioning.strongbox.rkp_only", + SecurityLevel::TRUSTED_ENVIRONMENT => "remote_provisioning.tee.rkp_only", + _ => return default_value, + }; + + rustutils::system_properties::read_bool(property_name, default_value) + .unwrap_or(default_value) + } + /// Checks if remote provisioning is enabled and partially caches the result. On a hybrid system /// remote provisioning can flip from being disabled to enabled depending on responses from the /// server, so unfortunately caching the presence or absence of the HAL is not enough to fully /// make decisions about the state of remote provisioning during runtime. fn check_rem_prov_enabled(&self, db: &mut KeystoreDB) -> Result<bool> { + if self.is_rkp_only() { + return Ok(true); + } if !self.is_hal_present.load(Ordering::Relaxed) || get_remotely_provisioned_component(&self.security_level).is_err() { @@ -137,12 +153,12 @@ impl RemProvState { match get_rem_prov_attest_key(key.domain, caller_uid, db, &self.km_uuid) { Err(e) => { log::error!( - concat!( - "In get_remote_provisioning_key_and_certs: Failed to get ", - "attestation key. {:?}" - ), + "In get_remote_provisioning_key_and_certs: Error occurred: {:?}", e ); + if self.is_rkp_only() { + return Err(e); + } log_rkp_error_stats(MetricsRkpError::FALL_BACK_DURING_HYBRID); Ok(None) } diff --git a/keystore2/src/security_level.rs b/keystore2/src/security_level.rs index 1f6be32b..28de1ec8 100644 --- a/keystore2/src/security_level.rs +++ b/keystore2/src/security_level.rs @@ -27,7 +27,8 @@ use crate::metrics_store::log_key_creation_event_stats; use crate::remote_provisioning::RemProvState; use crate::super_key::{KeyBlob, SuperKeyManager}; use crate::utils::{ - check_device_attestation_permissions, check_key_permission, is_device_id_attestation_tag, + check_device_attestation_permissions, check_key_permission, + check_unique_id_attestation_permissions, is_device_id_attestation_tag, key_characteristics_to_internal, uid_to_android_user, watchdog as wd, }; use crate::{ @@ -452,10 +453,14 @@ impl KeystoreSecurityLevel { } if params.iter().any(|kp| kp.tag == Tag::INCLUDE_UNIQUE_ID) { - check_key_permission(KeyPerm::GenUniqueId, key, &None).context(concat!( - "In add_required_parameters: ", - "Caller does not have the permission to generate a unique ID" - ))?; + if check_key_permission(KeyPerm::GenUniqueId, key, &None).is_err() + && check_unique_id_attestation_permissions().is_err() + { + return Err(Error::perm()).context( + "In add_required_parameters: \ + Caller does not have the permission to generate a unique ID", + ); + } if self.id_rotation_state.had_factory_reset_since_id_rotation().context( "In add_required_parameters: Call to had_factory_reset_since_id_rotation failed.", )? { diff --git a/keystore2/src/service.rs b/keystore2/src/service.rs index 79e76923..d634e0c0 100644 --- a/keystore2/src/service.rs +++ b/keystore2/src/service.rs @@ -276,22 +276,19 @@ impl KeystoreService { // If the first check fails we check if the caller has the list permission allowing to list // any namespace. In that case we also adjust the queried namespace if a specific uid was // selected. - match check_key_permission(KeyPerm::GetInfo, &k, &None) { - Err(e) => { - if let Some(selinux::Error::PermissionDenied) = - e.root_cause().downcast_ref::<selinux::Error>() - { - check_keystore_permission(KeystorePerm::List) - .context("In list_entries: While checking keystore permission.")?; - if namespace != -1 { - k.nspace = namespace; - } - } else { - return Err(e).context("In list_entries: While checking key permission.")?; + if let Err(e) = check_key_permission(KeyPerm::GetInfo, &k, &None) { + if let Some(selinux::Error::PermissionDenied) = + e.root_cause().downcast_ref::<selinux::Error>() { + + check_keystore_permission(KeystorePerm::List) + .context("In list_entries: While checking keystore permission.")?; + if namespace != -1 { + k.nspace = namespace; } + } else { + return Err(e).context("In list_entries: While checking key permission.")?; } - Ok(()) => {} - }; + } DB.with(|db| list_key_entries(&mut db.borrow_mut(), k.domain, k.nspace)) } diff --git a/keystore2/src/utils.rs b/keystore2/src/utils.rs index a312c4b8..9db2eb9d 100644 --- a/keystore2/src/utils.rs +++ b/keystore2/src/utils.rs @@ -107,9 +107,20 @@ pub fn is_device_id_attestation_tag(tag: Tag) -> bool { } /// This function checks whether the calling app has the Android permissions needed to attest device -/// identifiers. It throws an error if the permissions cannot be verified, or if the caller doesn't -/// have the right permissions, and returns silently otherwise. +/// identifiers. It throws an error if the permissions cannot be verified or if the caller doesn't +/// have the right permissions. Otherwise it returns silently. pub fn check_device_attestation_permissions() -> anyhow::Result<()> { + check_android_permission("android.permission.READ_PRIVILEGED_PHONE_STATE") +} + +/// This function checks whether the calling app has the Android permissions needed to attest the +/// device-unique identifier. It throws an error if the permissions cannot be verified or if the +/// caller doesn't have the right permissions. Otherwise it returns silently. +pub fn check_unique_id_attestation_permissions() -> anyhow::Result<()> { + check_android_permission("android.permission.REQUEST_UNIQUE_ID_ATTESTATION") +} + +fn check_android_permission(permission: &str) -> anyhow::Result<()> { let permission_controller: Strong<dyn IPermissionController::IPermissionController> = binder::get_interface("permission")?; @@ -119,7 +130,7 @@ pub fn check_device_attestation_permissions() -> anyhow::Result<()> { 500, ); permission_controller.checkPermission( - "android.permission.READ_PRIVILEGED_PHONE_STATE", + permission, ThreadState::get_calling_pid(), ThreadState::get_calling_uid() as i32, ) diff --git a/keystore2/tests/legacy_blobs/Android.bp b/keystore2/tests/legacy_blobs/Android.bp index 2f48d7f2..9322a411 100644 --- a/keystore2/tests/legacy_blobs/Android.bp +++ b/keystore2/tests/legacy_blobs/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "system_security_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["system_security_license"], +} + rust_test { name: "keystore2_legacy_blobs_test", srcs: ["keystore2_legacy_blob_tests.rs"], diff --git a/ondevice-signing/Android.bp b/ondevice-signing/Android.bp index bdc94b7e..d73f8fe5 100644 --- a/ondevice-signing/Android.bp +++ b/ondevice-signing/Android.bp @@ -112,6 +112,7 @@ cc_binary { "KeystoreKey.cpp", "KeystoreHmacKey.cpp", "odsign_main.cpp", + "StatsReporter.cpp", ], header_libs: ["odrefresh_headers"], diff --git a/ondevice-signing/StatsReporter.cpp b/ondevice-signing/StatsReporter.cpp new file mode 100644 index 00000000..65e645a3 --- /dev/null +++ b/ondevice-signing/StatsReporter.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2022 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 "StatsReporter.h" +#include <android-base/logging.h> +#include <stdlib.h> +#include <string> +#include <sys/stat.h> + +// Keep these constant in sync with COMPOS_METRIC_NAME & METRICS_FILE in OdsignStatsLogger.java. +constexpr const char* kOdsignMetricsFile = "/data/misc/odsign/metrics/odsign-metrics.txt"; +constexpr const char* kComposMetricName = "comp_os_artifacts_check_record"; + +StatsReporter::~StatsReporter() { + if (comp_os_artifacts_check_record_ == nullptr) { + LOG(INFO) << "Metrics report is empty"; + + // Remove the metrics file if any old version of the file already exists + if (std::filesystem::remove(kOdsignMetricsFile) != 0 && + !((errno = ENOENT) || errno == ENOTDIR)) { + PLOG(ERROR) << "Could not remove already present file"; + } + return; + } + + std::ofstream odsign_metrics_file_; + odsign_metrics_file_.open(kOdsignMetricsFile, std::ios::trunc); + if (!odsign_metrics_file_) { + PLOG(ERROR) << "Could not open file: " << kOdsignMetricsFile; + return; + } + + odsign_metrics_file_ << kComposMetricName << ' '; + odsign_metrics_file_ << comp_os_artifacts_check_record_->current_artifacts_ok << ' '; + odsign_metrics_file_ << comp_os_artifacts_check_record_->comp_os_pending_artifacts_exists + << ' '; + odsign_metrics_file_ << comp_os_artifacts_check_record_->use_comp_os_generated_artifacts + << '\n'; + if (chmod(kOdsignMetricsFile, 0644) != 0) { + PLOG(ERROR) << "Could not set correct file permissions for " << kOdsignMetricsFile; + return; + } + odsign_metrics_file_.close(); + if (!odsign_metrics_file_) { + PLOG(ERROR) << "Failed to close the file"; + } +} + +StatsReporter::CompOsArtifactsCheckRecord* StatsReporter::GetComposArtifactsCheckRecord() { + if (comp_os_artifacts_check_record_ == nullptr) { + comp_os_artifacts_check_record_ = std::make_unique<CompOsArtifactsCheckRecord>(); + } + return comp_os_artifacts_check_record_.get(); +} diff --git a/ondevice-signing/StatsReporter.h b/ondevice-signing/StatsReporter.h new file mode 100644 index 00000000..2682b963 --- /dev/null +++ b/ondevice-signing/StatsReporter.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2022 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. + */ + +#pragma once + +#include <fstream> + +// Class to store CompOsArtifactsCheck related metrics. +// These are flushed to a file kOdsignMetricsFile and consumed by +// System Server (in class OdsignStatsLogger) & sent to statsd. +class StatsReporter { + public: + // Keep sync with EarlyBootCompOsArtifactsCheckReported + // definition in proto_logging/stats/atoms.proto. + struct CompOsArtifactsCheckRecord { + bool current_artifacts_ok = false; + bool comp_os_pending_artifacts_exists = false; + bool use_comp_os_generated_artifacts = false; + }; + + // The report is flushed (from buffer) into a file by the destructor. + ~StatsReporter(); + + // Get pointer to comp_os_artifacts_check_record, caller can then modify it. + // Note: pointer remains valid for the lifetime of this StatsReporter. + CompOsArtifactsCheckRecord* GetComposArtifactsCheckRecord(); + + private: + // Temporary buffer which stores the metrics. + std::unique_ptr<CompOsArtifactsCheckRecord> comp_os_artifacts_check_record_; +}; diff --git a/ondevice-signing/odsign_main.cpp b/ondevice-signing/odsign_main.cpp index fc558462..04679a59 100644 --- a/ondevice-signing/odsign_main.cpp +++ b/ondevice-signing/odsign_main.cpp @@ -33,6 +33,7 @@ #include "CertUtils.h" #include "KeystoreKey.h" +#include "StatsReporter.h" #include "VerityUtils.h" #include "odsign_info.pb.h" @@ -365,19 +366,26 @@ Result<OdsignInfo> getComposInfo() { return compos_info; } -art::odrefresh::ExitCode checkCompOsPendingArtifacts(const SigningKey& signing_key, - bool* digests_verified) { +art::odrefresh::ExitCode CheckCompOsPendingArtifacts(const SigningKey& signing_key, + bool* digests_verified, + StatsReporter* stats_reporter) { + StatsReporter::CompOsArtifactsCheckRecord* compos_check_record = + stats_reporter->GetComposArtifactsCheckRecord(); + if (!directoryHasContent(kCompOsPendingArtifactsDir)) { // No pending CompOS artifacts, all that matters is the current ones. return checkArtifacts(); } + compos_check_record->comp_os_pending_artifacts_exists = true; + // CompOS has generated some artifacts that may, or may not, match the // current state. But if there are already valid artifacts present the // CompOS ones are redundant. art::odrefresh::ExitCode odrefresh_status = checkArtifacts(); if (odrefresh_status != art::odrefresh::ExitCode::kCompilationRequired) { if (odrefresh_status == art::odrefresh::ExitCode::kOkay) { + compos_check_record->current_artifacts_ok = true; LOG(INFO) << "Current artifacts are OK, deleting pending artifacts"; removeDirectory(kCompOsPendingArtifactsDir); } @@ -432,6 +440,7 @@ art::odrefresh::ExitCode checkCompOsPendingArtifacts(const SigningKey& signing_k // are pretty bad. return art::odrefresh::ExitCode::kCleanupFailed; } + compos_check_record->use_comp_os_generated_artifacts = true; LOG(INFO) << "Persisted CompOS digests."; *digests_verified = true; return odrefresh_status; @@ -455,6 +464,9 @@ art::odrefresh::ExitCode checkCompOsPendingArtifacts(const SigningKey& signing_k } // namespace int main(int /* argc */, char** argv) { + // stats_reporter is a pointer so that we can explicitly delete it + // instead of waiting for the program to die & its destrcutor be called + auto stats_reporter = std::make_unique<StatsReporter>(); android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM)); auto errorScopeGuard = []() { @@ -516,7 +528,14 @@ int main(int /* argc */, char** argv) { bool digests_verified = false; art::odrefresh::ExitCode odrefresh_status = - useCompOs ? checkCompOsPendingArtifacts(*key, &digests_verified) : checkArtifacts(); + useCompOs ? CheckCompOsPendingArtifacts(*key, &digests_verified, stats_reporter.get()) + : checkArtifacts(); + + // Explicitly reset the pointer - We rely on stats_reporter's + // destructor for actually writing the buffered metrics. This will otherwise not be called + // if the program doesn't exit normally (for ex, killed by init, which actually happens + // because odsign (after it finishes) sets kStopServiceProp instructing init to kill it). + stats_reporter.reset(); // The artifacts dir doesn't necessarily need to exist; if the existing // artifacts on the system partition are valid, those can be used. |