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