1 /*
2 *
3 * Copyright 2019, The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include "TrustyConfirmationUI.h"
19
20 #include <android-base/logging.h>
21 #include <android/hardware/confirmationui/1.0/types.h>
22 #include <android/hardware/keymaster/4.0/types.h>
23 #include <fcntl.h>
24 #include <linux/input.h>
25 #include <poll.h>
26 #include <pthread.h>
27 #include <secure_input/evdev.h>
28 #include <secure_input/secure_input_device.h>
29 #include <secure_input/secure_input_proto.h>
30 #include <signal.h>
31 #include <sys/ioctl.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
34 #include <teeui/msg_formatting.h>
35 #include <teeui/utils.h>
36 #include <time.h>
37
38 #include <atomic>
39 #include <functional>
40 #include <memory>
41 #include <thread>
42 #include <tuple>
43 #include <vector>
44
45 namespace android {
46 namespace hardware {
47 namespace confirmationui {
48 namespace V1_0 {
49 namespace implementation {
50
51 using namespace secure_input;
52
53 using ::android::trusty::TrustyAppError;
54
55 using ::teeui::AbortMsg;
56 using ::teeui::DeliverTestCommandMessage;
57 using ::teeui::DeliverTestCommandResponse;
58 using ::teeui::FetchConfirmationResult;
59 using ::teeui::MsgString;
60 using ::teeui::MsgVector;
61 using ::teeui::PromptUserConfirmationMsg;
62 using ::teeui::PromptUserConfirmationResponse;
63 using ::teeui::ResultMsg;
64
65 using ::secure_input::createSecureInput;
66
67 using ::android::hardware::keymaster::V4_0::HardwareAuthToken;
68
69 using ::std::tie;
70
71 using TeeuiRc = ::teeui::ResponseCode;
72
73 constexpr const char kTrustyDeviceName[] = "/dev/trusty-ipc-dev0";
74 constexpr const char kConfirmationuiAppName[] = "com.android.trusty.confirmationui";
75
76 namespace {
77
78 class Finalize {
79 private:
80 std::function<void()> f_;
81
82 public:
Finalize(std::function<void ()> f)83 Finalize(std::function<void()> f) : f_(f) {}
~Finalize()84 ~Finalize() {
85 if (f_) f_();
86 }
release()87 void release() { f_ = {}; }
88 };
89
convertRc(TeeuiRc trc)90 ResponseCode convertRc(TeeuiRc trc) {
91 static_assert(
92 uint32_t(TeeuiRc::OK) == uint32_t(ResponseCode::OK) &&
93 uint32_t(TeeuiRc::Canceled) == uint32_t(ResponseCode::Canceled) &&
94 uint32_t(TeeuiRc::Aborted) == uint32_t(ResponseCode::Aborted) &&
95 uint32_t(TeeuiRc::OperationPending) == uint32_t(ResponseCode::OperationPending) &&
96 uint32_t(TeeuiRc::Ignored) == uint32_t(ResponseCode::Ignored) &&
97 uint32_t(TeeuiRc::SystemError) == uint32_t(ResponseCode::SystemError) &&
98 uint32_t(TeeuiRc::Unimplemented) == uint32_t(ResponseCode::Unimplemented) &&
99 uint32_t(TeeuiRc::Unexpected) == uint32_t(ResponseCode::Unexpected) &&
100 uint32_t(TeeuiRc::UIError) == uint32_t(ResponseCode::UIError) &&
101 uint32_t(TeeuiRc::UIErrorMissingGlyph) == uint32_t(ResponseCode::UIErrorMissingGlyph) &&
102 uint32_t(TeeuiRc::UIErrorMessageTooLong) ==
103 uint32_t(ResponseCode::UIErrorMessageTooLong) &&
104 uint32_t(TeeuiRc::UIErrorMalformedUTF8Encoding) ==
105 uint32_t(ResponseCode::UIErrorMalformedUTF8Encoding),
106 "teeui::ResponseCode and "
107 "::android::hardware::confirmationui::V1_0::Responsecude are out of "
108 "sync");
109 return ResponseCode(trc);
110 }
111
convertUIOption(UIOption uio)112 teeui::UIOption convertUIOption(UIOption uio) {
113 static_assert(uint32_t(UIOption::AccessibilityInverted) ==
114 uint32_t(teeui::UIOption::AccessibilityInverted) &&
115 uint32_t(UIOption::AccessibilityMagnified) ==
116 uint32_t(teeui::UIOption::AccessibilityMagnified),
117 "teeui::UIOPtion and ::android::hardware::confirmationui::V1_0::UIOption "
118 "anre out of sync");
119 return teeui::UIOption(uio);
120 }
121
hidl2MsgString(const hidl_string & s)122 inline MsgString hidl2MsgString(const hidl_string& s) {
123 return {s.c_str(), s.c_str() + s.size()};
124 }
hidl2MsgVector(const hidl_vec<T> & v)125 template <typename T> inline MsgVector<T> hidl2MsgVector(const hidl_vec<T>& v) {
126 return {v};
127 }
128
hidl2MsgVector(const hidl_vec<UIOption> & v)129 inline MsgVector<teeui::UIOption> hidl2MsgVector(const hidl_vec<UIOption>& v) {
130 MsgVector<teeui::UIOption> result(v.size());
131 for (unsigned int i = 0; i < v.size(); ++i) {
132 result[i] = convertUIOption(v[i]);
133 }
134 return result;
135 }
136
137 } // namespace
138
TrustyConfirmationUI()139 TrustyConfirmationUI::TrustyConfirmationUI()
140 : listener_state_(ListenerState::None), prompt_result_(ResponseCode::Ignored) {}
141
~TrustyConfirmationUI()142 TrustyConfirmationUI::~TrustyConfirmationUI() {
143 ListenerState state = listener_state_;
144 if (state == ListenerState::SetupDone || state == ListenerState::Interactive) {
145 abort();
146 }
147 if (state != ListenerState::None) {
148 callback_thread_.join();
149 }
150 }
151
152 std::tuple<TeeuiRc, MsgVector<uint8_t>, MsgVector<uint8_t>>
promptUserConfirmation_(const MsgString & promptText,const MsgVector<uint8_t> & extraData,const MsgString & locale,const MsgVector<teeui::UIOption> & uiOptions)153 TrustyConfirmationUI::promptUserConfirmation_(const MsgString& promptText,
154 const MsgVector<uint8_t>& extraData,
155 const MsgString& locale,
156 const MsgVector<teeui::UIOption>& uiOptions) {
157 std::unique_lock<std::mutex> stateLock(listener_state_lock_);
158 /*
159 * This is the main listener thread function. The listener thread life cycle
160 * is equivalent to the life cycle of a single confirmation request. The life
161 * cycle is devided in four phases.
162 * * The starting phase:
163 * * The Trusted App gets loaded and/or the connection to it gets established.
164 * * A connection to the secure input device is established.
165 * * The prompt is initiated. This sends all information required by the
166 * confirmation dialog to the TA. The dialog is not yet displayed.
167 * * An event loop is created.
168 * * The event loop listens for user input events, fetches them from the
169 * secure input device, and delivers them to the TA.
170 * * All evdev devices are grabbed to give confirmationui exclusive access
171 * to user input.
172 *
173 * Note: During the starting phase the hwbinder service thread is blocked and
174 * waiting for possible Errors. If the setup phase concludes sucessfully, the
175 * hwbinder service thread gets unblocked and returns successfully. Errors
176 * that occur after the first phase are delivered by callback interface.
177 *
178 * * The 2nd phase - non interactive phase
179 * * The event loop thread is started.
180 * * After a grace period:
181 * * A handshake between the secure input device SecureInput and the TA
182 * is performed.
183 * * The input event handler are armed to process user input events.
184 *
185 * * The 3rd phase - interactive phase
186 * * We wait to any external event
187 * * Abort
188 * * Secure user input asserted
189 * * Secure input delivered (for non interactive VTS testing)
190 * * The result is fetched from the TA.
191 *
192 * * The 4th phase - cleanup
193 * The cleanup phase is given by the scope of automatic variables created
194 * in this function. The cleanup commences in reverse order of their creation.
195 * Here is a list of more complex items in the order in which they go out of
196 * scope
197 * * finalizeSecureTouch - signals and joins the secure touch thread.
198 * * eventloop - signals and joins the event loop thread. The event
199 * handlers also own all EventDev instances which ungrab the event devices.
200 * When the eventloop goes out of scope the EventDevs get destroyed
201 * relinquishing the exclusive hold on the event devices.
202 * * finalizeConfirmationPrompt - calls abort on the TA, making sure a
203 * pending operation gets canceled. If the prompt concluded successfully this
204 * is a spurious call but semantically a no op.
205 * * secureInput - shuts down the connection to the secure input device
206 * SecureInput.
207 * * app - disconnects the TA. Since app is a shared pointer this may not
208 * unload the app here. It is possible that more instances of the shared
209 * pointer are held in TrustyConfirmationUI::deliverSecureInputEvent and
210 * TrustyConfirmationUI::abort. But these instances are extremely short lived
211 * and it is safe if they are destroyed by either.
212 * * stateLock - unlocks the listener_state_lock_ if it happens to be held
213 * at the time of return.
214 */
215
216 std::tuple<TeeuiRc, MsgVector<uint8_t>, MsgVector<uint8_t>> result;
217 TeeuiRc& rc = std::get<TeeuiRc>(result);
218 rc = TeeuiRc::SystemError;
219
220 listener_state_ = ListenerState::Starting;
221
222 auto app = std::make_shared<TrustyApp>(kTrustyDeviceName, kConfirmationuiAppName);
223 if (!app) return result; // TeeuiRc::SystemError
224
225 app_ = app;
226
227 auto hsBegin = [&]() -> std::tuple<TeeuiRc, Nonce> {
228 auto [error, result] =
229 app->issueCmd<secure_input::InputHandshake, secure_input::InputHandshakeResponse>();
230 auto& [rc, nCo] = result;
231
232 if (error != TrustyAppError::OK || rc != TeeuiRc::OK) {
233 LOG(ERROR) << "Failed to begin secure input handshake (" << int32_t(error) << "/"
234 << uint32_t(rc) << ")";
235 rc = error != TrustyAppError::OK ? TeeuiRc::SystemError : rc;
236 }
237 return result;
238 };
239
240 auto hsFinalize = [&](const Signature& sig, const Nonce& nCi) -> TeeuiRc {
241 auto [error, finalizeResponse] =
242 app->issueCmd<FinalizeInputSessionHandshake, FinalizeInputSessionHandshakeResponse>(
243 nCi, sig);
244 auto& [rc] = finalizeResponse;
245 if (error != TrustyAppError::OK || rc != TeeuiRc::OK) {
246 LOG(ERROR) << "Failed to finalize secure input handshake (" << int32_t(error) << "/"
247 << uint32_t(rc) << ")";
248 rc = error != TrustyAppError::OK ? TeeuiRc::SystemError : rc;
249 }
250 return rc;
251 };
252
253 auto deliverInput = [&](DTupKeyEvent event,
254 const Signature& sig) -> std::tuple<TeeuiRc, InputResponse> {
255 auto [error, result] =
256 app->issueCmd<DeliverInputEvent, DeliverInputEventResponse>(event, sig);
257 auto& [rc, ir] = result;
258 if (error != TrustyAppError::OK) {
259 LOG(ERROR) << "Failed to deliver input command";
260 rc = TeeuiRc::SystemError;
261 }
262 return result;
263 };
264
265 std::atomic<TeeuiRc> eventRC = TeeuiRc::OperationPending;
266 auto inputResult = [&](TeeuiRc rc) {
267 TeeuiRc expected = TeeuiRc::OperationPending;
268 if (eventRC.compare_exchange_strong(expected, rc)) {
269 listener_state_condv_.notify_all();
270 }
271 };
272
273 // create Secure Input device.
274 auto secureInput = createSecureInput(hsBegin, hsFinalize, deliverInput, inputResult);
275 if (!secureInput || !(*secureInput)) {
276 LOG(ERROR) << "Failed to open secure input device";
277 return result; // TeeuiRc::SystemError;
278 }
279
280 Finalize finalizeConfirmationPrompt([app] {
281 LOG(INFO) << "Calling abort for cleanup";
282 app->issueCmd<AbortMsg>();
283 });
284
285 // initiate prompt
286 LOG(INFO) << "Initiating prompt";
287 TrustyAppError error;
288 auto initResponse = std::tie(rc);
289 std::tie(error, initResponse) =
290 app->issueCmd<PromptUserConfirmationMsg, PromptUserConfirmationResponse>(
291 promptText, extraData, locale, uiOptions);
292 if (error == TrustyAppError::MSG_TOO_LONG) {
293 LOG(ERROR) << "PromptUserConfirmationMsg failed: message too long";
294 rc = TeeuiRc::UIErrorMessageTooLong;
295 return result;
296 } else if (error != TrustyAppError::OK) {
297 LOG(ERROR) << "PromptUserConfirmationMsg failed: " << int32_t(error);
298 return result; // TeeuiRc::SystemError;
299 }
300 if (rc != TeeuiRc::OK) {
301 LOG(ERROR) << "PromptUserConfirmationMsg failed: " << uint32_t(rc);
302 return result;
303 }
304
305 LOG(INFO) << "Grabbing event devices";
306 EventLoop eventloop;
307 bool grabbed =
308 grabAllEvDevsAndRegisterCallbacks(&eventloop, [&](short flags, const EventDev& evDev) {
309 if (!(flags & POLLIN)) return;
310 secureInput->handleEvent(evDev);
311 });
312
313 if (!grabbed) {
314 rc = TeeuiRc::SystemError;
315 return result;
316 }
317
318 abort_called_ = false;
319 secureInputDelivered_ = false;
320
321 // ############################## Start 2nd Phase #############################################
322 listener_state_ = ListenerState::SetupDone;
323 stateLock.unlock();
324 listener_state_condv_.notify_all();
325
326 if (!eventloop.start()) {
327 rc = TeeuiRc::SystemError;
328 return result;
329 }
330
331 stateLock.lock();
332
333 LOG(INFO) << "going to sleep for the grace period";
334 auto then = std::chrono::system_clock::now() +
335 std::chrono::milliseconds(kUserPreInputGracePeriodMillis) +
336 std::chrono::microseconds(50);
337 listener_state_condv_.wait_until(stateLock, then, [&]() { return abort_called_; });
338 LOG(INFO) << "waking up";
339
340 if (abort_called_) {
341 LOG(ERROR) << "Abort called";
342 result = {TeeuiRc::Aborted, {}, {}};
343 return result;
344 }
345
346 LOG(INFO) << "Arming event poller";
347 // tell the event poller to act on received input events from now on.
348 secureInput->start();
349
350 // ############################## Start 3rd Phase - interactive phase #########################
351 LOG(INFO) << "Transition to Interactive";
352 listener_state_ = ListenerState::Interactive;
353 stateLock.unlock();
354 listener_state_condv_.notify_all();
355
356 stateLock.lock();
357 listener_state_condv_.wait(stateLock, [&]() {
358 return eventRC != TeeuiRc::OperationPending || abort_called_ || secureInputDelivered_;
359 });
360 LOG(INFO) << "Listener waking up";
361 if (abort_called_) {
362 LOG(ERROR) << "Abort called";
363 result = {TeeuiRc::Aborted, {}, {}};
364 return result;
365 }
366
367 if (!secureInputDelivered_) {
368 if (eventRC != TeeuiRc::OK) {
369 LOG(ERROR) << "Bad input response";
370 result = {eventRC, {}, {}};
371 return result;
372 }
373 }
374
375 stateLock.unlock();
376
377 LOG(INFO) << "Fetching Result";
378 std::tie(error, result) = app->issueCmd<FetchConfirmationResult, ResultMsg>();
379 LOG(INFO) << "Result yields " << int32_t(error) << "/" << uint32_t(rc);
380 if (error != TrustyAppError::OK) {
381 result = {TeeuiRc::SystemError, {}, {}};
382 }
383 return result;
384
385 // ############################## Start 4th Phase - cleanup ##################################
386 }
387
388 // Methods from ::android::hardware::confirmationui::V1_0::IConfirmationUI
389 // follow.
promptUserConfirmation(const sp<IConfirmationResultCallback> & resultCB,const hidl_string & promptText,const hidl_vec<uint8_t> & extraData,const hidl_string & locale,const hidl_vec<UIOption> & uiOptions)390 Return<ResponseCode> TrustyConfirmationUI::promptUserConfirmation(
391 const sp<IConfirmationResultCallback>& resultCB, const hidl_string& promptText,
392 const hidl_vec<uint8_t>& extraData, const hidl_string& locale,
393 const hidl_vec<UIOption>& uiOptions) {
394 std::unique_lock<std::mutex> stateLock(listener_state_lock_, std::defer_lock);
395 if (!stateLock.try_lock()) {
396 return ResponseCode::OperationPending;
397 }
398 switch (listener_state_) {
399 case ListenerState::None:
400 break;
401 case ListenerState::Starting:
402 case ListenerState::SetupDone:
403 case ListenerState::Interactive:
404 return ResponseCode::OperationPending;
405 case ListenerState::Terminating:
406 callback_thread_.join();
407 listener_state_ = ListenerState::None;
408 break;
409 default:
410 return ResponseCode::Unexpected;
411 }
412
413 assert(listener_state_ == ListenerState::None);
414
415 callback_thread_ = std::thread(
416 [this](sp<IConfirmationResultCallback> resultCB, hidl_string promptText,
417 hidl_vec<uint8_t> extraData, hidl_string locale, hidl_vec<UIOption> uiOptions) {
418 auto [trc, msg, token] =
419 promptUserConfirmation_(hidl2MsgString(promptText), hidl2MsgVector(extraData),
420 hidl2MsgString(locale), hidl2MsgVector(uiOptions));
421 bool do_callback = (listener_state_ == ListenerState::Interactive ||
422 listener_state_ == ListenerState::SetupDone) &&
423 resultCB;
424 prompt_result_ = convertRc(trc);
425 listener_state_ = ListenerState::Terminating;
426 if (do_callback) {
427 auto error = resultCB->result(prompt_result_, msg, token);
428 if (!error.isOk()) {
429 LOG(ERROR) << "Result callback failed " << error.description();
430 }
431 } else {
432 listener_state_condv_.notify_all();
433 }
434 },
435 resultCB, promptText, extraData, locale, uiOptions);
436
437 listener_state_condv_.wait(stateLock, [this] {
438 return listener_state_ == ListenerState::SetupDone ||
439 listener_state_ == ListenerState::Interactive ||
440 listener_state_ == ListenerState::Terminating;
441 });
442 if (listener_state_ == ListenerState::Terminating) {
443 callback_thread_.join();
444 listener_state_ = ListenerState::None;
445 return prompt_result_;
446 }
447 return ResponseCode::OK;
448 }
449
450 Return<ResponseCode>
deliverSecureInputEvent(const HardwareAuthToken & secureInputToken)451 TrustyConfirmationUI::deliverSecureInputEvent(const HardwareAuthToken& secureInputToken) {
452 ResponseCode rc = ResponseCode::Ignored;
453 {
454 /*
455 * deliverSecureInputEvent is only used by the VTS test to mock human input. A correct
456 * implementation responds with a mock confirmation token signed with a test key. The
457 * problem is that the non interactive grace period was not formalized in the HAL spec,
458 * so that the VTS test does not account for the grace period. (It probably should.)
459 * This means we can only pass the VTS test if we block until the grace period is over
460 * (SetupDone -> Interactive) before we deliver the input event.
461 *
462 * The true secure input is delivered by a different mechanism and gets ignored -
463 * not queued - until the grace period is over.
464 *
465 */
466 std::unique_lock<std::mutex> stateLock(listener_state_lock_);
467 listener_state_condv_.wait(stateLock,
468 [this] { return listener_state_ != ListenerState::SetupDone; });
469
470 if (listener_state_ != ListenerState::Interactive) return ResponseCode::Ignored;
471 auto sapp = app_.lock();
472 if (!sapp) return ResponseCode::Ignored;
473 auto [error, response] =
474 sapp->issueCmd<DeliverTestCommandMessage, DeliverTestCommandResponse>(
475 static_cast<teeui::TestModeCommands>(secureInputToken.challenge));
476 if (error != TrustyAppError::OK) return ResponseCode::SystemError;
477 auto& [trc] = response;
478 if (trc != TeeuiRc::Ignored) secureInputDelivered_ = true;
479 rc = convertRc(trc);
480 }
481 if (secureInputDelivered_) listener_state_condv_.notify_all();
482 // VTS test expect an OK response if the event was successfully delivered.
483 // But since the TA returns the callback response now, we have to translate
484 // Canceled into OK. Canceled is only returned if the delivered event canceled
485 // the operation, which means that the event was successfully delivered. Thus
486 // we return OK.
487 if (rc == ResponseCode::Canceled) return ResponseCode::OK;
488 return rc;
489 }
490
abort()491 Return<void> TrustyConfirmationUI::abort() {
492 {
493 std::unique_lock<std::mutex> stateLock(listener_state_lock_);
494 if (listener_state_ == ListenerState::SetupDone ||
495 listener_state_ == ListenerState::Interactive) {
496 auto sapp = app_.lock();
497 if (sapp) sapp->issueCmd<AbortMsg>();
498 abort_called_ = true;
499 }
500 }
501 listener_state_condv_.notify_all();
502 return Void();
503 }
504
createTrustyConfirmationUI()505 android::sp<IConfirmationUI> createTrustyConfirmationUI() {
506 return new TrustyConfirmationUI();
507 }
508
509 } // namespace implementation
510 } // namespace V1_0
511 } // namespace confirmationui
512 } // namespace hardware
513 } // namespace android
514