DO NOT MERGE - Merge qt-dev-plus-aosp-without-vendor (5699924) into stage-aosp-master
Bug: 134405016 Change-Id: I7b2848c7eff8a193adc998d4d2dfea0ec05b7b73
This commit is contained in:
commit
76206993e4
9 changed files with 185 additions and 36 deletions
|
@ -9,7 +9,16 @@ cc_defaults {
|
|||
],
|
||||
|
||||
sanitize: {
|
||||
misc_undefined: ["integer"],
|
||||
misc_undefined: [
|
||||
"signed-integer-overflow",
|
||||
"unsigned-integer-overflow",
|
||||
"shift",
|
||||
"integer-divide-by-zero",
|
||||
"implicit-unsigned-integer-truncation",
|
||||
// BUG: 123630767
|
||||
//"implicit-signed-integer-truncation",
|
||||
"implicit-integer-sign-change",
|
||||
],
|
||||
},
|
||||
|
||||
clang: true,
|
||||
|
|
|
@ -704,10 +704,27 @@ std::string KeyBlobEntry::getCharacteristicsBlobPath() const {
|
|||
}
|
||||
|
||||
bool KeyBlobEntry::hasKeyBlob() const {
|
||||
return !access(getKeyBlobPath().c_str(), R_OK | W_OK);
|
||||
int trys = 3;
|
||||
while (trys--) {
|
||||
if (!access(getKeyBlobPath().c_str(), R_OK | W_OK)) return true;
|
||||
if (errno == ENOENT) return false;
|
||||
LOG(WARNING) << "access encountered " << strerror(errno) << " (" << errno << ")"
|
||||
<< " while checking for key blob";
|
||||
if (errno != EAGAIN) break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool KeyBlobEntry::hasCharacteristicsBlob() const {
|
||||
return !access(getCharacteristicsBlobPath().c_str(), R_OK | W_OK);
|
||||
int trys = 3;
|
||||
while (trys--) {
|
||||
if (!access(getCharacteristicsBlobPath().c_str(), R_OK | W_OK)) return true;
|
||||
if (errno == ENOENT) return false;
|
||||
LOG(WARNING) << "access encountered " << strerror(errno) << " (" << errno << ")"
|
||||
<< " while checking for key characteristics blob";
|
||||
if (errno != EAGAIN) break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::tuple<bool, uid_t, std::string> filename2UidAlias(const std::string& filepath) {
|
||||
|
|
|
@ -69,8 +69,6 @@ using ::android::security::keystore::KeystoreResponse;
|
|||
|
||||
constexpr double kIdRotationPeriod = 30 * 24 * 60 * 60; /* Thirty days, in seconds */
|
||||
const char* kTimestampFilePath = "timestamp";
|
||||
const int ID_ATTESTATION_REQUEST_GENERIC_INFO = 1 << 0;
|
||||
const int ID_ATTESTATION_REQUEST_UNIQUE_DEVICE_ID = 1 << 1;
|
||||
|
||||
struct BIGNUM_Delete {
|
||||
void operator()(BIGNUM* p) const { BN_free(p); }
|
||||
|
@ -374,17 +372,13 @@ Status KeyStoreService::onUserPasswordChanged(int32_t userId, const String16& pa
|
|||
return Status::ok();
|
||||
}
|
||||
|
||||
const String8 password8(password);
|
||||
// Flush the auth token table to prevent stale tokens from sticking
|
||||
// around.
|
||||
mKeyStore->getAuthTokenTable().Clear();
|
||||
|
||||
if (password.size() == 0) {
|
||||
ALOGI("Secure lockscreen for user %d removed, deleting encrypted entries", userId);
|
||||
mKeyStore->resetUser(userId, true);
|
||||
*aidl_return = static_cast<int32_t>(ResponseCode::NO_ERROR);
|
||||
return Status::ok();
|
||||
} else {
|
||||
const String8 password8(password);
|
||||
switch (mKeyStore->getState(userId)) {
|
||||
case ::STATE_UNINITIALIZED: {
|
||||
// generate master key, encrypt with password, write to file,
|
||||
|
@ -996,9 +990,8 @@ Status KeyStoreService::addAuthToken(const ::std::vector<uint8_t>& authTokenAsVe
|
|||
return Status::ok();
|
||||
}
|
||||
|
||||
int isDeviceIdAttestationRequested(const KeymasterArguments& params) {
|
||||
bool isDeviceIdAttestationRequested(const KeymasterArguments& params) {
|
||||
const hardware::hidl_vec<KeyParameter>& paramsVec = params.getParameters();
|
||||
int result = 0;
|
||||
for (size_t i = 0; i < paramsVec.size(); ++i) {
|
||||
switch (paramsVec[i].tag) {
|
||||
case Tag::ATTESTATION_ID_BRAND:
|
||||
|
@ -1006,18 +999,15 @@ int isDeviceIdAttestationRequested(const KeymasterArguments& params) {
|
|||
case Tag::ATTESTATION_ID_MANUFACTURER:
|
||||
case Tag::ATTESTATION_ID_MODEL:
|
||||
case Tag::ATTESTATION_ID_PRODUCT:
|
||||
result |= ID_ATTESTATION_REQUEST_GENERIC_INFO;
|
||||
break;
|
||||
case Tag::ATTESTATION_ID_IMEI:
|
||||
case Tag::ATTESTATION_ID_MEID:
|
||||
case Tag::ATTESTATION_ID_SERIAL:
|
||||
result |= ID_ATTESTATION_REQUEST_UNIQUE_DEVICE_ID;
|
||||
break;
|
||||
return true;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return false;
|
||||
}
|
||||
|
||||
Status KeyStoreService::attestKey(
|
||||
|
@ -1031,15 +1021,7 @@ Status KeyStoreService::attestKey(
|
|||
|
||||
uid_t callingUid = IPCThreadState::self()->getCallingUid();
|
||||
|
||||
int needsIdAttestation = isDeviceIdAttestationRequested(params);
|
||||
bool needsUniqueIdAttestation = needsIdAttestation & ID_ATTESTATION_REQUEST_UNIQUE_DEVICE_ID;
|
||||
bool isPrimaryUserSystemUid = (callingUid == AID_SYSTEM);
|
||||
bool isSomeUserSystemUid = (get_app_id(callingUid) == AID_SYSTEM);
|
||||
// Allow system context from any user to request attestation with basic device information,
|
||||
// while only allow system context from user 0 (device owner) to request attestation with
|
||||
// unique device ID.
|
||||
if ((needsIdAttestation && !isSomeUserSystemUid) ||
|
||||
(needsUniqueIdAttestation && !isPrimaryUserSystemUid)) {
|
||||
if (isDeviceIdAttestationRequested(params) && (get_app_id(callingUid) != AID_SYSTEM)) {
|
||||
return AIDL_RETURN(KeyStoreServiceReturnCode(ErrorCode::INVALID_ARGUMENT));
|
||||
}
|
||||
|
||||
|
@ -1277,7 +1259,8 @@ uid_t KeyStoreService::getEffectiveUid(int32_t targetUid) {
|
|||
bool KeyStoreService::checkBinderPermission(perm_t permission, int32_t targetUid) {
|
||||
uid_t callingUid = IPCThreadState::self()->getCallingUid();
|
||||
pid_t spid = IPCThreadState::self()->getCallingPid();
|
||||
if (!has_permission(callingUid, permission, spid)) {
|
||||
const char* ssid = IPCThreadState::self()->getCallingSid();
|
||||
if (!has_permission(callingUid, permission, spid, ssid)) {
|
||||
ALOGW("permission %s denied for %d", get_perm_label(permission), callingUid);
|
||||
return false;
|
||||
}
|
||||
|
@ -1295,7 +1278,8 @@ bool KeyStoreService::checkBinderPermission(perm_t permission, int32_t targetUid
|
|||
bool KeyStoreService::checkBinderPermissionSelfOrSystem(perm_t permission, int32_t targetUid) {
|
||||
uid_t callingUid = IPCThreadState::self()->getCallingUid();
|
||||
pid_t spid = IPCThreadState::self()->getCallingPid();
|
||||
if (!has_permission(callingUid, permission, spid)) {
|
||||
const char* ssid = IPCThreadState::self()->getCallingSid();
|
||||
if (!has_permission(callingUid, permission, spid, ssid)) {
|
||||
ALOGW("permission %s denied for %d", get_perm_label(permission), callingUid);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
package keystore;
|
||||
|
||||
option optimize_for = LITE_RUNTIME;
|
||||
|
|
|
@ -156,6 +156,7 @@ int main(int argc, char* argv[]) {
|
|||
keyStore->initialize();
|
||||
android::sp<android::IServiceManager> sm = android::defaultServiceManager();
|
||||
android::sp<keystore::KeyStoreService> service = new keystore::KeyStoreService(keyStore);
|
||||
service->setRequestingSid(true);
|
||||
android::status_t ret = sm->addService(android::String16("android.security.keystore"), service);
|
||||
CHECK(ret == android::OK) << "Couldn't register binder service!";
|
||||
|
||||
|
|
|
@ -92,6 +92,7 @@ static const perm_t DEFAULT_PERMS = static_cast<perm_t>(
|
|||
struct audit_data {
|
||||
pid_t pid;
|
||||
uid_t uid;
|
||||
const char* sid;
|
||||
};
|
||||
|
||||
const char* get_perm_label(perm_t perm) {
|
||||
|
@ -111,7 +112,8 @@ static int audit_callback(void* data, security_class_t /* cls */, char* buf, siz
|
|||
return 0;
|
||||
}
|
||||
|
||||
snprintf(buf, len, "pid=%d uid=%d", ad->pid, ad->uid);
|
||||
const char* sid = ad->sid ? ad->sid : "N/A";
|
||||
snprintf(buf, len, "pid=%d uid=%d sid=%s", ad->pid, ad->uid, sid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -131,7 +133,7 @@ int configure_selinux() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool keystore_selinux_check_access(uid_t uid, perm_t perm, pid_t spid) {
|
||||
static bool keystore_selinux_check_access(uid_t uid, perm_t perm, pid_t spid, const char* ssid) {
|
||||
audit_data ad;
|
||||
char* sctx = nullptr;
|
||||
const char* selinux_class = "keystore_key";
|
||||
|
@ -141,15 +143,18 @@ static bool keystore_selinux_check_access(uid_t uid, perm_t perm, pid_t spid) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (getpidcon(spid, &sctx) != 0) {
|
||||
if (ssid == nullptr && getpidcon(spid, &sctx) != 0) {
|
||||
ALOGE("SELinux: Failed to get source pid context.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* use_sid = ssid ? ssid : sctx;
|
||||
|
||||
ad.pid = spid;
|
||||
ad.uid = uid;
|
||||
ad.sid = use_sid;
|
||||
|
||||
bool allowed = selinux_check_access(sctx, tctx, selinux_class, str_perm,
|
||||
bool allowed = selinux_check_access(use_sid, tctx, selinux_class, str_perm,
|
||||
reinterpret_cast<void*>(&ad)) == 0;
|
||||
freecon(sctx);
|
||||
return allowed;
|
||||
|
@ -171,20 +176,24 @@ uid_t get_keystore_euid(uid_t uid) {
|
|||
return uid;
|
||||
}
|
||||
|
||||
bool has_permission(uid_t uid, perm_t perm, pid_t spid) {
|
||||
bool has_permission(uid_t uid, perm_t perm, pid_t spid, const char* sid) {
|
||||
// All system users are equivalent for multi-user support.
|
||||
if (get_app_id(uid) == AID_SYSTEM) {
|
||||
uid = AID_SYSTEM;
|
||||
}
|
||||
|
||||
if (sid == nullptr) {
|
||||
android_errorWriteLog(0x534e4554, "121035042");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < sizeof(user_perms) / sizeof(user_perms[0]); i++) {
|
||||
struct user_perm user = user_perms[i];
|
||||
if (user.uid == uid) {
|
||||
return (user.perms & perm) && keystore_selinux_check_access(uid, perm, spid);
|
||||
return (user.perms & perm) && keystore_selinux_check_access(uid, perm, spid, sid);
|
||||
}
|
||||
}
|
||||
|
||||
return (DEFAULT_PERMS & perm) && keystore_selinux_check_access(uid, perm, spid);
|
||||
return (DEFAULT_PERMS & perm) && keystore_selinux_check_access(uid, perm, spid, sid);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -51,7 +51,12 @@ const char* get_perm_label(perm_t perm);
|
|||
*/
|
||||
uid_t get_keystore_euid(uid_t uid);
|
||||
|
||||
bool has_permission(uid_t uid, perm_t perm, pid_t spid);
|
||||
/**
|
||||
* Returns true if the uid/pid/sid has a permission. Checks based on sid if available.
|
||||
*
|
||||
* sid may be null on older kernels
|
||||
*/
|
||||
bool has_permission(uid_t uid, perm_t perm, pid_t spid, const char* sid);
|
||||
|
||||
/**
|
||||
* Returns true if the callingUid is allowed to interact in the targetUid's
|
||||
|
|
|
@ -37,3 +37,33 @@ cc_test {
|
|||
cfi: false,
|
||||
}
|
||||
}
|
||||
|
||||
cc_test {
|
||||
cflags: [
|
||||
"-Wall",
|
||||
"-Werror",
|
||||
"-Wextra",
|
||||
"-O0",
|
||||
],
|
||||
srcs: [
|
||||
"confirmationui_invocation_test.cpp",
|
||||
"gtest_main.cpp",
|
||||
],
|
||||
name: "confirmationui_invocation_test",
|
||||
static_libs: [
|
||||
"android.hardware.confirmationui@1.0",
|
||||
"libbase",
|
||||
"libgtest_main",
|
||||
"libutils",
|
||||
"liblog",
|
||||
],
|
||||
shared_libs: [
|
||||
"libbinder",
|
||||
"libkeystore_aidl", // for IKeyStoreService.asInterface()
|
||||
"libkeystore_binder",
|
||||
"libkeystore_parcelables",
|
||||
],
|
||||
sanitize: {
|
||||
cfi: false,
|
||||
}
|
||||
}
|
||||
|
|
92
keystore/tests/confirmationui_invocation_test.cpp
Normal file
92
keystore/tests/confirmationui_invocation_test.cpp
Normal file
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
**
|
||||
** Copyright 2019, 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 <android/hardware/confirmationui/1.0/types.h>
|
||||
#include <android/security/BnConfirmationPromptCallback.h>
|
||||
#include <android/security/keystore/IKeystoreService.h>
|
||||
#include <binder/IPCThreadState.h>
|
||||
#include <binder/IServiceManager.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <future>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
using ConfirmationResponseCode = android::hardware::confirmationui::V1_0::ResponseCode;
|
||||
using android::IBinder;
|
||||
using android::IServiceManager;
|
||||
using android::sp;
|
||||
using android::String16;
|
||||
using android::security::keystore::IKeystoreService;
|
||||
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
class ConfirmationListener
|
||||
: public android::security::BnConfirmationPromptCallback,
|
||||
public std::promise<std::tuple<ConfirmationResponseCode, std::vector<uint8_t>>> {
|
||||
public:
|
||||
ConfirmationListener() {}
|
||||
|
||||
virtual ::android::binder::Status
|
||||
onConfirmationPromptCompleted(int32_t result,
|
||||
const ::std::vector<uint8_t>& dataThatWasConfirmed) override {
|
||||
this->set_value({static_cast<ConfirmationResponseCode>(result), dataThatWasConfirmed});
|
||||
return ::android::binder::Status::ok();
|
||||
}
|
||||
};
|
||||
|
||||
TEST(ConfirmationInvocationTest, InvokeAndCancel) {
|
||||
android::ProcessState::self()->startThreadPool();
|
||||
|
||||
sp<IServiceManager> sm = android::defaultServiceManager();
|
||||
sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
|
||||
sp<IKeystoreService> service = android::interface_cast<IKeystoreService>(binder);
|
||||
ASSERT_TRUE(service);
|
||||
|
||||
String16 promptText16("Just a little test!");
|
||||
String16 locale16("en");
|
||||
std::vector<uint8_t> extraData{0xaa, 0xff, 0x00, 0x55};
|
||||
|
||||
sp<ConfirmationListener> listener = new ConfirmationListener();
|
||||
|
||||
auto future = listener->get_future();
|
||||
int32_t aidl_return;
|
||||
|
||||
android::binder::Status status = service->presentConfirmationPrompt(
|
||||
listener, promptText16, extraData, locale16, 0, &aidl_return);
|
||||
ASSERT_TRUE(status.isOk()) << "Presenting confirmation prompt failed with binder status '"
|
||||
<< status.toString8().c_str() << "'.\n";
|
||||
ConfirmationResponseCode responseCode = static_cast<ConfirmationResponseCode>(aidl_return);
|
||||
ASSERT_EQ(responseCode, ConfirmationResponseCode::OK)
|
||||
<< "Presenting confirmation prompt failed with response code " << aidl_return << ".\n";
|
||||
|
||||
auto fstatus = future.wait_for(2s);
|
||||
EXPECT_EQ(fstatus, std::future_status::timeout);
|
||||
|
||||
status = service->cancelConfirmationPrompt(listener, &aidl_return);
|
||||
ASSERT_TRUE(status.isOk());
|
||||
|
||||
responseCode = static_cast<ConfirmationResponseCode>(aidl_return);
|
||||
ASSERT_EQ(responseCode, ConfirmationResponseCode::OK);
|
||||
|
||||
future.wait();
|
||||
auto [rc, dataThatWasConfirmed] = future.get();
|
||||
|
||||
ASSERT_EQ(rc, ConfirmationResponseCode::Aborted);
|
||||
}
|
Loading…
Reference in a new issue