Merge "keystore2_unsafe_fuzzer: Bug Fix" into main
diff --git a/OWNERS b/OWNERS
index 03e5769..6fdb550 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,5 +1,4 @@
alanstokes@google.com
-cbrubaker@google.com
drysdale@google.com
eranm@google.com
hasinitg@google.com
@@ -8,4 +7,5 @@
kroot@google.com
sethmo@google.com
swillden@google.com
+trong@google.com
zeuthen@google.com
diff --git a/diced/open_dice/Android.bp b/diced/open_dice/Android.bp
index 45cbb67..c59419b 100644
--- a/diced/open_dice/Android.bp
+++ b/diced/open_dice/Android.bp
@@ -7,14 +7,6 @@
name: "libdiced_open_dice_defaults",
crate_name: "diced_open_dice",
srcs: ["src/lib.rs"],
- static_libs: [
- "libopen_dice_cbor",
- ],
- vendor_available: true,
- apex_available: [
- "//apex_available:platform",
- "com.android.virt",
- ],
}
rust_library_rlib {
@@ -37,6 +29,7 @@
rust_library {
name: "libdiced_open_dice",
defaults: ["libdiced_open_dice_defaults"],
+ vendor_available: true,
rustlibs: [
"libopen_dice_bcc_bindgen",
"libopen_dice_cbor_bindgen",
@@ -48,6 +41,9 @@
shared_libs: [
"libcrypto",
],
+ static_libs: [
+ "libopen_dice_cbor",
+ ],
whole_static_libs: [
"libopen_dice_bcc",
],
@@ -56,6 +52,10 @@
"//packages/modules/Virtualization:__subpackages__",
"//hardware/interfaces/security/dice/aidl:__subpackages__",
],
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.virt",
+ ],
}
rust_defaults {
@@ -120,7 +120,6 @@
rust_defaults {
name: "libopen_dice_cbor_bindgen.rust_defaults",
- defaults: ["libopen_dice.rust_defaults"],
wrapper_src: "bindgen/dice.h",
crate_name: "open_dice_cbor_bindgen",
source_stem: "bindings",
@@ -156,7 +155,10 @@
rust_bindgen {
name: "libopen_dice_cbor_bindgen",
- defaults: ["libopen_dice_cbor_bindgen.rust_defaults"],
+ defaults: [
+ "libopen_dice.rust_defaults",
+ "libopen_dice_cbor_bindgen.rust_defaults",
+ ],
whole_static_libs: ["libopen_dice_cbor"],
}
@@ -171,7 +173,6 @@
rust_defaults {
name: "libopen_dice_bcc_bindgen.rust_defaults",
- defaults: ["libopen_dice.rust_defaults"],
wrapper_src: "bindgen/android/bcc.h",
crate_name: "open_dice_bcc_bindgen",
source_stem: "bindings",
@@ -206,7 +207,10 @@
rust_bindgen {
name: "libopen_dice_bcc_bindgen",
- defaults: ["libopen_dice_bcc_bindgen.rust_defaults"],
+ defaults: [
+ "libopen_dice.rust_defaults",
+ "libopen_dice_bcc_bindgen.rust_defaults",
+ ],
rustlibs: [
"libopen_dice_cbor_bindgen",
],
diff --git a/fsverity_init/Android.bp b/fsverity_init/Android.bp
index 83c5945..07eaf6a 100644
--- a/fsverity_init/Android.bp
+++ b/fsverity_init/Android.bp
@@ -10,26 +10,10 @@
cc_binary {
name: "fsverity_init",
srcs: [
- "main.cpp",
+ "fsverity_init.cpp",
],
static_libs: [
"libc++fs",
- "libfsverity_init",
- "libmini_keyctl_static",
- ],
- shared_libs: [
- "libbase",
- "libkeyutils",
- "liblog",
- ],
- cflags: ["-Werror", "-Wall", "-Wextra"],
-}
-
-cc_library {
- name: "libfsverity_init",
- srcs: ["fsverity_init.cpp"],
- static_libs: [
- "libc++fs",
"libmini_keyctl_static",
],
shared_libs: [
@@ -38,6 +22,4 @@
"liblog",
],
cflags: ["-Werror", "-Wall", "-Wextra"],
- export_include_dirs: ["include"],
- recovery_available: true,
}
diff --git a/fsverity_init/fsverity_init.cpp b/fsverity_init/fsverity_init.cpp
index 61f84dd..797118d 100644
--- a/fsverity_init/fsverity_init.cpp
+++ b/fsverity_init/fsverity_init.cpp
@@ -14,6 +14,25 @@
* limitations under the License.
*/
+//
+// fsverity_init is a tool for loading X.509 certificates into the kernel keyring used by the
+// fsverity builtin signature verification kernel feature
+// (https://www.kernel.org/doc/html/latest/filesystems/fsverity.html#built-in-signature-verification).
+// Starting in Android 14, Android has actually stopped using this feature, as it was too inflexible
+// and caused problems. It has been replaced by userspace signature verification. Also, some uses
+// of fsverity in Android are now for integrity-only use cases.
+//
+// Regardless, there may exist fsverity files on-disk that were created by Android 13 or earlier.
+// These files still have builtin signatures. If the kernel is an older kernel that still has
+// CONFIG_FS_VERITY_BUILTIN_SIGNATURES enabled, these files cannot be opened unless the
+// corresponding key is in the ".fs-verity" keyring. Therefore, this tool still has to exist and be
+// used to load keys into the kernel, even though this has no security purpose anymore.
+//
+// This tool can be removed as soon as all supported kernels are guaranteed to have
+// CONFIG_FS_VERITY_BUILTIN_SIGNATURES disabled, or alternatively as soon as support for upgrades
+// from Android 13 or earlier is no longer required.
+//
+
#define LOG_TAG "fsverity_init"
#include <sys/types.h>
@@ -23,33 +42,10 @@
#include <android-base/file.h>
#include <android-base/logging.h>
-#include <android-base/properties.h>
#include <android-base/strings.h>
#include <log/log.h>
#include <mini_keyctl_utils.h>
-bool LoadKeyToKeyring(key_serial_t keyring_id, const char* desc, const char* data, size_t size) {
- key_serial_t key = add_key("asymmetric", desc, data, size, keyring_id);
- if (key < 0) {
- PLOG(ERROR) << "Failed to add key";
- return false;
- }
- return true;
-}
-
-bool LoadKeyFromStdin(key_serial_t keyring_id, const char* keyname) {
- std::string content;
- if (!android::base::ReadFdToString(STDIN_FILENO, &content)) {
- LOG(ERROR) << "Failed to read key from stdin";
- return false;
- }
- if (!LoadKeyToKeyring(keyring_id, keyname, content.c_str(), content.size())) {
- LOG(ERROR) << "Failed to load key from stdin";
- return false;
- }
- return true;
-}
-
void LoadKeyFromFile(key_serial_t keyring_id, const char* keyname, const std::string& path) {
LOG(INFO) << "LoadKeyFromFile path=" << path << " keyname=" << keyname;
std::string content;
@@ -57,8 +53,8 @@
LOG(ERROR) << "Failed to read key from " << path;
return;
}
- if (!LoadKeyToKeyring(keyring_id, keyname, content.c_str(), content.size())) {
- LOG(ERROR) << "Failed to load key from " << path;
+ if (add_key("asymmetric", keyname, content.c_str(), content.size(), keyring_id) < 0) {
+ PLOG(ERROR) << "Failed to add key from " << path;
}
}
@@ -81,3 +77,28 @@
LoadKeyFromDirectory(keyring_id, "fsv_system_", "/system/etc/security/fsverity");
LoadKeyFromDirectory(keyring_id, "fsv_product_", "/product/etc/security/fsverity");
}
+
+int main(int argc, const char** argv) {
+ if (argc < 2) {
+ LOG(ERROR) << "Not enough arguments";
+ return -1;
+ }
+
+ key_serial_t keyring_id = android::GetKeyringId(".fs-verity");
+ if (keyring_id < 0) {
+ // This is expected on newer kernels. See comment at the beginning of this file.
+ LOG(DEBUG) << "no initialization required";
+ return 0;
+ }
+
+ const std::string_view command = argv[1];
+
+ if (command == "--load-verified-keys") {
+ LoadKeyFromVerifiedPartitions(keyring_id);
+ } else {
+ LOG(ERROR) << "Unknown argument(s).";
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/fsverity_init/include/fsverity_init.h b/fsverity_init/include/fsverity_init.h
deleted file mode 100644
index c3bc93b..0000000
--- a/fsverity_init/include/fsverity_init.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2021 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 <mini_keyctl_utils.h>
-
-bool LoadKeyFromStdin(key_serial_t keyring_id, const char* keyname);
-void LoadKeyFromFile(key_serial_t keyring_id, const char* keyname, const std::string& path);
-void LoadKeyFromVerifiedPartitions(key_serial_t keyring_id);
diff --git a/fsverity_init/main.cpp b/fsverity_init/main.cpp
deleted file mode 100644
index b502b91..0000000
--- a/fsverity_init/main.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2021 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 <string>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <fsverity_init.h>
-#include <log/log.h>
-#include <mini_keyctl_utils.h>
-
-int main(int argc, const char** argv) {
- if (argc < 2) {
- LOG(ERROR) << "Not enough arguments";
- return -1;
- }
-
- key_serial_t keyring_id = android::GetKeyringId(".fs-verity");
- if (keyring_id < 0) {
- LOG(ERROR) << "Failed to find .fs-verity keyring id";
- return -1;
- }
-
- const std::string_view command = argv[1];
-
- if (command == "--load-verified-keys") {
- LoadKeyFromVerifiedPartitions(keyring_id);
- } else if (command == "--load-extra-key") {
- if (argc != 3) {
- LOG(ERROR) << "--load-extra-key requires <key_name> argument.";
- return -1;
- }
- if (!LoadKeyFromStdin(keyring_id, argv[2])) {
- return -1;
- }
- } else if (command == "--lock") {
- if (!android::base::GetBoolProperty("ro.debuggable", false)) {
- if (keyctl_restrict_keyring(keyring_id, nullptr, nullptr) < 0) {
- PLOG(ERROR) << "Cannot restrict .fs-verity keyring";
- }
- }
- } else {
- LOG(ERROR) << "Unknown argument(s).";
- return -1;
- }
-
- return 0;
-}
diff --git a/identity/CredentialData.cpp b/identity/CredentialData.cpp
index 803e671..ecf2258 100644
--- a/identity/CredentialData.cpp
+++ b/identity/CredentialData.cpp
@@ -527,7 +527,6 @@
return nullptr;
}
- int n = 0;
for (AuthKeyData& data : authKeyDatas_) {
if (nowMilliSeconds > data.expirationDateMillisSinceEpoch) {
if (!allowUsingExpiredKeys) {
@@ -540,7 +539,6 @@
candidate = &data;
}
}
- n++;
}
if (candidate == nullptr) {
diff --git a/keystore/keystore_attestation_id.cpp b/keystore/keystore_attestation_id.cpp
index ccd3808..8eade97 100644
--- a/keystore/keystore_attestation_id.cpp
+++ b/keystore/keystore_attestation_id.cpp
@@ -74,8 +74,8 @@
}
KeyAttestationApplicationIdProvider::KeyAttestationApplicationIdProvider()
- : BpKeyAttestationApplicationIdProvider(
- android::defaultServiceManager()->getService(String16("sec_key_att_app_id_provider"))) {}
+ : BpKeyAttestationApplicationIdProvider(android::defaultServiceManager()->waitForService(
+ String16("sec_key_att_app_id_provider"))) {}
DECLARE_STACK_OF(ASN1_OCTET_STRING);
@@ -158,7 +158,7 @@
return BAD_VALUE;
}
- std::string pkg_name(String8(*pinfo.package_name()).string());
+ std::string pkg_name(String8(*pinfo.package_name()).c_str());
if (!ASN1_OCTET_STRING_set(attestation_package_info->package_name,
reinterpret_cast<const unsigned char*>(pkg_name.data()),
pkg_name.size())) {
@@ -209,7 +209,7 @@
ALOGE("Key attestation package info lacks package name");
return BAD_VALUE;
}
- std::string package_name(String8(*pinfo->package_name()).string());
+ std::string package_name(String8(*pinfo->package_name()).c_str());
std::unique_ptr<KM_ATTESTATION_PACKAGE_INFO> attestation_package_info;
auto rc = build_attestation_package_info(*pinfo, &attestation_package_info);
if (rc != NO_ERROR) {
@@ -283,7 +283,7 @@
// caller is unknown.
if (!status.isOk()) {
ALOGW("package manager request for key attestation ID failed with: %s %d",
- status.exceptionMessage().string(), status.exceptionCode());
+ status.exceptionMessage().c_str(), status.exceptionCode());
auto pinfo = std::make_optional<KeyAttestationPackageInfo>(
String16(kUnknownPackageName), 1 /* version code */,
std::make_shared<KeyAttestationPackageInfo::SignaturesVector>());
diff --git a/keystore2/apc_compat/apc_compat.cpp b/keystore2/apc_compat/apc_compat.cpp
index 9f60db2..ffe7595 100644
--- a/keystore2/apc_compat/apc_compat.cpp
+++ b/keystore2/apc_compat/apc_compat.cpp
@@ -118,8 +118,7 @@
hidl_ui_options);
if (!rc.isOk()) {
LOG(ERROR) << "Communication error: promptUserConfirmation: " << rc.description();
- }
- if (rc == ResponseCode::OK) {
+ } else if (rc == ResponseCode::OK) {
callback_ = callback;
}
return responseCode2Compat(rc.withDefault(ResponseCode::SystemError));
diff --git a/keystore2/apc_compat/apc_compat.rs b/keystore2/apc_compat/apc_compat.rs
index 480f14d..e97ac59 100644
--- a/keystore2/apc_compat/apc_compat.rs
+++ b/keystore2/apc_compat/apc_compat.rs
@@ -53,7 +53,10 @@
/// ```
pub struct ApcHal(ApcCompatServiceHandle);
+// SAFETY: This is a wrapper around `ApcCompatSession`, which can be used from any thread.
unsafe impl Send for ApcHal {}
+// SAFETY: `ApcCompatSession` can be called simultaneously from different threads because AIDL and
+// HIDL are thread-safe.
unsafe impl Sync for ApcHal {}
impl Drop for ApcHal {
@@ -120,6 +123,7 @@
// `closeUserConfirmationService` when dropped.
let handle = unsafe { tryGetUserConfirmationService() };
match handle {
+ // SAFETY: This is just a constant.
h if h == unsafe { INVALID_SERVICE_HANDLE } => None,
h => Some(Self(h)),
}
diff --git a/keystore2/selinux/src/lib.rs b/keystore2/selinux/src/lib.rs
index e5c3091..32fdb59 100644
--- a/keystore2/selinux/src/lib.rs
+++ b/keystore2/selinux/src/lib.rs
@@ -20,6 +20,9 @@
//! * selabel_lookup for the keystore2_key backend.
//! And it provides an owning wrapper around context strings `Context`.
+// TODO(b/290018030): Remove this and add proper safety comments.
+#![allow(clippy::undocumented_unsafe_blocks)]
+
use anyhow::Context as AnyhowContext;
use anyhow::{anyhow, Result};
use lazy_static::lazy_static;
@@ -160,8 +163,9 @@
handle: *mut selinux::selabel_handle,
}
-// KeystoreKeyBackend is Sync because selabel_lookup is thread safe.
+// SAFETY: KeystoreKeyBackend is Sync because selabel_lookup is thread safe.
unsafe impl Sync for KeystoreKeyBackend {}
+// SAFETY: KeystoreKeyBackend is Send because selabel_lookup is thread safe.
unsafe impl Send for KeystoreKeyBackend {}
impl KeystoreKeyBackend {
diff --git a/keystore2/src/apc.rs b/keystore2/src/apc.rs
index 5d2083d..fbf9464 100644
--- a/keystore2/src/apc.rs
+++ b/keystore2/src/apc.rs
@@ -244,7 +244,7 @@
// If cancelled by the user or if aborted by the client.
(ResponseCode::CANCELLED, _, _) | (ResponseCode::ABORTED, true, _) => {
// Penalize.
- let mut rate_info = state.rate_limiting.entry(uid).or_default();
+ let rate_info = state.rate_limiting.entry(uid).or_default();
rate_info.counter += 1;
rate_info.timestamp = start;
}
diff --git a/keystore2/src/crypto/lib.rs b/keystore2/src/crypto/lib.rs
index 08b7589..8434651 100644
--- a/keystore2/src/crypto/lib.rs
+++ b/keystore2/src/crypto/lib.rs
@@ -49,8 +49,8 @@
/// Generate an AES256 key, essentially 32 random bytes from the underlying
/// boringssl library discretely stuffed into a ZVec.
pub fn generate_aes256_key() -> Result<ZVec, Error> {
- // Safety: key has the same length as the requested number of random bytes.
let mut key = ZVec::new(AES_256_KEY_LENGTH)?;
+ // Safety: key has the same length as the requested number of random bytes.
if unsafe { randomBytes(key.as_mut_ptr(), AES_256_KEY_LENGTH) } {
Ok(key)
} else {
@@ -65,8 +65,8 @@
/// Generate random data of the given size.
pub fn generate_random_data(size: usize) -> Result<Vec<u8>, Error> {
- // Safety: data has the same length as the requested number of random bytes.
let mut data = vec![0; size];
+ // Safety: data has the same length as the requested number of random bytes.
if unsafe { randomBytes(data.as_mut_ptr(), size) } {
Ok(data)
} else {
@@ -209,6 +209,8 @@
let pw = self.get_key();
let mut result = ZVec::new(key_length)?;
+ // Safety: We checked that the salt is exactly 16 bytes long. The other pointers are valid,
+ // and have matching lengths.
unsafe {
generateKeyFromPassword(
result.as_mut_ptr(),
@@ -324,10 +326,10 @@
/// Calls the boringssl ECDH_compute_key function.
pub fn ecdh_compute_key(pub_key: &EC_POINT, priv_key: &ECKey) -> Result<ZVec, Error> {
let mut buf = ZVec::new(EC_MAX_BYTES)?;
+ let result =
// Safety: Our ECDHComputeKey wrapper passes EC_MAX_BYES to ECDH_compute_key, which
// writes at most that many bytes to the output.
// The two keys are valid objects.
- let result =
unsafe { ECDHComputeKey(buf.as_mut_ptr() as *mut std::ffi::c_void, pub_key, priv_key.0) };
if result == -1 {
return Err(Error::ECDHComputeKeyFailed);
@@ -487,9 +489,11 @@
let input = vec![0; 16];
let mut out = vec![0; 16];
let mut out2 = vec![0; 16];
- let key = vec![0; 16];
- let iv = vec![0; 12];
+ let key = [0; 16];
+ let iv = [0; 12];
let mut tag = vec![0; 16];
+ // SAFETY: The various pointers are obtained from references so they are valid, and
+ // `AES_gcm_encrypt` and `AES_gcm_decrypt` don't do anything with them after they return.
unsafe {
let res = AES_gcm_encrypt(
input.as_ptr(),
@@ -519,10 +523,12 @@
#[test]
fn test_create_key_id() {
- let blob = vec![0; 16];
+ let blob = [0; 16];
let mut out: u64 = 0;
+ // SAFETY: The pointers are obtained from references so they are valid, the length matches
+ // the length of the array, and `CreateKeyId` doesn't access them after it returns.
unsafe {
- let res = CreateKeyId(blob.as_ptr(), 16, &mut out);
+ let res = CreateKeyId(blob.as_ptr(), blob.len(), &mut out);
assert!(res);
assert_ne!(out, 0);
}
@@ -531,10 +537,19 @@
#[test]
fn test_generate_key_from_password() {
let mut key = vec![0; 16];
- let pw = vec![0; 16];
- let salt = vec![0; 16];
+ let pw = [0; 16];
+ let salt = [0; 16];
+ // SAFETY: The pointers are obtained from references so they are valid, the salt is the
+ // expected length, the other lengths match the lengths of the arrays, and
+ // `generateKeyFromPassword` doesn't access them after it returns.
unsafe {
- generateKeyFromPassword(key.as_mut_ptr(), 16, pw.as_ptr(), 16, salt.as_ptr());
+ generateKeyFromPassword(
+ key.as_mut_ptr(),
+ key.len(),
+ pw.as_ptr(),
+ pw.len(),
+ salt.as_ptr(),
+ );
}
assert_ne!(key, vec![0; 16]);
}
diff --git a/keystore2/src/crypto/zvec.rs b/keystore2/src/crypto/zvec.rs
index 5a173c3..c917a89 100644
--- a/keystore2/src/crypto/zvec.rs
+++ b/keystore2/src/crypto/zvec.rs
@@ -45,6 +45,7 @@
let v: Vec<u8> = vec![0; size];
let b = v.into_boxed_slice();
if size > 0 {
+ // SAFETY: The address range is part of our address space.
unsafe { mlock(b.as_ptr() as *const std::ffi::c_void, b.len()) }?;
}
Ok(Self { elems: b, len: size })
@@ -71,11 +72,16 @@
impl Drop for ZVec {
fn drop(&mut self) {
for i in 0..self.elems.len() {
- unsafe { write_volatile(self.elems.as_mut_ptr().add(i), 0) };
+ // SAFETY: The pointer is valid and properly aligned because it came from a reference.
+ unsafe { write_volatile(&mut self.elems[i], 0) };
}
if !self.elems.is_empty() {
if let Err(e) =
- unsafe { munlock(self.elems.as_ptr() as *const std::ffi::c_void, self.elems.len()) }
+ // SAFETY: The address range is part of our address space, and was previously locked
+ // by `mlock` in `ZVec::new` or the `TryFrom<Vec<u8>>` implementation.
+ unsafe {
+ munlock(self.elems.as_ptr() as *const std::ffi::c_void, self.elems.len())
+ }
{
log::error!("In ZVec::drop: `munlock` failed: {:?}.", e);
}
@@ -130,6 +136,7 @@
v.resize(v.capacity(), 0);
let b = v.into_boxed_slice();
if !b.is_empty() {
+ // SAFETY: The address range is part of our address space.
unsafe { mlock(b.as_ptr() as *const std::ffi::c_void, b.len()) }?;
}
Ok(Self { elems: b, len })
diff --git a/keystore2/src/enforcements.rs b/keystore2/src/enforcements.rs
index 8d5e985..3bf582f 100644
--- a/keystore2/src/enforcements.rs
+++ b/keystore2/src/enforcements.rs
@@ -51,9 +51,9 @@
/// An outstanding per operation authorization request.
OpAuth,
/// An outstanding request for per operation authorization and secure timestamp.
- TimeStampedOpAuth(Receiver<Result<TimeStampToken, Error>>),
+ TimeStampedOpAuth(Mutex<Receiver<Result<TimeStampToken, Error>>>),
/// An outstanding request for a timestamp token.
- TimeStamp(Receiver<Result<TimeStampToken, Error>>),
+ TimeStamp(Mutex<Receiver<Result<TimeStampToken, Error>>>),
}
#[derive(Debug)]
@@ -64,8 +64,6 @@
hat: Mutex<Option<HardwareAuthToken>>,
}
-unsafe impl Sync for AuthRequest {}
-
impl AuthRequest {
fn op_auth() -> Arc<Self> {
Arc::new(Self { state: AuthRequestState::OpAuth, hat: Mutex::new(None) })
@@ -73,7 +71,7 @@
fn timestamped_op_auth(receiver: Receiver<Result<TimeStampToken, Error>>) -> Arc<Self> {
Arc::new(Self {
- state: AuthRequestState::TimeStampedOpAuth(receiver),
+ state: AuthRequestState::TimeStampedOpAuth(Mutex::new(receiver)),
hat: Mutex::new(None),
})
}
@@ -82,7 +80,10 @@
hat: HardwareAuthToken,
receiver: Receiver<Result<TimeStampToken, Error>>,
) -> Arc<Self> {
- Arc::new(Self { state: AuthRequestState::TimeStamp(receiver), hat: Mutex::new(Some(hat)) })
+ Arc::new(Self {
+ state: AuthRequestState::TimeStamp(Mutex::new(receiver)),
+ hat: Mutex::new(Some(hat)),
+ })
}
fn add_auth_token(&self, hat: HardwareAuthToken) {
@@ -100,7 +101,11 @@
let tst = match &self.state {
AuthRequestState::TimeStampedOpAuth(recv) | AuthRequestState::TimeStamp(recv) => {
- let result = recv.recv().context("In get_auth_tokens: Sender disconnected.")?;
+ let result = recv
+ .lock()
+ .unwrap()
+ .recv()
+ .context("In get_auth_tokens: Sender disconnected.")?;
Some(result.context(ks_err!(
"Worker responded with error \
from generating timestamp token.",
diff --git a/keystore2/src/entropy.rs b/keystore2/src/entropy.rs
index de38187..1dcdc86 100644
--- a/keystore2/src/entropy.rs
+++ b/keystore2/src/entropy.rs
@@ -29,7 +29,7 @@
/// Register the entropy feeder as an idle callback.
pub fn register_feeder() {
crate::globals::ASYNC_TASK.add_idle(|shelf| {
- let mut info = shelf.get_mut::<FeederInfo>();
+ let info = shelf.get_mut::<FeederInfo>();
let now = Instant::now();
let feed_needed = match info.last_feed {
None => true,
diff --git a/keystore2/src/id_rotation.rs b/keystore2/src/id_rotation.rs
index 460caa7..5904047 100644
--- a/keystore2/src/id_rotation.rs
+++ b/keystore2/src/id_rotation.rs
@@ -26,7 +26,7 @@
use std::fs;
use std::io::ErrorKind;
use std::path::{Path, PathBuf};
-use std::time::Duration;
+use std::time::{Duration, SystemTime};
const ID_ROTATION_PERIOD: Duration = Duration::from_secs(30 * 24 * 60 * 60); // Thirty days.
static TIMESTAMP_FILE_NAME: &str = "timestamp";
@@ -36,6 +36,8 @@
/// and passed down to the users of the feature which can then query the timestamp on demand.
#[derive(Debug, Clone)]
pub struct IdRotationState {
+ /// We consider the time of last factory reset to be the point in time when this timestamp file
+ /// is created.
timestamp_path: PathBuf,
}
@@ -47,25 +49,41 @@
Self { timestamp_path }
}
- /// Reads the metadata of or creates the timestamp file. It returns true if the timestamp
- /// file is younger than `ID_ROTATION_PERIOD`, i.e., 30 days.
- pub fn had_factory_reset_since_id_rotation(&self) -> Result<bool> {
+ /// Returns true iff a factory reset has occurred since the last ID rotation.
+ pub fn had_factory_reset_since_id_rotation(
+ &self,
+ creation_datetime: &SystemTime,
+ ) -> Result<bool> {
match fs::metadata(&self.timestamp_path) {
Ok(metadata) => {
- let duration_since_factory_reset = metadata
- .modified()
- .context("File creation time not supported.")?
- .elapsed()
- .context("Failed to compute time elapsed since factory reset.")?;
- Ok(duration_since_factory_reset < ID_ROTATION_PERIOD)
+ // For Tag::UNIQUE_ID, temporal counter value is defined as Tag::CREATION_DATETIME
+ // divided by 2592000000, dropping any remainder. Temporal counter value is
+ // effectively the index of the ID rotation period that we are currently in, with
+ // each ID rotation period being 30 days.
+ let temporal_counter_value = creation_datetime
+ .duration_since(SystemTime::UNIX_EPOCH)
+ .context(ks_err!("Failed to get epoch time"))?
+ .as_millis()
+ / ID_ROTATION_PERIOD.as_millis();
+
+ // Calculate the beginning of the current ID rotation period, which is also the
+ // last time ID was rotated.
+ let id_rotation_time: SystemTime = SystemTime::UNIX_EPOCH
+ .checked_add(ID_ROTATION_PERIOD * temporal_counter_value.try_into()?)
+ .context(ks_err!("Failed to get ID rotation time."))?;
+
+ let factory_reset_time =
+ metadata.modified().context(ks_err!("File creation time not supported."))?;
+
+ Ok(id_rotation_time <= factory_reset_time)
}
Err(e) => match e.kind() {
ErrorKind::NotFound => {
fs::File::create(&self.timestamp_path)
- .context("Failed to create timestamp file.")?;
+ .context(ks_err!("Failed to create timestamp file."))?;
Ok(true)
}
- _ => Err(e).context("Failed to open timestamp file."),
+ _ => Err(e).context(ks_err!("Failed to open timestamp file.")),
},
}
.context(ks_err!())
@@ -78,47 +96,75 @@
use keystore2_test_utils::TempDir;
use nix::sys::stat::utimes;
use nix::sys::time::{TimeVal, TimeValLike};
- use std::convert::TryInto;
- use std::time::UNIX_EPOCH;
+ use std::thread::sleep;
- #[test]
- fn test_had_factory_reset_since_id_rotation() -> Result<()> {
- let temp_dir = TempDir::new("test_had_factory_reset_since_id_rotation_")
- .expect("Failed to create temp dir.");
+ static TEMP_DIR_NAME: &str = "test_had_factory_reset_since_id_rotation_";
+
+ fn set_up() -> (TempDir, PathBuf, IdRotationState) {
+ let temp_dir = TempDir::new(TEMP_DIR_NAME).expect("Failed to create temp dir.");
+ let mut timestamp_file_path = temp_dir.path().to_owned();
+ timestamp_file_path.push(TIMESTAMP_FILE_NAME);
let id_rotation_state = IdRotationState::new(temp_dir.path());
- let mut temp_file_path = temp_dir.path().to_owned();
- temp_file_path.push(TIMESTAMP_FILE_NAME);
+ (temp_dir, timestamp_file_path, id_rotation_state)
+ }
+
+ #[test]
+ fn test_timestamp_creation() {
+ let (_temp_dir, timestamp_file_path, id_rotation_state) = set_up();
+ let creation_datetime = SystemTime::now();
// The timestamp file should not exist.
- assert!(!temp_file_path.exists());
+ assert!(!timestamp_file_path.exists());
- // This should return true.
- assert!(id_rotation_state.had_factory_reset_since_id_rotation()?);
+ // Trigger timestamp file creation one second later.
+ sleep(Duration::new(1, 0));
+ assert!(id_rotation_state.had_factory_reset_since_id_rotation(&creation_datetime).unwrap());
// Now the timestamp file should exist.
- assert!(temp_file_path.exists());
+ assert!(timestamp_file_path.exists());
- // We should still return true because the timestamp file is young.
- assert!(id_rotation_state.had_factory_reset_since_id_rotation()?);
+ let metadata = fs::metadata(×tamp_file_path).unwrap();
+ assert!(metadata.modified().unwrap() > creation_datetime);
+ }
- // Now let's age the timestamp file by backdating the modification time.
- let metadata = fs::metadata(&temp_file_path)?;
- let mtime = metadata.modified()?;
- let mtime = mtime.duration_since(UNIX_EPOCH)?;
- let mtime =
- mtime.checked_sub(ID_ROTATION_PERIOD).expect("Failed to subtract id rotation period");
- let mtime = TimeVal::seconds(mtime.as_secs().try_into().unwrap());
+ #[test]
+ fn test_existing_timestamp() {
+ let (_temp_dir, timestamp_file_path, id_rotation_state) = set_up();
- let atime = metadata.accessed()?;
- let atime = atime.duration_since(UNIX_EPOCH)?;
- let atime = TimeVal::seconds(atime.as_secs().try_into().unwrap());
+ // Let's start with at a known point in time, so that it's easier to control which ID
+ // rotation period we're in.
+ let mut creation_datetime = SystemTime::UNIX_EPOCH;
- utimes(&temp_file_path, &atime, &mtime)?;
+ // Create timestamp file and backdate it back to Unix epoch.
+ fs::File::create(×tamp_file_path).unwrap();
+ let mtime = TimeVal::seconds(0);
+ let atime = TimeVal::seconds(0);
+ utimes(×tamp_file_path, &atime, &mtime).unwrap();
- // Now that the file has aged we should see false.
- assert!(!id_rotation_state.had_factory_reset_since_id_rotation()?);
+ // Timestamp file was backdated to the very beginning of the current ID rotation period.
+ // So, this should return true.
+ assert!(id_rotation_state.had_factory_reset_since_id_rotation(&creation_datetime).unwrap());
- Ok(())
+ // Move time forward, but stay in the same ID rotation period.
+ creation_datetime += Duration::from_millis(1);
+
+ // We should still return true because we're in the same ID rotation period.
+ assert!(id_rotation_state.had_factory_reset_since_id_rotation(&creation_datetime).unwrap());
+
+ // Move time to the next ID rotation period.
+ creation_datetime += ID_ROTATION_PERIOD;
+
+ // Now we should see false.
+ assert!(!id_rotation_state
+ .had_factory_reset_since_id_rotation(&creation_datetime)
+ .unwrap());
+
+ // Move timestamp to the future. This shouldn't ever happen, but even in this edge case ID
+ // must be rotated.
+ let mtime = TimeVal::seconds((ID_ROTATION_PERIOD.as_secs() * 10).try_into().unwrap());
+ let atime = TimeVal::seconds((ID_ROTATION_PERIOD.as_secs() * 10).try_into().unwrap());
+ utimes(×tamp_file_path, &atime, &mtime).unwrap();
+ assert!(id_rotation_state.had_factory_reset_since_id_rotation(&creation_datetime).unwrap());
}
}
diff --git a/keystore2/src/keystore2_main.rs b/keystore2/src/keystore2_main.rs
index 31c1e29..059d59d 100644
--- a/keystore2/src/keystore2_main.rs
+++ b/keystore2/src/keystore2_main.rs
@@ -68,6 +68,8 @@
fn sqlite_log_handler(err: c_int, message: &str) {
log::error!("[SQLITE3] {}: {}", err, message);
}
+ // SAFETY: There are no other threads yet, `sqlite_log_handler` is threadsafe, and it doesn't
+ // invoke any SQLite calls.
unsafe { sqlite_trace::config_log(Some(sqlite_log_handler)) }
.expect("Error setting sqlite log callback.");
diff --git a/keystore2/src/km_compat/lib.rs b/keystore2/src/km_compat/lib.rs
index 2632ec4..e61a13a 100644
--- a/keystore2/src/km_compat/lib.rs
+++ b/keystore2/src/km_compat/lib.rs
@@ -21,6 +21,7 @@
#[allow(missing_docs)] // TODO remove this
pub fn add_keymint_device_service() -> i32 {
+ // SAFETY: This is always safe to call.
unsafe { addKeyMintDeviceService() }
}
diff --git a/keystore2/src/maintenance.rs b/keystore2/src/maintenance.rs
index 73dc881..8c9ed63 100644
--- a/keystore2/src/maintenance.rs
+++ b/keystore2/src/maintenance.rs
@@ -178,7 +178,7 @@
(SecurityLevel::TRUSTED_ENVIRONMENT, "TRUSTED_ENVIRONMENT"),
(SecurityLevel::STRONGBOX, "STRONGBOX"),
];
- sec_levels.iter().fold(Ok(()), move |result, (sec_level, sec_level_string)| {
+ sec_levels.iter().try_fold((), |_result, (sec_level, sec_level_string)| {
let curr_result = Maintenance::call_with_watchdog(*sec_level, name, &op);
match curr_result {
Ok(()) => log::info!(
@@ -193,7 +193,7 @@
e
),
}
- result.and(curr_result)
+ curr_result
})
}
diff --git a/keystore2/src/security_level.rs b/keystore2/src/security_level.rs
index 5eed37c..db44d4b 100644
--- a/keystore2/src/security_level.rs
+++ b/keystore2/src/security_level.rs
@@ -405,8 +405,7 @@
) -> Result<Vec<KeyParameter>> {
let mut result = params.to_vec();
- // Unconditionally add the CREATION_DATETIME tag and prevent callers from
- // specifying it.
+ // Prevent callers from specifying the CREATION_DATETIME tag.
if params.iter().any(|kp| kp.tag == Tag::CREATION_DATETIME) {
return Err(Error::Rc(ResponseCode::INVALID_ARGUMENT)).context(ks_err!(
"KeystoreSecurityLevel::add_required_parameters: \
@@ -414,12 +413,16 @@
));
}
+ // Use this variable to refer to notion of "now". This eliminates discrepancies from
+ // quering the clock multiple times.
+ let creation_datetime = SystemTime::now();
+
// Add CREATION_DATETIME only if the backend version Keymint V1 (100) or newer.
if self.hw_info.versionNumber >= 100 {
result.push(KeyParameter {
tag: Tag::CREATION_DATETIME,
value: KeyParameterValue::DateTime(
- SystemTime::now()
+ creation_datetime
.duration_since(SystemTime::UNIX_EPOCH)
.context(ks_err!(
"KeystoreSecurityLevel::add_required_parameters: \
@@ -462,7 +465,7 @@
}
if self
.id_rotation_state
- .had_factory_reset_since_id_rotation()
+ .had_factory_reset_since_id_rotation(&creation_datetime)
.context(ks_err!("Call to had_factory_reset_since_id_rotation failed."))?
{
result.push(KeyParameter {
diff --git a/keystore2/src/super_key.rs b/keystore2/src/super_key.rs
index 2e8b60f..7fc3ed4 100644
--- a/keystore2/src/super_key.rs
+++ b/keystore2/src/super_key.rs
@@ -823,7 +823,7 @@
unlocking_sids: &[i64],
) {
log::info!("Locking screen bound for user {} sids {:?}", user_id, unlocking_sids);
- let mut entry = self.data.user_keys.entry(user_id).or_default();
+ let entry = self.data.user_keys.entry(user_id).or_default();
if !unlocking_sids.is_empty() {
if let (Some(aes), Some(ecdh)) = (
entry.screen_lock_bound.as_ref().cloned(),
@@ -899,7 +899,7 @@
db: &mut KeystoreDB,
user_id: UserId,
) -> Result<()> {
- let mut entry = self.data.user_keys.entry(user_id).or_default();
+ let entry = self.data.user_keys.entry(user_id).or_default();
if let Some(biometric) = entry.biometric_unlock.as_ref() {
let (key_id_guard, key_entry) = db
.load_key_entry(
diff --git a/keystore2/src/utils.rs b/keystore2/src/utils.rs
index acac7ee..584a51c 100644
--- a/keystore2/src/utils.rs
+++ b/keystore2/src/utils.rs
@@ -215,8 +215,8 @@
/// as an integer.
pub fn get_current_time_in_milliseconds() -> i64 {
let mut current_time = libc::timespec { tv_sec: 0, tv_nsec: 0 };
- // Following unsafe block includes one system call to get monotonic time.
- // Therefore, it is not considered harmful.
+ // SAFETY: The pointer is valid because it comes from a reference, and clock_gettime doesn't
+ // retain it beyond the call.
unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC_RAW, &mut current_time) };
current_time.tv_sec as i64 * 1000 + (current_time.tv_nsec as i64 / 1_000_000)
}
diff --git a/keystore2/test_utils/key_generations.rs b/keystore2/test_utils/key_generations.rs
index 0a1ffb1..0f9ecbe 100644
--- a/keystore2/test_utils/key_generations.rs
+++ b/keystore2/test_utils/key_generations.rs
@@ -46,6 +46,52 @@
/// Vold context
pub const TARGET_VOLD_CTX: &str = "u:r:vold:s0";
+/// Allowed tags in generated/imported key authorizations.
+/// See hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl for the
+/// list feature tags.
+/// Note: This list need to be updated whenever a new Tag is introduced and is expected to be added
+/// in key authorizations.
+pub const ALLOWED_TAGS_IN_KEY_AUTHS: &[Tag] = &[
+ Tag::ACTIVE_DATETIME,
+ Tag::ALGORITHM,
+ Tag::ALLOW_WHILE_ON_BODY,
+ Tag::AUTH_TIMEOUT,
+ Tag::BLOCK_MODE,
+ Tag::BOOTLOADER_ONLY,
+ Tag::BOOT_PATCHLEVEL,
+ Tag::CALLER_NONCE,
+ Tag::CREATION_DATETIME,
+ Tag::DIGEST,
+ Tag::EARLY_BOOT_ONLY,
+ Tag::EC_CURVE,
+ Tag::IDENTITY_CREDENTIAL_KEY,
+ Tag::INCLUDE_UNIQUE_ID,
+ Tag::KEY_SIZE,
+ Tag::MAX_BOOT_LEVEL,
+ Tag::MAX_USES_PER_BOOT,
+ Tag::MIN_MAC_LENGTH,
+ Tag::NO_AUTH_REQUIRED,
+ Tag::ORIGIN,
+ Tag::ORIGINATION_EXPIRE_DATETIME,
+ Tag::OS_PATCHLEVEL,
+ Tag::OS_VERSION,
+ Tag::PADDING,
+ Tag::PURPOSE,
+ Tag::ROLLBACK_RESISTANCE,
+ Tag::RSA_OAEP_MGF_DIGEST,
+ Tag::RSA_PUBLIC_EXPONENT,
+ Tag::STORAGE_KEY,
+ Tag::TRUSTED_CONFIRMATION_REQUIRED,
+ Tag::TRUSTED_USER_PRESENCE_REQUIRED,
+ Tag::UNLOCKED_DEVICE_REQUIRED,
+ Tag::USAGE_COUNT_LIMIT,
+ Tag::USAGE_EXPIRE_DATETIME,
+ Tag::USER_AUTH_TYPE,
+ Tag::USER_ID,
+ Tag::USER_SECURE_ID,
+ Tag::VENDOR_PATCHLEVEL,
+];
+
/// Key parameters to generate a key.
pub struct KeyParams {
/// Key Size.
@@ -337,6 +383,35 @@
})
}
+/// Verify that given key param is listed in given authorizations list.
+pub fn check_key_param(authorizations: &[Authorization], key_param: &KeyParameter) -> bool {
+ authorizations.iter().any(|auth| &auth.keyParameter == key_param)
+}
+
+fn check_key_authorizations(authorizations: &[Authorization], expected_params: &[KeyParameter]) {
+ // Make sure key authorizations contains only `ALLOWED_TAGS_IN_KEY_AUTHS`
+ authorizations.iter().all(|auth| {
+ assert!(
+ ALLOWED_TAGS_IN_KEY_AUTHS.contains(&auth.keyParameter.tag),
+ "key authorization is not allowed: {:#?}",
+ auth.keyParameter
+ );
+ true
+ });
+
+ //Check allowed-expected-key-parameters are present in given key authorizations list.
+ expected_params.iter().all(|key_param| {
+ if ALLOWED_TAGS_IN_KEY_AUTHS.contains(&key_param.tag) {
+ assert!(
+ check_key_param(authorizations, key_param),
+ "Key parameter not found: {:#?}",
+ key_param
+ );
+ }
+ true
+ });
+}
+
/// Generate EC Key using given security level and domain with below key parameters and
/// optionally allow the generated key to be attested with factory provisioned attest key using
/// given challenge and application id -
@@ -380,6 +455,7 @@
assert!(key_metadata.key.blob.is_some());
}
+ check_key_authorizations(&key_metadata.authorizations, &gen_params);
Ok(key_metadata)
}
Err(e) => Err(e),
@@ -422,6 +498,7 @@
} else {
assert!(key_metadata.key.blob.is_none());
}
+ check_key_authorizations(&key_metadata.authorizations, &gen_params);
Ok(key_metadata)
}
@@ -483,6 +560,19 @@
|| key_metadata.key.blob.is_none()
);
+ check_key_authorizations(&key_metadata.authorizations, &gen_params);
+ // If `RSA_OAEP_MGF_DIGEST` tag is not mentioned explicitly while generating/importing a key,
+ // then make sure `RSA_OAEP_MGF_DIGEST` tag with default value (SHA1) must not be included in
+ // key authorization list.
+ if key_params.mgf_digest.is_none() {
+ assert!(!check_key_param(
+ &key_metadata.authorizations,
+ &KeyParameter {
+ tag: Tag::RSA_OAEP_MGF_DIGEST,
+ value: KeyParameterValue::Digest(Digest::SHA1)
+ }
+ ));
+ }
Ok(key_metadata)
}
@@ -527,6 +617,7 @@
// Should not have an attestation record.
assert!(key_metadata.certificateChain.is_none());
+ check_key_authorizations(&key_metadata.authorizations, &gen_params);
Ok(key_metadata)
}
@@ -566,6 +657,7 @@
// Should not have an attestation record.
assert!(key_metadata.certificateChain.is_none());
+ check_key_authorizations(&key_metadata.authorizations, &gen_params);
Ok(key_metadata)
}
@@ -650,6 +742,7 @@
// Should have an attestation record.
assert!(attestation_key_metadata.certificateChain.is_some());
+ check_key_authorizations(&attestation_key_metadata.authorizations, &gen_params);
Ok(attestation_key_metadata)
}
@@ -684,20 +777,10 @@
// Shouldn't have an attestation record.
assert!(ec_key_metadata.certificateChain.is_none());
+ check_key_authorizations(&ec_key_metadata.authorizations, &ec_gen_params);
Ok(ec_key_metadata)
}
-/// Verify that given key param is listed in given authorizations list.
-pub fn check_key_param(authorizations: &[Authorization], key_param: KeyParameter) -> bool {
- for authrization in authorizations {
- if authrization.keyParameter == key_param {
- return true;
- }
- }
-
- false
-}
-
/// Imports above defined RSA key - `RSA_2048_KEY` and validates imported key parameters.
pub fn import_rsa_2048_key(
sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
@@ -719,24 +802,27 @@
assert!(key_metadata.certificate.is_some());
assert!(key_metadata.certificateChain.is_none());
+ check_key_authorizations(&key_metadata.authorizations, &import_params);
+
+ // Check below auths explicitly, they might not be addd in import parameters.
assert!(check_key_param(
&key_metadata.authorizations,
- KeyParameter { tag: Tag::ALGORITHM, value: KeyParameterValue::Algorithm(Algorithm::RSA) }
+ &KeyParameter { tag: Tag::ALGORITHM, value: KeyParameterValue::Algorithm(Algorithm::RSA) }
));
assert!(check_key_param(
&key_metadata.authorizations,
- KeyParameter { tag: Tag::KEY_SIZE, value: KeyParameterValue::Integer(2048) }
+ &KeyParameter { tag: Tag::KEY_SIZE, value: KeyParameterValue::Integer(2048) }
));
assert!(check_key_param(
&key_metadata.authorizations,
- KeyParameter { tag: Tag::DIGEST, value: KeyParameterValue::Digest(Digest::SHA_2_256) }
+ &KeyParameter { tag: Tag::DIGEST, value: KeyParameterValue::Digest(Digest::SHA_2_256) }
));
assert!(check_key_param(
&key_metadata.authorizations,
- KeyParameter {
+ &KeyParameter {
tag: Tag::RSA_PUBLIC_EXPONENT,
value: KeyParameterValue::LongInteger(65537)
}
@@ -744,7 +830,7 @@
assert!(check_key_param(
&key_metadata.authorizations,
- KeyParameter {
+ &KeyParameter {
tag: Tag::PADDING,
value: KeyParameterValue::PaddingMode(PaddingMode::RSA_PSS)
}
@@ -752,7 +838,7 @@
assert!(check_key_param(
&key_metadata.authorizations,
- KeyParameter { tag: Tag::ORIGIN, value: KeyParameterValue::Origin(KeyOrigin::IMPORTED) }
+ &KeyParameter { tag: Tag::ORIGIN, value: KeyParameterValue::Origin(KeyOrigin::IMPORTED) }
));
Ok(key_metadata)
@@ -779,23 +865,26 @@
assert!(key_metadata.certificate.is_some());
assert!(key_metadata.certificateChain.is_none());
+ check_key_authorizations(&key_metadata.authorizations, &import_params);
+
+ // Check below auths explicitly, they might not be addd in import parameters.
assert!(check_key_param(
&key_metadata.authorizations,
- KeyParameter { tag: Tag::ALGORITHM, value: KeyParameterValue::Algorithm(Algorithm::EC) }
+ &KeyParameter { tag: Tag::ALGORITHM, value: KeyParameterValue::Algorithm(Algorithm::EC) }
));
assert!(check_key_param(
&key_metadata.authorizations,
- KeyParameter { tag: Tag::EC_CURVE, value: KeyParameterValue::EcCurve(EcCurve::P_256) }
+ &KeyParameter { tag: Tag::EC_CURVE, value: KeyParameterValue::EcCurve(EcCurve::P_256) }
));
assert!(check_key_param(
&key_metadata.authorizations,
- KeyParameter { tag: Tag::DIGEST, value: KeyParameterValue::Digest(Digest::SHA_2_256) }
+ &KeyParameter { tag: Tag::DIGEST, value: KeyParameterValue::Digest(Digest::SHA_2_256) }
));
assert!(check_key_param(
&key_metadata.authorizations,
- KeyParameter { tag: Tag::ORIGIN, value: KeyParameterValue::Origin(KeyOrigin::IMPORTED) }
+ &KeyParameter { tag: Tag::ORIGIN, value: KeyParameterValue::Origin(KeyOrigin::IMPORTED) }
));
Ok(key_metadata)
@@ -828,28 +917,31 @@
AES_KEY,
)?;
+ check_key_authorizations(&key_metadata.authorizations, &import_params);
+
+ // Check below auths explicitly, they might not be addd in import parameters.
assert!(check_key_param(
&key_metadata.authorizations,
- KeyParameter { tag: Tag::ALGORITHM, value: KeyParameterValue::Algorithm(Algorithm::AES) }
+ &KeyParameter { tag: Tag::ALGORITHM, value: KeyParameterValue::Algorithm(Algorithm::AES) }
));
assert!(check_key_param(
&key_metadata.authorizations,
- KeyParameter { tag: Tag::KEY_SIZE, value: KeyParameterValue::Integer(128) }
+ &KeyParameter { tag: Tag::KEY_SIZE, value: KeyParameterValue::Integer(128) }
));
assert!(check_key_param(
&key_metadata.authorizations,
- KeyParameter {
+ &KeyParameter {
tag: Tag::PADDING,
value: KeyParameterValue::PaddingMode(PaddingMode::PKCS7)
}
));
assert!(check_key_param(
&key_metadata.authorizations,
- KeyParameter { tag: Tag::BLOCK_MODE, value: KeyParameterValue::BlockMode(BlockMode::ECB) }
+ &KeyParameter { tag: Tag::BLOCK_MODE, value: KeyParameterValue::BlockMode(BlockMode::ECB) }
));
assert!(check_key_param(
&key_metadata.authorizations,
- KeyParameter { tag: Tag::ORIGIN, value: KeyParameterValue::Origin(KeyOrigin::IMPORTED) }
+ &KeyParameter { tag: Tag::ORIGIN, value: KeyParameterValue::Origin(KeyOrigin::IMPORTED) }
));
Ok(key_metadata)
@@ -884,31 +976,34 @@
TRIPLE_DES_KEY,
)?;
+ check_key_authorizations(&key_metadata.authorizations, &import_params);
+
+ // Check below auths explicitly, they might not be addd in import parameters.
assert!(check_key_param(
&key_metadata.authorizations,
- KeyParameter {
+ &KeyParameter {
tag: Tag::ALGORITHM,
value: KeyParameterValue::Algorithm(Algorithm::TRIPLE_DES)
}
));
assert!(check_key_param(
&key_metadata.authorizations,
- KeyParameter { tag: Tag::KEY_SIZE, value: KeyParameterValue::Integer(168) }
+ &KeyParameter { tag: Tag::KEY_SIZE, value: KeyParameterValue::Integer(168) }
));
assert!(check_key_param(
&key_metadata.authorizations,
- KeyParameter {
+ &KeyParameter {
tag: Tag::PADDING,
value: KeyParameterValue::PaddingMode(PaddingMode::PKCS7)
}
));
assert!(check_key_param(
&key_metadata.authorizations,
- KeyParameter { tag: Tag::BLOCK_MODE, value: KeyParameterValue::BlockMode(BlockMode::ECB) }
+ &KeyParameter { tag: Tag::BLOCK_MODE, value: KeyParameterValue::BlockMode(BlockMode::ECB) }
));
assert!(check_key_param(
&key_metadata.authorizations,
- KeyParameter { tag: Tag::ORIGIN, value: KeyParameterValue::Origin(KeyOrigin::IMPORTED) }
+ &KeyParameter { tag: Tag::ORIGIN, value: KeyParameterValue::Origin(KeyOrigin::IMPORTED) }
));
Ok(key_metadata)
@@ -941,21 +1036,24 @@
HMAC_KEY,
)?;
+ check_key_authorizations(&key_metadata.authorizations, &import_params);
+
+ // Check below auths explicitly, they might not be addd in import parameters.
assert!(check_key_param(
&key_metadata.authorizations,
- KeyParameter { tag: Tag::ALGORITHM, value: KeyParameterValue::Algorithm(Algorithm::HMAC) }
+ &KeyParameter { tag: Tag::ALGORITHM, value: KeyParameterValue::Algorithm(Algorithm::HMAC) }
));
assert!(check_key_param(
&key_metadata.authorizations,
- KeyParameter { tag: Tag::KEY_SIZE, value: KeyParameterValue::Integer(128) }
+ &KeyParameter { tag: Tag::KEY_SIZE, value: KeyParameterValue::Integer(128) }
));
assert!(check_key_param(
&key_metadata.authorizations,
- KeyParameter { tag: Tag::DIGEST, value: KeyParameterValue::Digest(Digest::SHA_2_256) }
+ &KeyParameter { tag: Tag::DIGEST, value: KeyParameterValue::Digest(Digest::SHA_2_256) }
));
assert!(check_key_param(
&key_metadata.authorizations,
- KeyParameter { tag: Tag::ORIGIN, value: KeyParameterValue::Origin(KeyOrigin::IMPORTED) }
+ &KeyParameter { tag: Tag::ORIGIN, value: KeyParameterValue::Origin(KeyOrigin::IMPORTED) }
));
Ok(key_metadata)
@@ -1090,6 +1188,7 @@
assert!(key_metadata.key.blob.is_some());
}
+ check_key_authorizations(&key_metadata.authorizations, &gen_params);
Ok(key_metadata)
}
Err(e) => Err(e),
diff --git a/keystore2/test_utils/run_as.rs b/keystore2/test_utils/run_as.rs
index 2485ab5..be643b6 100644
--- a/keystore2/test_utils/run_as.rs
+++ b/keystore2/test_utils/run_as.rs
@@ -255,7 +255,9 @@
let (response_reader, mut response_writer) =
pipe_channel().expect("Failed to create cmd pipe.");
- match fork() {
+ // SAFETY: Our caller guarantees that the process only has a single thread, so calling
+ // non-async-signal-safe functions in the child is in fact safe.
+ match unsafe { fork() } {
Ok(ForkResult::Parent { child, .. }) => {
drop(response_writer);
drop(cmd_reader);
@@ -314,7 +316,9 @@
selinux::Context::new(se_context).expect("Unable to construct selinux::Context.");
let (mut reader, mut writer) = pipe_channel::<R>().expect("Failed to create pipe.");
- match fork() {
+ // SAFETY: Our caller guarantees that the process only has a single thread, so calling
+ // non-async-signal-safe functions in the child is in fact safe.
+ match unsafe { fork() } {
Ok(ForkResult::Parent { child, .. }) => {
drop(writer);
let status = waitpid(child, None).expect("Failed while waiting for child.");
diff --git a/keystore2/tests/keystore2_client_ec_key_tests.rs b/keystore2/tests/keystore2_client_ec_key_tests.rs
index c2034de..8267140 100644
--- a/keystore2/tests/keystore2_client_ec_key_tests.rs
+++ b/keystore2/tests/keystore2_client_ec_key_tests.rs
@@ -432,15 +432,18 @@
// Client#1: Generate a key and create an operation using generated key.
// Wait until the parent notifies to continue. Once the parent notifies, this operation
// is expected to be completed successfully.
- let mut child_handle = execute_op_run_as_child(
- TARGET_CTX,
- Domain::APP,
- -1,
- Some(alias.to_string()),
- Uid::from_raw(uid1),
- Gid::from_raw(gid1),
- ForcedOp(false),
- );
+ // SAFETY: The test is run in a separate process with no other threads.
+ let mut child_handle = unsafe {
+ execute_op_run_as_child(
+ TARGET_CTX,
+ Domain::APP,
+ -1,
+ Some(alias.to_string()),
+ Uid::from_raw(uid1),
+ Gid::from_raw(gid1),
+ ForcedOp(false),
+ )
+ };
// Wait until (client#1) child process notifies us to continue, so that there will be a key
// generated by client#1.
@@ -450,6 +453,7 @@
const APPLICATION_ID_2: u32 = 10602;
let uid2 = USER_ID * AID_USER_OFFSET + APPLICATION_ID_2;
let gid2 = USER_ID * AID_USER_OFFSET + APPLICATION_ID_2;
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(TARGET_CTX, Uid::from_raw(uid2), Gid::from_raw(gid2), move || {
let keystore2_inst = get_keystore_service();
diff --git a/keystore2/tests/keystore2_client_grant_key_tests.rs b/keystore2/tests/keystore2_client_grant_key_tests.rs
index bde872d..516869a 100644
--- a/keystore2/tests/keystore2_client_grant_key_tests.rs
+++ b/keystore2/tests/keystore2_client_grant_key_tests.rs
@@ -114,6 +114,7 @@
static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
static GRANTEE_GID: u32 = GRANTEE_UID;
+ // SAFETY: The test is run in a separate process with no other threads.
let grant_key_nspace = unsafe {
run_as::run_as(TARGET_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
let empty_access_vector = KeyPermission::NONE.0;
@@ -132,6 +133,7 @@
// In grantee context try to load the key, it should fail to load the granted key as it is
// granted with empty access vector.
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(
GRANTEE_CTX,
@@ -169,6 +171,7 @@
static GRANTEE_GID: u32 = GRANTEE_UID;
// Generate a key and grant it to a user with GET_INFO|USE key permissions.
+ // SAFETY: The test is run in a separate process with no other threads.
let grant_key_nspace = unsafe {
run_as::run_as(TARGET_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
let access_vector = KeyPermission::GET_INFO.0 | KeyPermission::USE.0;
@@ -185,6 +188,7 @@
};
// In grantee context load the key and try to perform crypto operation.
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(
GRANTEE_CTX,
@@ -251,6 +255,7 @@
static ALIAS: &str = "ks_grant_key_delete_success";
// Generate a key and grant it to a user with DELETE permission.
+ // SAFETY: The test is run in a separate process with no other threads.
let grant_key_nspace = unsafe {
run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
let keystore2 = get_keystore_service();
@@ -270,6 +275,7 @@
};
// Grantee context, delete the key.
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(
GRANTEE_CTX,
@@ -290,6 +296,7 @@
};
// Verify whether key got deleted in grantor's context.
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), move || {
let keystore2_inst = get_keystore_service();
@@ -325,6 +332,7 @@
static SEC_GRANTEE_GID: u32 = SEC_GRANTEE_UID;
// Generate a key and grant it to a user with GET_INFO permission.
+ // SAFETY: The test is run in a separate process with no other threads.
let grant_key_nspace = unsafe {
run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
let keystore2 = get_keystore_service();
@@ -345,6 +353,7 @@
};
// Grantee context, load the granted key and try to grant it to `SEC_GRANTEE_UID` grantee.
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(
GRANTEE_CTX,
@@ -375,6 +384,7 @@
};
// Make sure second grantee shouldn't have access to the above granted key.
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(
GRANTEE_CTX,
@@ -457,6 +467,7 @@
static GRANTEE_GID: u32 = GRANTEE_UID;
// Generate a key and grant it to a user with GET_INFO permission.
+ // SAFETY: The test is run in a separate process with no other threads.
let grant_key_nspace = unsafe {
run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
let keystore2 = get_keystore_service();
@@ -492,6 +503,7 @@
};
// Grantee context, try to load the ungranted key.
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(
GRANTEE_CTX,
@@ -527,6 +539,7 @@
static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
static GRANTEE_GID: u32 = GRANTEE_UID;
+ // SAFETY: The test is run in a separate process with no other threads.
let grant_key_nspace = unsafe {
run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
let keystore2 = get_keystore_service();
@@ -576,6 +589,7 @@
// Make sure grant did not persist, try to access the earlier granted key in grantee context.
// Grantee context should fail to load the granted key as its associated key is deleted in
// grantor context.
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(
GRANTEE_CTX,
@@ -614,6 +628,7 @@
static GRANTEE_2_GID: u32 = GRANTEE_2_UID;
// Generate a key and grant it to multiple users with GET_INFO|USE permissions.
+ // SAFETY: The test is run in a separate process with no other threads.
let mut grant_keys = unsafe {
run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
let keystore2 = get_keystore_service();
@@ -636,6 +651,7 @@
&[(GRANTEE_1_UID, GRANTEE_1_GID), (GRANTEE_2_UID, GRANTEE_2_GID)]
{
let grant_key_nspace = grant_keys.remove(0);
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(
GRANTEE_CTX,
@@ -678,6 +694,7 @@
static GRANTEE_2_GID: u32 = GRANTEE_2_UID;
// Generate a key and grant it to multiple users with GET_INFO permission.
+ // SAFETY: The test is run in a separate process with no other threads.
let mut grant_keys = unsafe {
run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
let keystore2 = get_keystore_service();
@@ -699,6 +716,7 @@
// Grantee #1 context
let grant_key1_nspace = grant_keys.remove(0);
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(
GRANTEE_CTX,
@@ -733,6 +751,7 @@
// Grantee #2 context
let grant_key2_nspace = grant_keys.remove(0);
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(
GRANTEE_CTX,
diff --git a/keystore2/tests/keystore2_client_keystore_engine_tests.rs b/keystore2/tests/keystore2_client_keystore_engine_tests.rs
index 1aed8e6..339eb60 100644
--- a/keystore2/tests/keystore2_client_keystore_engine_tests.rs
+++ b/keystore2/tests/keystore2_client_keystore_engine_tests.rs
@@ -167,6 +167,7 @@
static GRANTEE_GID: u32 = GRANTEE_UID;
// Generate a key and grant it to a user with GET_INFO|USE|DELETE key permissions.
+ // SAFETY: The test is run in a separate process with no other threads.
let grant_key_nspace = unsafe {
run_as::run_as(TARGET_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
let keystore2 = get_keystore_service();
@@ -184,6 +185,7 @@
};
// In grantee context load the key and try to perform crypto operation.
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(
GRANTEE_CTX,
@@ -208,6 +210,7 @@
static GRANTEE_GID: u32 = GRANTEE_UID;
// Generate a key and grant it to a user with GET_INFO|USE|DELETE key permissions.
+ // SAFETY: The test is run in a separate process with no other threads.
let grant_key_nspace = unsafe {
run_as::run_as(TARGET_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
let keystore2 = get_keystore_service();
@@ -225,6 +228,7 @@
};
// In grantee context load the key and try to perform crypto operation.
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(
GRANTEE_CTX,
@@ -250,6 +254,7 @@
// Generate a key and re-encode it's certificate as PEM and update it and
// grant it to a user with GET_INFO|USE|DELETE key permissions.
+ // SAFETY: The test is run in a separate process with no other threads.
let grant_key_nspace = unsafe {
run_as::run_as(TARGET_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
let keystore2 = get_keystore_service();
@@ -285,6 +290,7 @@
};
// In grantee context load the key and try to perform crypto operation.
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(
GRANTEE_CTX,
diff --git a/keystore2/tests/keystore2_client_list_entries_tests.rs b/keystore2/tests/keystore2_client_list_entries_tests.rs
index 809c01f..1c0c496 100644
--- a/keystore2/tests/keystore2_client_list_entries_tests.rs
+++ b/keystore2/tests/keystore2_client_list_entries_tests.rs
@@ -60,6 +60,7 @@
static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
static GRANTEE_GID: u32 = GRANTEE_UID;
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
let keystore2 = get_keystore_service();
@@ -113,6 +114,7 @@
};
// In user context validate list of key entries associated with it.
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(
GRANTEE_CTX,
@@ -161,6 +163,7 @@
let agid = 91 * AID_USER_OFFSET + 10001;
static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(TARGET_CTX, Uid::from_raw(auid), Gid::from_raw(agid), move || {
let keystore2 = get_keystore_service();
@@ -198,6 +201,7 @@
static CLIENT_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
static CLIENT_GID: u32 = CLIENT_UID;
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(CLIENT_CTX, Uid::from_raw(CLIENT_UID), Gid::from_raw(CLIENT_GID), || {
let keystore2 = get_keystore_service();
@@ -264,6 +268,7 @@
static CLIENT_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
static CLIENT_GID: u32 = CLIENT_UID;
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(CLIENT_CTX, Uid::from_raw(CLIENT_UID), Gid::from_raw(CLIENT_GID), || {
let keystore2 = get_keystore_service();
@@ -331,6 +336,7 @@
static CLIENT_GID: u32 = CLIENT_UID;
static ALIAS_PREFIX: &str = "key_test_batch_list";
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(CLIENT_CTX, Uid::from_raw(CLIENT_UID), Gid::from_raw(CLIENT_GID), || {
let keystore2 = get_keystore_service();
@@ -361,6 +367,7 @@
})
};
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(CLIENT_CTX, Uid::from_raw(CLIENT_UID), Gid::from_raw(CLIENT_GID), || {
let keystore2 = get_keystore_service();
@@ -428,6 +435,7 @@
static CLIENT_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
static CLIENT_GID: u32 = CLIENT_UID;
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(CLIENT_CTX, Uid::from_raw(CLIENT_UID), Gid::from_raw(CLIENT_GID), || {
let keystore2 = get_keystore_service();
@@ -511,6 +519,7 @@
static CLIENT_GID: u32 = CLIENT_UID;
static ALIAS_PREFIX: &str = "key_test_batch_list";
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(CLIENT_CTX, Uid::from_raw(CLIENT_UID), Gid::from_raw(CLIENT_GID), || {
let keystore2 = get_keystore_service();
@@ -647,6 +656,7 @@
let agid = 91 * AID_USER_OFFSET + 10001;
static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(TARGET_CTX, Uid::from_raw(auid), Gid::from_raw(agid), move || {
let keystore2 = get_keystore_service();
@@ -686,6 +696,7 @@
let agid = 91 * AID_USER_OFFSET + 10001;
static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(TARGET_CTX, Uid::from_raw(auid), Gid::from_raw(agid), move || {
let keystore2 = get_keystore_service();
diff --git a/keystore2/tests/keystore2_client_operation_tests.rs b/keystore2/tests/keystore2_client_operation_tests.rs
index 19175dd..89b5a31 100644
--- a/keystore2/tests/keystore2_client_operation_tests.rs
+++ b/keystore2/tests/keystore2_client_operation_tests.rs
@@ -36,7 +36,11 @@
/// Create `max_ops` number child processes with the given context and perform an operation under each
/// child process.
-pub fn create_operations(
+///
+/// # Safety
+///
+/// Must be called from a process with no other threads.
+pub unsafe fn create_operations(
target_ctx: &'static str,
forced_op: ForcedOp,
max_ops: i32,
@@ -45,7 +49,8 @@
let base_gid = 99 * AID_USER_OFFSET + 10001;
let base_uid = 99 * AID_USER_OFFSET + 10001;
(0..max_ops)
- .map(|i| {
+ // SAFETY: The caller guarantees that there are no other threads.
+ .map(|i| unsafe {
execute_op_run_as_child(
target_ctx,
Domain::APP,
@@ -87,7 +92,8 @@
const MAX_OPS: i32 = 100;
static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
- let mut child_handles = create_operations(TARGET_CTX, ForcedOp(false), MAX_OPS);
+ // SAFETY: The test is run in a separate process with no other threads.
+ let mut child_handles = unsafe { create_operations(TARGET_CTX, ForcedOp(false), MAX_OPS) };
// Wait until all child procs notifies us to continue,
// so that there are definitely enough operations outstanding to trigger a BACKEND_BUSY.
@@ -120,7 +126,8 @@
static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
// Create regular operations.
- let mut child_handles = create_operations(TARGET_CTX, ForcedOp(false), MAX_OPS);
+ // SAFETY: The test is run in a separate process with no other threads.
+ let mut child_handles = unsafe { create_operations(TARGET_CTX, ForcedOp(false), MAX_OPS) };
// Wait until all child procs notifies us to continue, so that there are enough
// operations outstanding to trigger a BACKEND_BUSY.
@@ -131,6 +138,7 @@
// Create a forced operation.
let auid = 99 * AID_USER_OFFSET + 10604;
let agid = 99 * AID_USER_OFFSET + 10604;
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(
key_generations::TARGET_VOLD_CTX,
@@ -203,15 +211,18 @@
// Create initial forced operation in a child process
// and wait for the parent to notify to perform operation.
let alias = format!("ks_forced_op_key_{}", getuid());
- let mut first_op_handle = execute_op_run_as_child(
- key_generations::TARGET_SU_CTX,
- Domain::SELINUX,
- key_generations::SELINUX_SHELL_NAMESPACE,
- Some(alias),
- Uid::from_raw(auid),
- Gid::from_raw(agid),
- ForcedOp(true),
- );
+ // SAFETY: The test is run in a separate process with no other threads.
+ let mut first_op_handle = unsafe {
+ execute_op_run_as_child(
+ key_generations::TARGET_SU_CTX,
+ Domain::SELINUX,
+ key_generations::SELINUX_SHELL_NAMESPACE,
+ Some(alias),
+ Uid::from_raw(auid),
+ Gid::from_raw(agid),
+ ForcedOp(true),
+ )
+ };
// Wait until above child proc notifies us to continue, so that there is definitely a forced
// operation outstanding to perform a operation.
@@ -219,7 +230,8 @@
// Create MAX_OPS number of forced operations.
let mut child_handles =
- create_operations(key_generations::TARGET_SU_CTX, ForcedOp(true), MAX_OPS);
+ // SAFETY: The test is run in a separate process with no other threads.
+ unsafe { create_operations(key_generations::TARGET_SU_CTX, ForcedOp(true), MAX_OPS) };
// Wait until all child procs notifies us to continue, so that there are enough operations
// outstanding to trigger a BACKEND_BUSY.
@@ -282,15 +294,18 @@
// Create an operation in an untrusted_app context. Wait until the parent notifies to continue.
// Once the parent notifies, this operation is expected to be completed successfully.
let alias = format!("ks_reg_op_key_{}", getuid());
- let mut child_handle = execute_op_run_as_child(
- TARGET_CTX,
- Domain::APP,
- -1,
- Some(alias),
- Uid::from_raw(uid),
- Gid::from_raw(gid),
- ForcedOp(false),
- );
+ // SAFETY: The test is run in a separate process with no other threads.
+ let mut child_handle = unsafe {
+ execute_op_run_as_child(
+ TARGET_CTX,
+ Domain::APP,
+ -1,
+ Some(alias),
+ Uid::from_raw(uid),
+ Gid::from_raw(gid),
+ ForcedOp(false),
+ )
+ };
// Wait until child process notifies us to continue, so that an operation from child process is
// outstanding to complete the operation.
@@ -377,6 +392,7 @@
let gid = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
for context in TARGET_CTXS.iter() {
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(context, Uid::from_raw(uid), Gid::from_raw(gid), move || {
let alias = format!("ks_app_forced_op_test_key_{}", getuid());
@@ -406,6 +422,7 @@
let uid = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
let gid = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(TARGET_CTX, Uid::from_raw(uid), Gid::from_raw(gid), move || {
let alias = format!("ks_vold_forced_op_key_{}", getuid());
diff --git a/keystore2/tests/keystore2_client_test_utils.rs b/keystore2/tests/keystore2_client_test_utils.rs
index 3354798..f7e7985 100644
--- a/keystore2/tests/keystore2_client_test_utils.rs
+++ b/keystore2/tests/keystore2_client_test_utils.rs
@@ -266,7 +266,11 @@
}
/// Create new operation on child proc and perform simple operation after parent notification.
-pub fn execute_op_run_as_child(
+///
+/// # Safety
+///
+/// Must only be called from a single-threaded process.
+pub unsafe fn execute_op_run_as_child(
target_ctx: &'static str,
domain: Domain,
nspace: i64,
@@ -275,6 +279,7 @@
agid: Gid,
forced_op: ForcedOp,
) -> run_as::ChildHandle<TestOutcome, BarrierReached> {
+ // SAFETY: The caller guarantees that there are no other threads.
unsafe {
run_as::run_as_child(target_ctx, auid, agid, move |reader, writer| {
let result = key_generations::map_ks_error(create_signing_operation(
diff --git a/keystore2/tests/keystore2_client_update_subcomponent_tests.rs b/keystore2/tests/keystore2_client_update_subcomponent_tests.rs
index 0be092f..d9576a8 100644
--- a/keystore2/tests/keystore2_client_update_subcomponent_tests.rs
+++ b/keystore2/tests/keystore2_client_update_subcomponent_tests.rs
@@ -167,6 +167,7 @@
static GRANTEE_2_GID: u32 = GRANTEE_2_UID;
// Generate a key and grant it to multiple users with different access permissions.
+ // SAFETY: The test is run in a separate process with no other threads.
let mut granted_keys = unsafe {
run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
let keystore2 = get_keystore_service();
@@ -205,6 +206,7 @@
// Grantee context, try to update the key public certs, permission denied error is expected.
let granted_key1_nspace = granted_keys.remove(0);
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(
GRANTEE_CTX,
@@ -234,6 +236,7 @@
// Grantee context, update granted key public certs. Update should happen successfully.
let granted_key2_nspace = granted_keys.remove(0);
+ // SAFETY: The test is run in a separate process with no other threads.
unsafe {
run_as::run_as(
GRANTEE_CTX,
diff --git a/prng_seeder/src/cutils_socket.rs b/prng_seeder/src/cutils_socket.rs
index ab2c869..b408be6 100644
--- a/prng_seeder/src/cutils_socket.rs
+++ b/prng_seeder/src/cutils_socket.rs
@@ -19,7 +19,11 @@
pub fn android_get_control_socket(name: &str) -> Result<UnixListener> {
let name = CString::new(name)?;
+ // SAFETY: name is a valid C string, and android_get_control_socket doesn't retain it after it
+ // returns.
let fd = unsafe { cutils_socket_bindgen::android_get_control_socket(name.as_ptr()) };
ensure!(fd >= 0, "android_get_control_socket failed");
+ // SAFETY: android_get_control_socket either returns a valid and open FD or -1, and we checked
+ // that it's not -1.
Ok(unsafe { UnixListener::from_raw_fd(fd) })
}
diff --git a/prng_seeder/src/drbg.rs b/prng_seeder/src/drbg.rs
index 89c5a88..808ea18 100644
--- a/prng_seeder/src/drbg.rs
+++ b/prng_seeder/src/drbg.rs
@@ -23,6 +23,9 @@
impl Drbg {
pub fn new(entropy: &Entropy) -> Result<Drbg> {
+ // SAFETY: entropy must be a valid pointer because it comes from a reference, and a null
+ // pointer is allowed for personalization. CTR_DRBG_new doesn't retain the entropy pointer
+ // for use after it returns.
let p = unsafe { bssl_sys::CTR_DRBG_new(entropy.as_ptr(), std::ptr::null(), 0) };
ensure!(!p.is_null(), "CTR_DRBG_new failed");
Ok(Drbg(p))
@@ -30,6 +33,9 @@
pub fn reseed(&mut self, entropy: &Entropy) -> Result<()> {
ensure!(
+ // SAFETY: We know that self.0 is valid because it was initialised from CTR_DRBG_new in
+ // Drbg::new above. The entropy pointer must be valid because it comes from a reference,
+ // and CTR_DRBG_reseed doesn't retain it after it returns.
unsafe { bssl_sys::CTR_DRBG_reseed(self.0, entropy.as_ptr(), std::ptr::null(), 0) }
== 1,
"CTR_DRBG_reseed failed"
@@ -39,6 +45,10 @@
pub fn generate(&mut self, buf: &mut [u8]) -> Result<()> {
ensure!(
+ // SAFETY: We know that self.0 is valid because it was initialised from CTR_DRBG_new in
+ // Drbg::new above. The out pointer and length must be valid and unaliased because they
+ // come from a mutable slice reference, and CTR_DRBG_generate doesn't retain them after
+ // it returns.
unsafe {
bssl_sys::CTR_DRBG_generate(
self.0,
@@ -56,10 +66,13 @@
impl Drop for Drbg {
fn drop(&mut self) {
+ // SAFETY: We know that self.0 is valid because it was initialised from CTR_DRBG_new in
+ // Drbg::new above, and this is the only place that frees it.
unsafe {
bssl_sys::CTR_DRBG_free(self.0);
}
}
}
+// SAFETY: CTR_DRBG functions can be called from any thread.
unsafe impl Send for Drbg {}
diff --git a/prng_seeder/src/main.rs b/prng_seeder/src/main.rs
index 924481a..f8b0c63 100644
--- a/prng_seeder/src/main.rs
+++ b/prng_seeder/src/main.rs
@@ -70,6 +70,7 @@
fn setup() -> Result<(ConditionerBuilder, UnixListener)> {
configure_logging()?;
let cli = Cli::try_parse()?;
+ // SAFETY: Nothing else sets the signal handler, so either it was set here or it is the default.
unsafe { signal::signal(signal::Signal::SIGPIPE, signal::SigHandler::SigIgn) }
.context("In setup, setting SIGPIPE to SIG_IGN")?;
diff --git a/provisioner/Android.bp b/provisioner/Android.bp
index 7d3549e..605abb4 100644
--- a/provisioner/Android.bp
+++ b/provisioner/Android.bp
@@ -29,18 +29,20 @@
"keymint_use_latest_hal_aidl_ndk_static",
],
shared_libs: [
- "libbinder",
"libbinder_ndk",
"libcrypto",
"liblog",
],
static_libs: [
+ "android.hardware.common-V2-ndk",
+ "android.hardware.drm-V1-ndk",
"android.hardware.security.rkp-V3-ndk",
"libbase",
"libcppbor_external",
"libcppcose_rkp",
"libjsoncpp",
"libkeymint_remote_prov_support",
+ "libmediadrmrkp",
],
}
@@ -90,26 +92,25 @@
suffix: "64",
},
},
- stl: "libc++_static",
target: {
android_arm: {
dist: {
- dir: "rkp_factory_extraction_tool/arm",
+ dir: "rkp/arm",
},
},
android_arm64: {
dist: {
- dir: "rkp_factory_extraction_tool/arm64",
+ dir: "rkp/arm64",
},
},
android_x86: {
dist: {
- dir: "rkp_factory_extraction_tool/x86",
+ dir: "rkp/x86",
},
},
android_x86_64: {
dist: {
- dir: "rkp_factory_extraction_tool/x86_64",
+ dir: "rkp/x86_64",
},
},
},
diff --git a/provisioner/rkp_factory_extraction_tool.cpp b/provisioner/rkp_factory_extraction_tool.cpp
index 5ba777e..5765e05 100644
--- a/provisioner/rkp_factory_extraction_tool.cpp
+++ b/provisioner/rkp_factory_extraction_tool.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <aidl/android/hardware/drm/IDrmFactory.h>
#include <aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h>
#include <android/binder_manager.h>
#include <cppbor.h>
@@ -26,8 +27,10 @@
#include <string>
#include <vector>
+#include "DrmRkpAdapter.h"
#include "rkp_factory_extraction_lib.h"
+using aidl::android::hardware::drm::IDrmFactory;
using aidl::android::hardware::security::keymint::IRemotelyProvisionedComponent;
using aidl::android::hardware::security::keymint::remote_prov::jsonEncodeCsrWithBuild;
@@ -47,6 +50,10 @@
constexpr std::string_view kBuildPlusCsr = "build+csr"; // Text-encoded (JSON) build
// fingerprint plus CSR.
+std::string getFullServiceName(const char* descriptor, const char* name) {
+ return std::string(descriptor) + "/" + name;
+}
+
void writeOutput(const std::string instance_name, const Array& csr) {
if (FLAGS_output_format == kBinaryCsrOutput) {
auto bytes = csr.encode();
@@ -67,12 +74,21 @@
}
}
+void getCsrForIRpc(const char* descriptor, const char* name, IRemotelyProvisionedComponent* irpc) {
+ auto [request, errMsg] = getCsr(name, irpc, FLAGS_self_test);
+ auto fullName = getFullServiceName(descriptor, name);
+ if (!request) {
+ std::cerr << "Unable to build CSR for '" << fullName << ": " << errMsg << std::endl;
+ exit(-1);
+ }
+
+ writeOutput(std::string(name), *request);
+}
+
// Callback for AServiceManager_forEachDeclaredInstance that writes out a CSR
// for every IRemotelyProvisionedComponent.
void getCsrForInstance(const char* name, void* /*context*/) {
- const std::vector<uint8_t> challenge = generateChallenge();
-
- auto fullName = std::string(IRemotelyProvisionedComponent::descriptor) + "/" + name;
+ auto fullName = getFullServiceName(IRemotelyProvisionedComponent::descriptor, name);
AIBinder* rkpAiBinder = AServiceManager_getService(fullName.c_str());
::ndk::SpAIBinder rkp_binder(rkpAiBinder);
auto rkp_service = IRemotelyProvisionedComponent::fromBinder(rkp_binder);
@@ -81,13 +97,7 @@
exit(-1);
}
- auto [request, errMsg] = getCsr(name, rkp_service.get(), FLAGS_self_test);
- if (!request) {
- std::cerr << "Unable to build CSR for '" << fullName << ": " << errMsg << std::endl;
- exit(-1);
- }
-
- writeOutput(std::string(name), *request);
+ getCsrForIRpc(IRemotelyProvisionedComponent::descriptor, name, rkp_service.get());
}
} // namespace
@@ -98,5 +108,10 @@
AServiceManager_forEachDeclaredInstance(IRemotelyProvisionedComponent::descriptor,
/*context=*/nullptr, getCsrForInstance);
+ // Append drm csr's
+ for (auto const& e : android::mediadrm::getDrmRemotelyProvisionedComponents()) {
+ getCsrForIRpc(IDrmFactory::descriptor, e.first.c_str(), e.second.get());
+ }
+
return 0;
}