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