| David Zeuthen | c6eb7cd | 2017-11-27 11:33:55 -0500 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright (C) 2017 The Android Open Source Project | 
|  | 3 | * | 
|  | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 5 | * you may not use this file except in compliance with the License. | 
|  | 6 | * You may obtain a copy of the License at | 
|  | 7 | * | 
|  | 8 | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 9 | * | 
|  | 10 | * Unless required by applicable law or agreed to in writing, software | 
|  | 11 | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 13 | * See the License for the specific language governing permissions and | 
|  | 14 | * limitations under the License. | 
|  | 15 | */ | 
|  | 16 |  | 
|  | 17 | #define LOG_TAG "ConfirmationManager" | 
|  | 18 |  | 
|  | 19 | #include "confirmation_manager.h" | 
|  | 20 |  | 
|  | 21 | #include <android/hardware/confirmationui/1.0/IConfirmationResultCallback.h> | 
|  | 22 | #include <android/hardware/confirmationui/1.0/IConfirmationUI.h> | 
|  | 23 | #include <android/hardware/confirmationui/1.0/types.h> | 
|  | 24 | #include <android/security/BpConfirmationPromptCallback.h> | 
|  | 25 | #include <binder/BpBinder.h> | 
| Janis Danisevskis | 064ce85 | 2018-03-12 16:49:16 -0700 | [diff] [blame] | 26 | #include <binder/IPCThreadState.h> | 
| David Zeuthen | c6eb7cd | 2017-11-27 11:33:55 -0500 | [diff] [blame] | 27 | #include <binder/Parcel.h> | 
|  | 28 |  | 
|  | 29 | #include "keystore_aidl_hidl_marshalling_utils.h" | 
|  | 30 |  | 
|  | 31 | namespace keystore { | 
|  | 32 |  | 
|  | 33 | using android::IBinder; | 
|  | 34 | using android::sp; | 
|  | 35 | using android::String16; | 
|  | 36 | using android::String8; | 
|  | 37 | using android::wp; | 
|  | 38 | using android::binder::Status; | 
|  | 39 | using android::hardware::hidl_vec; | 
|  | 40 | using android::hardware::Return; | 
|  | 41 | using android::hardware::confirmationui::V1_0::IConfirmationResultCallback; | 
|  | 42 | using android::hardware::confirmationui::V1_0::IConfirmationUI; | 
|  | 43 | using android::hardware::confirmationui::V1_0::UIOption; | 
|  | 44 |  | 
|  | 45 | using android::security::BpConfirmationPromptCallback; | 
|  | 46 | using std::lock_guard; | 
|  | 47 | using std::mutex; | 
|  | 48 | using std::vector; | 
|  | 49 |  | 
|  | 50 | ConfirmationManager::ConfirmationManager(IBinder::DeathRecipient* deathRecipient) | 
|  | 51 | : IConfirmationResultCallback(), mDeathRecipient(deathRecipient) {} | 
|  | 52 |  | 
|  | 53 | // Called by keystore main thread. | 
|  | 54 | Status ConfirmationManager::presentConfirmationPrompt(const sp<IBinder>& listener, | 
|  | 55 | const String16& promptText, | 
|  | 56 | const hidl_vec<uint8_t>& extraData, | 
|  | 57 | const String16& locale, int uiOptionsAsFlags, | 
|  | 58 | int32_t* aidl_return) { | 
|  | 59 | lock_guard<mutex> lock(mMutex); | 
|  | 60 |  | 
|  | 61 | if (mCurrentListener != nullptr) { | 
|  | 62 | *aidl_return = static_cast<int32_t>(ConfirmationResponseCode::OperationPending); | 
|  | 63 | return Status::ok(); | 
|  | 64 | } | 
|  | 65 |  | 
|  | 66 | sp<IConfirmationUI> confirmationUI = IConfirmationUI::tryGetService(); | 
|  | 67 | if (confirmationUI == nullptr) { | 
|  | 68 | ALOGW("Error getting confirmationUI service\n"); | 
|  | 69 | *aidl_return = static_cast<int32_t>(ConfirmationResponseCode::Unimplemented); | 
|  | 70 | return Status::ok(); | 
|  | 71 | } | 
|  | 72 |  | 
| Janis Danisevskis | 064ce85 | 2018-03-12 16:49:16 -0700 | [diff] [blame] | 73 | uid_t callingUid = android::IPCThreadState::self()->getCallingUid(); | 
|  | 74 | if (!mRateLimiting.tryPrompt(callingUid)) { | 
|  | 75 | *aidl_return = static_cast<int32_t>(ConfirmationResponseCode::SystemError); | 
|  | 76 | return Status::ok(); | 
|  | 77 | } | 
|  | 78 |  | 
| David Zeuthen | c6eb7cd | 2017-11-27 11:33:55 -0500 | [diff] [blame] | 79 | String8 promptText8(promptText); | 
|  | 80 | String8 locale8(locale); | 
|  | 81 | vector<UIOption> uiOptionsVector; | 
|  | 82 | for (int n = 0; n < 32; n++) { | 
|  | 83 | if (uiOptionsAsFlags & (1 << n)) { | 
|  | 84 | uiOptionsVector.push_back(UIOption(n)); | 
|  | 85 | } | 
|  | 86 | } | 
|  | 87 | ConfirmationResponseCode responseCode; | 
|  | 88 | responseCode = confirmationUI->promptUserConfirmation(sp<IConfirmationResultCallback>(this), | 
|  | 89 | promptText8.string(), extraData, | 
|  | 90 | locale8.string(), uiOptionsVector); | 
|  | 91 | if (responseCode != ConfirmationResponseCode::OK) { | 
|  | 92 | ALOGW("Unexpecxted responseCode %d from promptUserConfirmation\n", responseCode); | 
|  | 93 | *aidl_return = static_cast<int32_t>(responseCode); | 
|  | 94 | return Status::ok(); | 
|  | 95 | } | 
|  | 96 |  | 
|  | 97 | listener->linkToDeath(mDeathRecipient); | 
|  | 98 | confirmationUI->linkToDeath(this, 0); | 
|  | 99 | mCurrentListener = listener; | 
|  | 100 | mCurrentConfirmationUI = confirmationUI; | 
|  | 101 |  | 
|  | 102 | *aidl_return = static_cast<int32_t>(ConfirmationResponseCode::OK); | 
|  | 103 | return Status::ok(); | 
|  | 104 | } | 
|  | 105 |  | 
|  | 106 | // Called by keystore main thread. | 
|  | 107 | Status ConfirmationManager::cancelConfirmationPrompt(const sp<IBinder>& listener, | 
|  | 108 | int32_t* aidl_return) { | 
|  | 109 | mMutex.lock(); | 
|  | 110 | if (mCurrentListener != listener) { | 
|  | 111 | // If the prompt was displayed by another application, return | 
|  | 112 | // OperationPending. | 
|  | 113 | mMutex.unlock(); | 
|  | 114 | *aidl_return = static_cast<int32_t>(ConfirmationResponseCode::OperationPending); | 
|  | 115 | return Status::ok(); | 
|  | 116 | } | 
|  | 117 | mMutex.unlock(); | 
|  | 118 |  | 
|  | 119 | finalizeTransaction(ConfirmationResponseCode::Aborted, {}, true); | 
|  | 120 |  | 
|  | 121 | *aidl_return = static_cast<int32_t>(ConfirmationResponseCode::OK); | 
|  | 122 | return Status::ok(); | 
|  | 123 | } | 
|  | 124 |  | 
| David Zeuthen | 1a49231 | 2018-02-26 11:00:30 -0500 | [diff] [blame] | 125 | // Called by keystore main thread. | 
|  | 126 | Status ConfirmationManager::isConfirmationPromptSupported(bool* aidl_return) { | 
|  | 127 | sp<IConfirmationUI> confirmationUI = IConfirmationUI::tryGetService(); | 
|  | 128 | if (confirmationUI == nullptr) { | 
|  | 129 | ALOGW("Error getting confirmationUI service\n"); | 
|  | 130 | *aidl_return = false; | 
|  | 131 | return Status::ok(); | 
|  | 132 | } | 
|  | 133 |  | 
|  | 134 | *aidl_return = true; | 
|  | 135 | return Status::ok(); | 
|  | 136 | } | 
|  | 137 |  | 
| David Zeuthen | c6eb7cd | 2017-11-27 11:33:55 -0500 | [diff] [blame] | 138 | void ConfirmationManager::finalizeTransaction(ConfirmationResponseCode responseCode, | 
|  | 139 | hidl_vec<uint8_t> dataThatWasConfirmed, | 
|  | 140 | bool callAbortOnHal) { | 
|  | 141 | // Note that confirmationUI->abort() may make the remote HAL process do an IPC call back | 
|  | 142 | // into our process resulting in confirmationResultCallback() to be called... this in turn | 
|  | 143 | // calls finalizeTransaction(). So we have to be careful a) not holding any locks; | 
|  | 144 | // and b) ensure state has been cleared; before doing this... | 
|  | 145 |  | 
|  | 146 | mMutex.lock(); | 
| Janis Danisevskis | 064ce85 | 2018-03-12 16:49:16 -0700 | [diff] [blame] | 147 | mRateLimiting.processResult(responseCode); | 
| David Zeuthen | c6eb7cd | 2017-11-27 11:33:55 -0500 | [diff] [blame] | 148 | sp<IBinder> listener = mCurrentListener; | 
|  | 149 | if (mCurrentListener != nullptr) { | 
|  | 150 | mCurrentListener->unlinkToDeath(mDeathRecipient); | 
|  | 151 | mCurrentListener = nullptr; | 
|  | 152 | } | 
|  | 153 | sp<IConfirmationUI> confirmationUI = mCurrentConfirmationUI; | 
|  | 154 | if (mCurrentConfirmationUI != nullptr) { | 
|  | 155 | mCurrentConfirmationUI->unlinkToDeath(this); | 
|  | 156 | mCurrentConfirmationUI = nullptr; | 
|  | 157 | } | 
|  | 158 | mMutex.unlock(); | 
|  | 159 |  | 
|  | 160 | // Tell the HAL to shut down the confirmation dialog, if requested. | 
|  | 161 | if (confirmationUI != nullptr && callAbortOnHal) { | 
|  | 162 | confirmationUI->abort(); | 
|  | 163 | } | 
|  | 164 |  | 
|  | 165 | // Deliver result to the application that started the operation. | 
|  | 166 | if (listener != nullptr) { | 
|  | 167 | sp<BpConfirmationPromptCallback> obj = new BpConfirmationPromptCallback(listener); | 
|  | 168 | Status status = obj->onConfirmationPromptCompleted(static_cast<int32_t>(responseCode), | 
|  | 169 | dataThatWasConfirmed); | 
|  | 170 | if (!status.isOk()) { | 
|  | 171 | ALOGW("Error sending onConfirmationPromptCompleted - status: %s\n", | 
|  | 172 | status.toString8().c_str()); | 
|  | 173 | } | 
|  | 174 | } | 
|  | 175 | } | 
|  | 176 |  | 
|  | 177 | // Called by hwbinder thread (not keystore main thread). | 
|  | 178 | Return<void> ConfirmationManager::result(ConfirmationResponseCode responseCode, | 
|  | 179 | const hidl_vec<uint8_t>& dataThatWasConfirmed, | 
|  | 180 | const hidl_vec<uint8_t>& confirmationToken) { | 
|  | 181 | finalizeTransaction(responseCode, dataThatWasConfirmed, false); | 
|  | 182 | lock_guard<mutex> lock(mMutex); | 
|  | 183 | mLatestConfirmationToken = confirmationToken; | 
|  | 184 | return Return<void>(); | 
|  | 185 | } | 
|  | 186 |  | 
| Janis Danisevskis | ff3d7f4 | 2018-10-08 07:15:09 -0700 | [diff] [blame] | 187 | // Called by keystore main thread or keymaster worker | 
| David Zeuthen | c6eb7cd | 2017-11-27 11:33:55 -0500 | [diff] [blame] | 188 | hidl_vec<uint8_t> ConfirmationManager::getLatestConfirmationToken() { | 
|  | 189 | lock_guard<mutex> lock(mMutex); | 
|  | 190 | return mLatestConfirmationToken; | 
|  | 191 | } | 
|  | 192 |  | 
|  | 193 | void ConfirmationManager::binderDied(const wp<IBinder>& who) { | 
|  | 194 | // This is also called for other binders so need to check it's for | 
|  | 195 | // us before acting on it. | 
|  | 196 | mMutex.lock(); | 
|  | 197 | if (who == mCurrentListener) { | 
|  | 198 | // Clear this so we don't call back into the already dead | 
|  | 199 | // binder in finalizeTransaction(). | 
|  | 200 | mCurrentListener->unlinkToDeath(mDeathRecipient); | 
|  | 201 | mCurrentListener = nullptr; | 
|  | 202 | mMutex.unlock(); | 
|  | 203 | ALOGW("The process which requested the confirmation dialog died.\n"); | 
|  | 204 | finalizeTransaction(ConfirmationResponseCode::SystemError, {}, true); | 
|  | 205 | } else { | 
|  | 206 | mMutex.unlock(); | 
|  | 207 | } | 
|  | 208 | } | 
|  | 209 |  | 
|  | 210 | void ConfirmationManager::serviceDied(uint64_t /* cookie */, | 
|  | 211 | const wp<android::hidl::base::V1_0::IBase>& /* who */) { | 
|  | 212 | ALOGW("The ConfirmationUI HAL died.\n"); | 
|  | 213 | finalizeTransaction(ConfirmationResponseCode::SystemError, {}, false); | 
|  | 214 | } | 
|  | 215 |  | 
|  | 216 | }  // namespace keystore |