summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-04-28 19:53:29 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-04-28 19:53:29 +0000
commitd52ead2a03b7f62bd03bfaaed1ffbf9360258763 (patch)
tree564b27298c1ad70c065d6e0f5d1c4501ddb0c061
parent3c3ce834241e30ea68bea901a7ae1c14b4490697 (diff)
parent8c6abf187fd1b233a2774b9776640262d0cf54b5 (diff)
downloadsecurity-d52ead2a03b7f62bd03bfaaed1ffbf9360258763.tar.gz
Snap for 8505378 from 8c6abf187fd1b233a2774b9776640262d0cf54b5 to mainline-go-permission-release
Change-Id: I1a907b3f971239756c5d782bec787b6de400d85a
-rw-r--r--identity/Android.bp2
-rw-r--r--keystore/tests/fuzzer/Android.bp4
-rw-r--r--keystore2/Android.bp1
-rw-r--r--keystore2/src/km_compat/km_compat.cpp2
-rw-r--r--keystore2/src/remote_provisioning.rs24
-rw-r--r--keystore2/src/security_level.rs15
-rw-r--r--keystore2/src/service.rs25
-rw-r--r--keystore2/src/utils.rs17
-rw-r--r--keystore2/tests/legacy_blobs/Android.bp9
-rw-r--r--ondevice-signing/Android.bp1
-rw-r--r--ondevice-signing/StatsReporter.cpp67
-rw-r--r--ondevice-signing/StatsReporter.h44
-rw-r--r--ondevice-signing/odsign_main.cpp25
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.