1 /*
2 * Copyright (C) 2022 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 #include <fcntl.h>
18 #include <inttypes.h>
19 #include <sys/epoll.h>
20 #include <sys/socket.h>
21 #include <chrono>
22 #include <limits>
23 #include <aidl/android/hardware/biometrics/common/BnCancellationSignal.h>
24 #include <android-base/unique_fd.h>
25 #include <debug.h>
26 #include <log/log.h>
27 #include <qemud.h>
28 #include <utils/Timers.h>
29
30 #include "session.h"
31 #include "storage.h"
32
33 #define SESSION_DEBUG(FMT, ...) \
34 ALOGD("%p:%s:%d: " FMT, this, __func__, __LINE__, __VA_ARGS__)
35 #define SESSION_ERR(FMT, ...) \
36 ALOGE("%p:%s:%d: " FMT, this, __func__, __LINE__, __VA_ARGS__)
37
38 #define SESSION_DEBUG0(STR) SESSION_DEBUG("%s", STR)
39
40 namespace aidl::android::hardware::biometrics::fingerprint {
41
42 using ::android::base::unique_fd;
43
44 namespace {
45 constexpr char kSensorServiceName[] = "fingerprintlisten";
46 constexpr char kSensorListenerQuitCmd = 'Q';
47
generateSeed(void * p)48 int64_t generateSeed(void* p) {
49 auto now = std::chrono::high_resolution_clock::now();
50 decltype(now) epoch;
51 return (now - epoch).count() ^ reinterpret_cast<uintptr_t>(p);
52 }
53
epollCtlAdd(int epollFd,int fd)54 int epollCtlAdd(int epollFd, int fd) {
55 int ret;
56
57 /* make the fd non-blocking */
58 ret = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL));
59 if (ret < 0) {
60 return ret;
61 }
62
63 ret = TEMP_FAILURE_RETRY(fcntl(fd, F_SETFL, ret | O_NONBLOCK));
64 if (ret < 0) {
65 return ret;
66 }
67
68 struct epoll_event ev;
69 ev.events = EPOLLIN;
70 ev.data.fd = fd;
71
72 return TEMP_FAILURE_RETRY(epoll_ctl(epollFd, EPOLL_CTL_ADD, fd, &ev));
73 }
74
vec2str(const std::vector<T> & v)75 template <class T> std::string vec2str(const std::vector<T>& v) {
76 if (v.empty()) {
77 return "empty";
78 } else {
79 std::string result;
80
81 for (const auto& x : v) {
82 if (result.empty()) {
83 result = std::to_string(x);
84 } else {
85 result += ",";
86 result += std::to_string(x);
87 }
88 }
89
90 return std::string("[") + result + std::string("]");
91 }
92 }
93
state2str(const Session::State s)94 std::string state2str(const Session::State s) {
95 switch (s) {
96 case Session::State::IDLE: return "IDLE";
97 case Session::State::ENROLLING_START: return "ENROLLING_START";
98 case Session::State::ENROLLING_END: return "ENROLLING_END";
99 case Session::State::AUTHENTICATING: return "AUTHENTICATING";
100 case Session::State::DETECTING_INTERACTION: return "DETECTING_INTERACTION";
101 default: return std::to_string(static_cast<int>(s));
102 }
103 }
104
errorCode2str(const Session::ErrorCode ec)105 std::string errorCode2str(const Session::ErrorCode ec) {
106 switch (ec) {
107 case Session::ErrorCode::OK: return "OK";
108 case Session::ErrorCode::E_HAT_MAC_EMPTY: return "E_HAT_MAC_EMPTY";
109 case Session::ErrorCode::E_HAT_WRONG_CHALLENGE: return "E_HAT_WRONG_CHALLENGE";
110 case Session::ErrorCode::E_INCORRECT_STATE: return "E_INCORRECT_STATE";
111 case Session::ErrorCode::E_ENROLL_FAILED: return "E_ENROLL_FAILED";
112 default: return std::to_string(static_cast<int>(ec));
113 }
114 }
115
116 } // namespace
117
118 struct CancellationSignal : public common::BnCancellationSignal {
CancellationSignalaidl::android::hardware::biometrics::fingerprint::CancellationSignal119 CancellationSignal(std::function<void()> cb) : mCB(std::move(cb)) {}
120
cancelaidl::android::hardware::biometrics::fingerprint::CancellationSignal121 ndk::ScopedAStatus cancel() override {
122 mCB();
123 return ndk::ScopedAStatus::ok();
124 }
125
126 const std::function<void()> mCB;
127 };
128
Session(const int32_t sensorId,const int32_t userId,std::shared_ptr<ISessionCallback> scb)129 Session::Session(const int32_t sensorId, const int32_t userId,
130 std::shared_ptr<ISessionCallback> scb)
131 : mSessionCb(std::move(scb))
132 , mStorage(sensorId, userId)
133 , mRandom(generateSeed(this))
134 {
135 SESSION_DEBUG("New session: sensorId=%d userId=%d", sensorId, userId);
136
137 if (::android::base::Socketpair(AF_LOCAL, SOCK_STREAM, 0,
138 &mCallerFd, &mSensorThreadFd)) {
139 mSensorListener = std::thread(&Session::sensorListenerFunc, this);
140 } else {
141 mSensorListener = std::thread([](){});
142 LOG_ALWAYS_FATAL("%p:%s:%d: Socketpair failed", this, __func__, __LINE__);
143 }
144 }
145
~Session()146 Session::~Session() {
147 SESSION_DEBUG0("Terminating session");
148
149 TEMP_FAILURE_RETRY(write(mCallerFd.get(), &kSensorListenerQuitCmd, 1));
150 mSensorListener.join();
151 }
152
generateChallenge()153 ndk::ScopedAStatus Session::generateChallenge() {
154 while (true) {
155 int64_t challenge;
156 {
157 std::lock_guard<std::mutex> lock(mMutex);
158 challenge = generateInt64();
159 }
160
161 if (mChallenges.insert(challenge).second) {
162 SESSION_DEBUG("onChallengeGenerated(challenge=%" PRId64 ")", challenge);
163 mSessionCb->onChallengeGenerated(challenge);
164 return ndk::ScopedAStatus::ok();
165 }
166 }
167 }
168
revokeChallenge(const int64_t challenge)169 ndk::ScopedAStatus Session::revokeChallenge(const int64_t challenge) {
170 mChallenges.erase(challenge);
171 SESSION_DEBUG("onChallengeRevoked(challenge=%" PRId64 ")", challenge);
172 mSessionCb->onChallengeRevoked(challenge);
173 return ndk::ScopedAStatus::ok();
174 }
175
enroll(const keymaster::HardwareAuthToken & hat,std::shared_ptr<common::ICancellationSignal> * out)176 ndk::ScopedAStatus Session::enroll(const keymaster::HardwareAuthToken& hat,
177 std::shared_ptr<common::ICancellationSignal>* out) {
178 const ErrorCode err = validateHat(hat);
179 if (err == ErrorCode::OK) {
180 State previousState;
181 bool ok;
182 {
183 std::lock_guard<std::mutex> lock(mMutex);
184 previousState = mState;
185 if (previousState == State::IDLE) {
186 mEnrollingSecUserId = hat.userId;
187 mState = State::ENROLLING_START;
188 ok = true;
189 } else {
190 ok = false;
191 }
192 }
193
194 if (ok) {
195 SESSION_DEBUG("ENROLLING_START hat.userId=%" PRId64, hat.userId);
196 *out = SharedRefBase::make<CancellationSignal>([this](){ cancellEnroll(); });
197 } else {
198 SESSION_ERR("onError(UNABLE_TO_PROCESS, %d): incorrect state, %s",
199 int(ErrorCode::E_INCORRECT_STATE), state2str(previousState).c_str());
200 mSessionCb->onError(Error::UNABLE_TO_PROCESS,
201 int(ErrorCode::E_INCORRECT_STATE));
202 }
203 } else {
204 SESSION_ERR("onError(UNABLE_TO_PROCESS, %d): `hat` is invalid: %s",
205 int(err), errorCode2str(err).c_str());
206 mSessionCb->onError(Error::UNABLE_TO_PROCESS, int(err));
207 }
208
209 return ndk::ScopedAStatus::ok();
210 }
211
authenticate(const int64_t operationId,std::shared_ptr<common::ICancellationSignal> * out)212 ndk::ScopedAStatus Session::authenticate(const int64_t operationId,
213 std::shared_ptr<common::ICancellationSignal>* out) {
214 State previousState;
215 bool ok;
216 {
217 std::lock_guard<std::mutex> lock(mMutex);
218 previousState = mState;
219 if (previousState == State::IDLE) {
220 mAuthChallenge = operationId;
221 mState = State::AUTHENTICATING;
222 ok = true;
223 } else {
224 ok = false;
225 }
226 }
227
228 if (ok) {
229 SESSION_DEBUG("AUTHENTICATING operationId=%" PRId64, operationId);
230 *out = SharedRefBase::make<CancellationSignal>([this](){ cancellAuthenticate(); });
231 } else {
232 SESSION_ERR("onError(UNABLE_TO_PROCESS, %d): incorrect state, %s",
233 int(ErrorCode::E_INCORRECT_STATE),
234 state2str(previousState).c_str());
235 mSessionCb->onError(Error::UNABLE_TO_PROCESS,
236 int(ErrorCode::E_INCORRECT_STATE));
237 }
238
239 return ndk::ScopedAStatus::ok();
240 }
241
detectInteraction(std::shared_ptr<common::ICancellationSignal> * out)242 ndk::ScopedAStatus Session::detectInteraction(
243 std::shared_ptr<common::ICancellationSignal>* out) {
244 State previousState;
245 bool ok;
246 {
247 std::lock_guard<std::mutex> lock(mMutex);
248 previousState = mState;
249 if (previousState == State::IDLE) {
250 mState = State::DETECTING_INTERACTION;
251 ok = true;
252 } else {
253 ok = false;
254 }
255 }
256
257 if (ok) {
258 SESSION_DEBUG0("DETECTING_INTERACTION");
259 *out = SharedRefBase::make<CancellationSignal>([this](){ cancellDetectInteraction(); });
260 } else {
261 SESSION_ERR("onError(UNABLE_TO_PROCESS, %d): incorrect state, %s",
262 int(ErrorCode::E_INCORRECT_STATE),
263 state2str(previousState).c_str());
264 mSessionCb->onError(Error::UNABLE_TO_PROCESS,
265 int(ErrorCode::E_INCORRECT_STATE));
266 }
267
268 return ndk::ScopedAStatus::ok();
269 }
270
enumerateEnrollments()271 ndk::ScopedAStatus Session::enumerateEnrollments() {
272 std::vector<int32_t> enrollmentIds;
273 {
274 std::lock_guard<std::mutex> lock(mMutex);
275 enrollmentIds = mStorage.enumerateEnrollments();
276 }
277
278 SESSION_DEBUG("onEnrollmentsEnumerated(enrollmentIds=%s)",
279 vec2str(enrollmentIds).c_str());
280 mSessionCb->onEnrollmentsEnumerated(enrollmentIds);
281 return ndk::ScopedAStatus::ok();
282 }
283
removeEnrollments(const std::vector<int32_t> & enrollmentIds)284 ndk::ScopedAStatus Session::removeEnrollments(const std::vector<int32_t>& enrollmentIds) {
285 {
286 std::lock_guard<std::mutex> lock(mMutex);
287 mStorage.removeEnrollments(enrollmentIds);
288 }
289
290 SESSION_DEBUG("onEnrollmentsRemoved(enrollmentIds=%s)",
291 vec2str(enrollmentIds).c_str());
292 mSessionCb->onEnrollmentsRemoved(enrollmentIds);
293 return ndk::ScopedAStatus::ok();
294 }
295
getAuthenticatorId()296 ndk::ScopedAStatus Session::getAuthenticatorId() {
297 int64_t authId;
298 {
299 std::lock_guard<std::mutex> lock(mMutex);
300 authId = mStorage.getAuthenticatorId();
301 }
302
303 SESSION_DEBUG("onAuthenticatorIdRetrieved(authId=%" PRId64 ")", authId);
304 mSessionCb->onAuthenticatorIdRetrieved(authId);
305 return ndk::ScopedAStatus::ok();
306 }
307
invalidateAuthenticatorId()308 ndk::ScopedAStatus Session::invalidateAuthenticatorId() {
309 int64_t authId;
310 {
311 std::lock_guard<std::mutex> lock(mMutex);
312 authId = mStorage.invalidateAuthenticatorId(generateInt64());
313 }
314
315 SESSION_DEBUG("onAuthenticatorIdInvalidated(authId=%" PRId64 ")", authId);
316 mSessionCb->onAuthenticatorIdInvalidated(authId);
317 return ndk::ScopedAStatus::ok();
318 }
319
resetLockout(const keymaster::HardwareAuthToken & hat)320 ndk::ScopedAStatus Session::resetLockout(const keymaster::HardwareAuthToken& hat) {
321 const ErrorCode err = validateHat(hat);
322 if (err == ErrorCode::OK) {
323 {
324 std::lock_guard<std::mutex> lock(mMutex);
325 mStorage.resetLockout();
326 }
327
328 SESSION_DEBUG0("onLockoutCleared");
329 mSessionCb->onLockoutCleared();
330 } else {
331 SESSION_ERR("onError(UNABLE_TO_PROCESS, %d): `hat` is invalid: %s",
332 int(err), errorCode2str(err).c_str());
333 mSessionCb->onError(Error::UNABLE_TO_PROCESS, int(err));
334 }
335 return ndk::ScopedAStatus::ok();
336 }
337
close()338 ndk::ScopedAStatus Session::close() {
339 mChallenges.clear();
340 SESSION_DEBUG0("onSessionClosed");
341 mSessionCb->onSessionClosed();
342 return ndk::ScopedAStatus::ok();
343 }
344
validateHat(const keymaster::HardwareAuthToken & hat) const345 Session::ErrorCode Session::validateHat(const keymaster::HardwareAuthToken& hat) const {
346 if (hat.mac.empty()) {
347 return FAILURE(ErrorCode::E_HAT_MAC_EMPTY);
348 }
349
350 if (!mChallenges.count(hat.challenge)) {
351 return FAILURE_V(ErrorCode::E_HAT_WRONG_CHALLENGE,
352 "unexpected challenge: %" PRId64, hat.challenge);
353 }
354
355 return ErrorCode::OK;
356 }
357
generateInt64()358 int64_t Session::generateInt64() {
359 std::uniform_int_distribution<int64_t> distrib(1, std::numeric_limits<int64_t>::max());
360 return distrib(mRandom);
361 }
362
onSensorEventOn(const int32_t enrollmentId)363 void Session::onSensorEventOn(const int32_t enrollmentId) {
364 std::lock_guard<std::mutex> lock(mMutex);
365 switch (mState) {
366 case State::ENROLLING_START:
367 case State::ENROLLING_END:
368 {
369 SESSION_DEBUG("onAcquired(GOOD, %d)", 0);
370 mSessionCb->onAcquired(AcquiredInfo::GOOD, 0);
371
372 const int left = int(State::ENROLLING_END) - int(mState);
373 if (left > 0) {
374 SESSION_DEBUG("onEnrollmentProgress(enrollmentId=%d, left=%d)",
375 enrollmentId, left);
376 mSessionCb->onEnrollmentProgress(enrollmentId, left);
377 mState = State(int(mState) + 1);
378 } else if (mStorage.enroll(enrollmentId, mEnrollingSecUserId, generateInt64())) {
379 SESSION_DEBUG("onEnrollmentProgress(enrollmentId=%d, left=%d)",
380 enrollmentId, left);
381 mSessionCb->onEnrollmentProgress(enrollmentId, left);
382 mState = State::IDLE;
383 } else {
384 SESSION_ERR("onError(UNABLE_TO_PROCESS, %d): enrollmentId=%d, "
385 "secureIserId=%" PRId64 ,
386 int(ErrorCode::E_ENROLL_FAILED),
387 enrollmentId, mEnrollingSecUserId);
388 mSessionCb->onError(Error::UNABLE_TO_PROCESS,
389 int(ErrorCode::E_ENROLL_FAILED));
390 mState = State::IDLE;
391 }
392 }
393 break;
394
395 case State::AUTHENTICATING:
396 {
397 const auto [res, lockoutDurationMillis, tok] =
398 mStorage.authenticate(enrollmentId);
399 if (res != Storage::AuthResult::LOCKED_OUT_PERMANENT) {
400 SESSION_DEBUG("onAcquired(GOOD, %d)", 0);
401 mSessionCb->onAcquired(AcquiredInfo::GOOD, 0);
402 }
403
404 switch (res) {
405 case Storage::AuthResult::OK: {
406 SESSION_DEBUG("onAuthenticationSucceeded(enrollmentId=%d, "
407 "hat={ .challenge=%" PRId64 ", .userId=%" PRId64 ", "
408 ".authenticatorId=%" PRId64 " })",
409 enrollmentId, mAuthChallenge,
410 tok.userId, tok.authenticatorId);
411
412 keymaster::HardwareAuthToken hat;
413 hat.challenge = mAuthChallenge;
414 hat.userId = tok.userId;
415 hat.authenticatorId = tok.authenticatorId;
416 hat.authenticatorType = keymaster::HardwareAuthenticatorType::FINGERPRINT;
417 hat.timestamp.milliSeconds = ns2ms(systemTime(SYSTEM_TIME_BOOTTIME));
418 mSessionCb->onAuthenticationSucceeded(enrollmentId, hat);
419 mState = State::IDLE;
420 }
421 break;
422
423 case Storage::AuthResult::FAILED:
424 SESSION_ERR("onAuthenticationFailed: enrollmentId=%d", enrollmentId);
425 mSessionCb->onAuthenticationFailed();
426 break;
427
428 case Storage::AuthResult::LOCKED_OUT_TIMED:
429 SESSION_ERR("onLockoutTimed(durationMillis=%d): enrollmentId=%d",
430 lockoutDurationMillis, enrollmentId);
431 mSessionCb->onLockoutTimed(lockoutDurationMillis);
432 mState = State::IDLE;
433 break;
434
435 case Storage::AuthResult::LOCKED_OUT_PERMANENT:
436 SESSION_ERR("onLockoutPermanent: enrollmentId=%d", enrollmentId);
437 mSessionCb->onLockoutPermanent();
438 mState = State::IDLE;
439 break;
440
441 default:
442 LOG_ALWAYS_FATAL("%p:%s:%d: Unexpected result from `mStorage.authenticate`",
443 this, __func__, __LINE__);
444 break;
445 }
446 }
447 break;
448
449 case State::DETECTING_INTERACTION:
450 mSessionCb->onInteractionDetected();
451 mState = State::IDLE;
452 break;
453
454 case State::IDLE:
455 break;
456
457 default:
458 LOG_ALWAYS_FATAL("%p:%s:%d: Unexpected session state", this, __func__, __LINE__);
459 break;
460 }
461 }
462
onSensorEventOff()463 void Session::onSensorEventOff() {}
464
cancellEnroll()465 void Session::cancellEnroll() {
466 {
467 std::lock_guard<std::mutex> lock(mMutex);
468 if ((mState >= State::ENROLLING_START) && (mState <= State::ENROLLING_END)) {
469 mState = State::IDLE;
470 }
471 }
472
473 SESSION_DEBUG("onError(CANCELED, %d)", 0);
474 mSessionCb->onError(Error::CANCELED, 0);
475 }
476
cancellAuthenticate()477 void Session::cancellAuthenticate() {
478 {
479 std::lock_guard<std::mutex> lock(mMutex);
480 if (mState == State::AUTHENTICATING) {
481 mState = State::IDLE;
482 }
483 }
484
485 SESSION_DEBUG("onError(CANCELED, %d)", 0);
486 mSessionCb->onError(Error::CANCELED, 0);
487 }
488
cancellDetectInteraction()489 void Session::cancellDetectInteraction() {
490 {
491 std::lock_guard<std::mutex> lock(mMutex);
492 if (mState == State::DETECTING_INTERACTION) {
493 mState = State::IDLE;
494 }
495 }
496
497 SESSION_DEBUG("onError(CANCELED, %d)", 0);
498 mSessionCb->onError(Error::CANCELED, 0);
499 }
500
sensorListenerFuncImpl()501 bool Session::sensorListenerFuncImpl() {
502 unique_fd sensorFd(qemud_channel_open(kSensorServiceName));
503 LOG_ALWAYS_FATAL_IF(!sensorFd.ok(),
504 "%p:%s:%d: Could not open the sensor service: '%s'",
505 this, __func__, __LINE__, kSensorServiceName);
506
507 const unique_fd epollFd(epoll_create1(EPOLL_CLOEXEC));
508 epollCtlAdd(epollFd.get(), sensorFd.get());
509 epollCtlAdd(epollFd.get(), mSensorThreadFd.get());
510
511 qemud_channel_send(sensorFd.get(), "listen", 6);
512
513 while (true) {
514 const int kTimeoutMs = 250;
515 struct epoll_event event;
516 const int n = TEMP_FAILURE_RETRY(epoll_wait(epollFd.get(),
517 &event, 1,
518 kTimeoutMs));
519 if (n <= 0) {
520 bool lockoutCleared;
521 {
522 std::lock_guard<std::mutex> lock(mMutex);
523 lockoutCleared = mStorage.checkIfLockoutCleared();
524 }
525
526 if (lockoutCleared) {
527 SESSION_DEBUG0("onLockoutCleared");
528 mSessionCb->onLockoutCleared();
529 }
530 continue;
531 }
532
533 const int fd = event.data.fd;
534 const int ev_events = event.events;
535 if (fd == sensorFd.get()) {
536 if (ev_events & (EPOLLERR | EPOLLHUP)) {
537 SESSION_ERR("epoll_wait: devFd has an error, ev_events=%x", ev_events);
538 return true;
539 } else if (ev_events & EPOLLIN) {
540 char buf[64];
541 int n = qemud_channel_recv(fd, buf, sizeof(buf) - 1);
542 if (n > 0) {
543 buf[n] = 0;
544 int32_t fid;
545 if (sscanf(buf, "on:%d", &fid) == 1) {
546 if (fid > 0) {
547 onSensorEventOn(fid);
548 } else {
549 SESSION_ERR("incorrect fingerprint: %d", fid);
550 }
551 } else if (!strcmp(buf, "off")) {
552 onSensorEventOff();
553 } else {
554 SESSION_ERR("unexpected hw message: '%s'", buf);
555 return true;
556 }
557 } else {
558 SESSION_ERR("hw read error, n=%d, errno=%d", n, errno);
559 return true;
560 }
561 }
562 } else if (fd == mSensorThreadFd.get()) {
563 if (ev_events & (EPOLLERR | EPOLLHUP)) {
564 LOG_ALWAYS_FATAL("%p:%s:%d: epoll_wait: threadsFd has an error, ev_events=%x",
565 this, __func__, __LINE__, ev_events);
566 } else if (ev_events & EPOLLIN) {
567 char cmd;
568 int n = TEMP_FAILURE_RETRY(read(fd, &cmd, sizeof(cmd)));
569 if (n == 1) {
570 switch (cmd) {
571 case kSensorListenerQuitCmd:
572 return false; // quit
573
574 default:
575 LOG_ALWAYS_FATAL("%p:%s:%d: unexpected command, cmd=%c",
576 this, __func__, __LINE__, cmd);
577 break;
578 }
579 } else {
580 LOG_ALWAYS_FATAL("%p:%s:%d: error readind from mThreadsFd, errno=%d",
581 this, __func__, __LINE__, errno);
582 }
583 }
584 } else {
585 SESSION_ERR("%s", "epoll_wait() returned unexpected fd");
586 }
587 }
588 }
589
590 } // namespace aidl::android::hardware::biometrics::fingerprint
591