1 /*
2  * Copyright (C) 2024 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 "aidl_service.h"
18 
19 #include <algorithm>
20 #include <cstddef>
21 #include <cstdint>
22 #include <cstdlib>
23 #include <cstring>
24 #include <limits>
25 #include <memory>
26 #include <vector>
27 
28 #include <trusty_ipc.h>
29 
30 #include <interface/storage/storage_aidl/ports.h>
31 
32 #include <binder/RpcServerTrusty.h>
33 #include <binder/Status.h>
34 #include <utils/Errors.h>
35 
36 #include <android/hardware/security/see/storage/BnDir.h>
37 #include <android/hardware/security/see/storage/BnFile.h>
38 #include <android/hardware/security/see/storage/BnSecureStorage.h>
39 #include <android/hardware/security/see/storage/BnStorageSession.h>
40 #include <android/hardware/security/see/storage/CreationMode.h>
41 #include <android/hardware/security/see/storage/DeleteOptions.h>
42 #include <android/hardware/security/see/storage/FileAvailability.h>
43 #include <android/hardware/security/see/storage/FileIntegrity.h>
44 #include <android/hardware/security/see/storage/FileMode.h>
45 #include <android/hardware/security/see/storage/FileProperties.h>
46 #include <android/hardware/security/see/storage/IDir.h>
47 #include <android/hardware/security/see/storage/IFile.h>
48 #include <android/hardware/security/see/storage/ISecureStorage.h>
49 #include <android/hardware/security/see/storage/IStorageSession.h>
50 #include <android/hardware/security/see/storage/OpenOptions.h>
51 #include <android/hardware/security/see/storage/ReadIntegrity.h>
52 #include <android/hardware/security/see/storage/RenameOptions.h>
53 
54 #include "client.h"
55 #include "client_session.h"
56 #include "file.h"
57 #include "storage_limits.h"
58 
59 using ::android::RpcServerTrusty;
60 using ::android::RpcSession;
61 using ::android::sp;
62 using ::android::wp;
63 using ::android::binder::Status;
64 using ::android::hardware::security::see::storage::BnDir;
65 using ::android::hardware::security::see::storage::BnFile;
66 using ::android::hardware::security::see::storage::BnSecureStorage;
67 using ::android::hardware::security::see::storage::BnStorageSession;
68 using ::android::hardware::security::see::storage::CreationMode;
69 using ::android::hardware::security::see::storage::DeleteOptions;
70 using ::android::hardware::security::see::storage::FileAvailability;
71 using ::android::hardware::security::see::storage::FileIntegrity;
72 using ::android::hardware::security::see::storage::FileMode;
73 using ::android::hardware::security::see::storage::FileProperties;
74 using ::android::hardware::security::see::storage::IDir;
75 using ::android::hardware::security::see::storage::IFile;
76 using ::android::hardware::security::see::storage::ISecureStorage;
77 using ::android::hardware::security::see::storage::IStorageSession;
78 using ::android::hardware::security::see::storage::OpenOptions;
79 using ::android::hardware::security::see::storage::ReadIntegrity;
80 using ::android::hardware::security::see::storage::RenameOptions;
81 
82 #define SS_ERR(args...) fprintf(stderr, "ss-aidl: " args)
83 
84 namespace storage_service {
85 namespace {
86 
87 constexpr uint32_t kAclFlags =
88 #if TEST_BUILD
89         IPC_PORT_ALLOW_TA_CONNECT | IPC_PORT_ALLOW_NS_CONNECT;
90 #else
91         IPC_PORT_ALLOW_TA_CONNECT;
92 #endif
93 
94 constexpr size_t kMaxBufferSize = STORAGE_MAX_BUFFER_SIZE;
95 
status_from_storage_err(storage_err err)96 static Status status_from_storage_err(storage_err err) {
97     switch (err) {
98     case storage_err::STORAGE_NO_ERROR:
99         return Status::ok();
100     case storage_err::STORAGE_ERR_GENERIC:
101         return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
102     case storage_err::STORAGE_ERR_NOT_VALID:
103         return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
104     case storage_err::STORAGE_ERR_UNIMPLEMENTED:
105         return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION);
106     case storage_err::STORAGE_ERR_ACCESS:
107         return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
108     case storage_err::STORAGE_ERR_NOT_FOUND:
109         return Status::fromServiceSpecificError(ISecureStorage::ERR_NOT_FOUND);
110     case storage_err::STORAGE_ERR_EXIST:
111         return Status::fromServiceSpecificError(
112                 ISecureStorage::ERR_ALREADY_EXISTS);
113     case storage_err::STORAGE_ERR_TRANSACT:
114         return Status::fromServiceSpecificError(
115                 ISecureStorage::ERR_BAD_TRANSACTION);
116     case storage_err::STORAGE_ERR_NOT_ALLOWED:
117         return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
118     case storage_err::STORAGE_ERR_CORRUPTED:
119         return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
120     case storage_err::STORAGE_ERR_FS_REPAIRED:
121         // TODO: Distinguish rolled back vs reset; catch other tampering
122         return Status::fromServiceSpecificError(
123                 ISecureStorage::ERR_FS_ROLLED_BACK);
124     default:
125         return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION,
126                                          "Unknown error code.");
127     }
128 }
129 
create_mode(CreationMode mode)130 static file_create_mode create_mode(CreationMode mode) {
131     switch (mode) {
132     case CreationMode::CREATE_EXCLUSIVE:
133         return file_create_mode::FILE_OPEN_CREATE_EXCLUSIVE;
134     case CreationMode::CREATE:
135         return file_create_mode::FILE_OPEN_CREATE;
136     case CreationMode::NO_CREATE:
137         return file_create_mode::FILE_OPEN_NO_CREATE;
138     }
139 }
140 
get_fs(const FileProperties & properties,storage_aidl_filesystem * out)141 static Status get_fs(const FileProperties& properties,
142                      storage_aidl_filesystem* out) {
143     switch (properties.integrity) {
144     case FileIntegrity::TAMPER_PROOF_AT_REST: {
145         // TP is persistent and available before userdata
146         *out = STORAGE_AIDL_TP;
147         break;
148     }
149     case FileIntegrity::TAMPER_DETECT:
150     case FileIntegrity::TAMPER_DETECT_IGNORE_RESET: {
151         switch (properties.availability) {
152         case FileAvailability::BEFORE_USERDATA: {
153             if (properties.persistent) {
154                 return Status::fromExceptionCode(
155                         Status::EX_UNSUPPORTED_OPERATION,
156                         "Unsupported FileProperties: TDEA does not guarantee persistence");
157             }
158             *out = STORAGE_AIDL_TDEA;
159             break;
160         }
161         case FileAvailability::AFTER_USERDATA: {
162             *out = properties.persistent ? STORAGE_AIDL_TDP : STORAGE_AIDL_TD;
163             break;
164         }
165         default:
166             return Status::fromExceptionCode(
167                     Status::EX_UNSUPPORTED_OPERATION,
168                     "Unsupported FileProperties: Unknown FileAvailability value");
169         }
170         break;
171     }
172     default:
173         return Status::fromExceptionCode(
174                 Status::EX_UNSUPPORTED_OPERATION,
175                 "Unsupported FileProperties: Unknown FileIntegrity value");
176     }
177     return Status::ok();
178 }
179 
180 class StorageClientSession {
181 public:
StorageClientSession(struct fs * fs,storage_aidl_filesystem fs_type,const uuid_t * peer)182     StorageClientSession(struct fs* fs,
183                          storage_aidl_filesystem fs_type,
184                          const uuid_t* peer)
185             : inner_(), fs_type_(fs_type), active_(false) {
186         storage_client_session_init(&inner_, fs, peer);
187         active_ = true;
188     }
~StorageClientSession()189     ~StorageClientSession() { Deactivate(); }
190 
get()191     storage_client_session* get() { return active_ ? &inner_ : nullptr; }
fs_type()192     storage_aidl_filesystem fs_type() { return fs_type_; }
193 
Deactivate()194     void Deactivate() {
195         active_ = false;
196         storage_client_session_destroy(&inner_);
197     }
198 
199 private:
200     storage_client_session inner_;
201     storage_aidl_filesystem fs_type_;
202     bool active_;
203 };
204 
205 class Dir : public BnDir {
206 public:
Dir(std::weak_ptr<StorageClientSession> session,ReadIntegrity integrity)207     Dir(std::weak_ptr<StorageClientSession> session, ReadIntegrity integrity)
208             : session_(std::move(session)),
209               integrity_(integrity),
210               last_state_(storage_file_list_flag::STORAGE_FILE_LIST_START),
211               last_name_() {}
212 
readNextFilenames(int32_t max_count,std::vector<std::string> * out)213     Status readNextFilenames(int32_t max_count,
214                              std::vector<std::string>* out) final {
215         constexpr size_t kMaxFilenames = STORAGE_MAX_BUFFER_SIZE / FS_PATH_MAX;
216 
217         if (max_count < 0) {
218             return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
219                                              "maxCount must not be negative.");
220         }
221         size_t max_names = (max_count == 0)
222                                    ? kMaxFilenames
223                                    : std::min(kMaxFilenames,
224                                               static_cast<size_t>(max_count));
225 
226         std::shared_ptr<StorageClientSession> session = session_.lock();
227         if (session == nullptr) {
228             return Status::fromExceptionCode(
229                     Status::EX_ILLEGAL_STATE,
230                     "IDir cannot be used after its parent session has been destroyed.");
231         }
232         storage_client_session* client_session = session->get();
233         if (client_session == nullptr) {
234             return Status::fromExceptionCode(
235                     Status::EX_ILLEGAL_STATE,
236                     "Connection to underlying filesystem lost. Start a new session.");
237         }
238 
239         if (last_state_ == storage_file_list_flag::STORAGE_FILE_LIST_END) {
240             return Status::ok();
241         }
242 
243         ListCallbackData data = {
244                 .out = out,
245                 .curr_flags = last_state_,
246         };
247 
248         storage_err result = storage_file_list(
249                 client_session, max_names, last_state_, last_name_.data(),
250                 last_name_.size(), op_flags(),
251                 [](void* callback_data, size_t max_path_len) { return true; },
252                 [](void* callback_data, enum storage_file_list_flag flags,
253                    const char* path, size_t path_len) {
254                     auto& data = *static_cast<ListCallbackData*>(callback_data);
255 
256                     data.curr_flags = flags;
257                     if (flags ==
258                         storage_file_list_flag::STORAGE_FILE_LIST_END) {
259                         return;
260                     }
261 
262                     data.out->emplace_back(path, path_len);
263 
264                     // TODO: Do we need to tell the caller whether the file is
265                     // committed, added, removed?
266                 },
267                 &data);
268 
269         last_state_ = data.curr_flags;
270         last_name_ = out->empty() ? "" : out->back();
271 
272         return status_from_storage_err(result);
273     }
274 
275 private:
276     struct ListCallbackData {
277         std::vector<std::string>* out;
278         enum storage_file_list_flag curr_flags;
279     };
280 
op_flags()281     storage_op_flags op_flags() {
282         return storage_op_flags{
283                 // TODO: support acking reset only
284                 .allow_repaired = integrity_ == ReadIntegrity::IGNORE_ROLLBACK,
285                 .complete_transaction = false,
286                 .update_checkpoint = false,
287         };
288     }
289 
290     std::weak_ptr<StorageClientSession> session_;
291     ReadIntegrity integrity_;
292 
293     enum storage_file_list_flag last_state_;
294     std::string last_name_;
295 };
296 
297 class File : public BnFile {
298 public:
File(std::weak_ptr<StorageClientSession> session,uint32_t file_handle,FileMode access_mode,ReadIntegrity integrity,bool allow_writes_during_ab_update)299     File(std::weak_ptr<StorageClientSession> session,
300          uint32_t file_handle,
301          FileMode access_mode,
302          ReadIntegrity integrity,
303          bool allow_writes_during_ab_update)
304             : session_(std::move(session)),
305               file_handle_(file_handle),
306               access_mode_(access_mode),
307               integrity_(integrity),
308               allow_writes_during_ab_update_(allow_writes_during_ab_update) {
309         assert(!allow_writes_during_ab_update_);
310     }
311 
~File()312     ~File() {
313         std::shared_ptr<StorageClientSession> session = session_.lock();
314         if (session == nullptr) {
315             return;
316         }
317         storage_client_session* client_session = session->get();
318         if (client_session == nullptr) {
319             return;
320         }
321 
322         (void)storage_file_close(client_session, file_handle_, op_flags());
323     }
324 
read(int64_t size,int64_t offset,std::vector<uint8_t> * out)325     Status read(int64_t size, int64_t offset, std::vector<uint8_t>* out) final {
326         if (access_mode_ != FileMode::READ_ONLY &&
327             access_mode_ != FileMode::READ_WRITE) {
328             return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
329                                              "File not opened for reading.");
330         }
331         if (size < 0) {
332             return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
333                                              "Size must not be negative.");
334         }
335         if (size > std::numeric_limits<uint32_t>::max()) {
336             return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
337                                              "Size would overflow");
338         }
339         if (offset < 0) {
340             return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
341                                              "Offset must not be negative.");
342         }
343         std::shared_ptr<StorageClientSession> session = session_.lock();
344         if (session == nullptr) {
345             return Status::fromExceptionCode(
346                     Status::EX_ILLEGAL_STATE,
347                     "IFile cannot be used after its parent session has been destroyed.");
348         }
349         storage_client_session* client_session = session->get();
350         if (client_session == nullptr) {
351             return Status::fromExceptionCode(
352                     Status::EX_ILLEGAL_STATE,
353                     "Connection to underlying filesystem lost. Start a new session.");
354         }
355 
356         out->resize(
357                 std::min(size, static_cast<int64_t>(STORAGE_MAX_BUFFER_SIZE)));
358         size_t out_len = out->size();
359 
360         storage_err result =
361                 storage_file_read(client_session, file_handle_, size, offset,
362                                   op_flags(), out->data(), &out_len);
363 
364         out->resize(out_len);
365         return status_from_storage_err(result);
366     }
367 
write(int64_t offset,const std::vector<uint8_t> & buffer,int64_t * out)368     Status write(int64_t offset,
369                  const std::vector<uint8_t>& buffer,
370                  int64_t* out) final {
371         if (access_mode_ != FileMode::WRITE_ONLY &&
372             access_mode_ != FileMode::READ_WRITE) {
373             return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
374                                              "File not opened for writing.");
375         }
376         if (offset < 0) {
377             return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
378                                              "Offset must not be negative.");
379         }
380         std::shared_ptr<StorageClientSession> session = session_.lock();
381         if (session == nullptr) {
382             return Status::fromExceptionCode(
383                     Status::EX_ILLEGAL_STATE,
384                     "IFile cannot be used after its parent session has been destroyed.");
385         }
386         storage_client_session* client_session = session->get();
387         if (client_session == nullptr) {
388             return Status::fromExceptionCode(
389                     Status::EX_ILLEGAL_STATE,
390                     "Connection to underlying filesystem lost. Start a new session.");
391         }
392 
393         storage_err result =
394                 storage_file_write(session->get(), file_handle_, offset,
395                                    buffer.data(), buffer.size(), op_flags());
396         if (result != storage_err::STORAGE_NO_ERROR) {
397             return status_from_storage_err(result);
398         }
399 
400         *out = buffer.size();
401         return Status::ok();
402     }
403 
getSize(int64_t * out)404     Status getSize(int64_t* out) final {
405         std::shared_ptr<StorageClientSession> session = session_.lock();
406         if (session == nullptr) {
407             return Status::fromExceptionCode(
408                     Status::EX_ILLEGAL_STATE,
409                     "IFile cannot be used after its parent session has been destroyed.");
410         }
411         storage_client_session* client_session = session->get();
412         if (client_session == nullptr) {
413             return Status::fromExceptionCode(
414                     Status::EX_ILLEGAL_STATE,
415                     "Connection to underlying filesystem lost. Start a new session.");
416         }
417 
418         uint64_t size;
419         storage_err result = storage_file_get_size(session->get(), file_handle_,
420                                                    op_flags(), &size);
421         if (result != storage_err::STORAGE_NO_ERROR) {
422             return status_from_storage_err(result);
423         }
424 
425         if (size > std::numeric_limits<int64_t>::max()) {
426             return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE,
427                                              "Size would overflow");
428         }
429         *out = static_cast<int64_t>(size);
430         return Status::ok();
431     }
432 
setSize(int64_t new_size)433     Status setSize(int64_t new_size) final {
434         if (access_mode_ != FileMode::WRITE_ONLY &&
435             access_mode_ != FileMode::READ_WRITE) {
436             return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
437                                              "File not opened for writing.");
438         }
439         std::shared_ptr<StorageClientSession> session = session_.lock();
440         if (session == nullptr) {
441             return Status::fromExceptionCode(
442                     Status::EX_ILLEGAL_STATE,
443                     "IFile cannot be used after its parent session has been destroyed.");
444         }
445         storage_client_session* client_session = session->get();
446         if (client_session == nullptr) {
447             return Status::fromExceptionCode(
448                     Status::EX_ILLEGAL_STATE,
449                     "Connection to underlying filesystem lost. Start a new session.");
450         }
451 
452         storage_err result = storage_file_set_size(session->get(), file_handle_,
453                                                    new_size, op_flags());
454         return status_from_storage_err(result);
455     }
456 
rename(const std::string & new_name,CreationMode dest_create_mode)457     Status rename(const std::string& new_name, CreationMode dest_create_mode) {
458         if (access_mode_ != FileMode::WRITE_ONLY &&
459             access_mode_ != FileMode::READ_WRITE) {
460             return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
461                                              "File not opened for writing.");
462         }
463         std::shared_ptr<StorageClientSession> session = session_.lock();
464         if (session == nullptr) {
465             return Status::fromExceptionCode(
466                     Status::EX_ILLEGAL_STATE,
467                     "IFile cannot be used after its parent session has been destroyed.");
468         }
469         storage_client_session* client_session = session->get();
470         if (client_session == nullptr) {
471             return Status::fromExceptionCode(
472                     Status::EX_ILLEGAL_STATE,
473                     "Connection to underlying filesystem lost. Start a new session.");
474         }
475 
476         storage_err result = storage_file_move(
477                 session->get(), file_handle_, true, nullptr, 0, new_name.data(),
478                 new_name.size(), create_mode(dest_create_mode), op_flags());
479         return status_from_storage_err(result);
480     }
481 
482 private:
op_flags()483     storage_op_flags op_flags() {
484         return storage_op_flags{
485                 // TODO: support acking reset only
486                 .allow_repaired = integrity_ == ReadIntegrity::IGNORE_ROLLBACK,
487                 .complete_transaction = false,
488                 .update_checkpoint = false,
489         };
490     }
491 
492     std::weak_ptr<StorageClientSession> session_;
493     uint32_t file_handle_;
494     FileMode access_mode_;
495     ReadIntegrity integrity_;
496     bool allow_writes_during_ab_update_;
497 };
498 
499 class StorageSession : public BnStorageSession {
500 public:
StorageSession(std::shared_ptr<StorageClientSession> session)501     StorageSession(std::shared_ptr<StorageClientSession> session)
502             : session_(std::move(session)) {}
503 
commitChanges()504     Status commitChanges() final { return endTransactions(true); }
abandonChanges()505     Status abandonChanges() final { return endTransactions(false); }
506 
openFile(const std::string & file_name,const OpenOptions & options,sp<IFile> * out)507     Status openFile(const std::string& file_name,
508                     const OpenOptions& options,
509                     sp<IFile>* out) final {
510         if (options.allowWritesDuringAbUpdate) {
511             return Status::fromExceptionCode(
512                     Status::EX_UNSUPPORTED_OPERATION,
513                     "Unsupported option: allowWritesDuringAbUpdate");
514         }
515         storage_client_session* client_session = session_->get();
516         if (client_session == nullptr) {
517             return Status::fromExceptionCode(
518                     Status::EX_ILLEGAL_STATE,
519                     "Connection to underlying filesystem lost. Start a new session.");
520         }
521 
522         uint32_t file_handle;
523         storage_err err = storage_file_open(
524                 client_session, file_name.data(), file_name.size(),
525                 create_mode(options.createMode), options.truncateOnOpen,
526                 storage_op_flags{
527                         // TODO: support acking reset only
528                         .allow_repaired = options.readIntegrity ==
529                                           ReadIntegrity::IGNORE_ROLLBACK,
530                         .complete_transaction = false,
531                         .update_checkpoint = false,
532                 },
533                 &file_handle);
534         if (err != storage_err::STORAGE_NO_ERROR) {
535             return status_from_storage_err(err);
536         }
537 
538         *out = sp<File>::make(session_, file_handle, options.accessMode,
539                               options.readIntegrity,
540                               options.allowWritesDuringAbUpdate);
541         return Status::ok();
542     }
543 
deleteFile(const std::string & file_name,const DeleteOptions & options)544     Status deleteFile(const std::string& file_name,
545                       const DeleteOptions& options) final {
546         if (options.allowWritesDuringAbUpdate) {
547             return Status::fromExceptionCode(
548                     Status::EX_UNSUPPORTED_OPERATION,
549                     "Unsupported option: allowWritesDuringAbUpdate");
550         }
551         storage_client_session* client_session = session_->get();
552         if (client_session == nullptr) {
553             return Status::fromExceptionCode(
554                     Status::EX_ILLEGAL_STATE,
555                     "Connection to underlying filesystem lost. Start a new session.");
556         }
557 
558         storage_err err = storage_file_delete(
559                 client_session, file_name.data(), file_name.size(),
560                 storage_op_flags{
561                         // TODO: support acking reset only
562                         .allow_repaired = options.readIntegrity ==
563                                           ReadIntegrity::IGNORE_ROLLBACK,
564                         .complete_transaction = false,
565                         .update_checkpoint = false,
566                 });
567         return status_from_storage_err(err);
568     }
569 
renameFile(const std::string & file_name,const std::string & new_name,const RenameOptions & options)570     Status renameFile(const std::string& file_name,
571                       const std::string& new_name,
572                       const RenameOptions& options) final {
573         if (options.allowWritesDuringAbUpdate) {
574             return Status::fromExceptionCode(
575                     Status::EX_UNSUPPORTED_OPERATION,
576                     "Unsupported option: allowWritesDuringAbUpdate");
577         }
578         storage_client_session* client_session = session_->get();
579         if (client_session == nullptr) {
580             return Status::fromExceptionCode(
581                     Status::EX_ILLEGAL_STATE,
582                     "Connection to underlying filesystem lost. Start a new session.");
583         }
584 
585         storage_err err = storage_file_move(
586                 client_session, 0, false, file_name.data(), file_name.size(),
587                 new_name.data(), new_name.size(),
588                 create_mode(options.destCreateMode),
589                 storage_op_flags{
590                         // TODO: support acking reset only
591                         .allow_repaired = options.readIntegrity ==
592                                           ReadIntegrity::IGNORE_ROLLBACK,
593                         .complete_transaction = false,
594                         .update_checkpoint = false,
595                 });
596         return status_from_storage_err(err);
597     }
598 
openDir(const std::string & file_name,ReadIntegrity integrity,sp<IDir> * out)599     Status openDir(const std::string& file_name,
600                    ReadIntegrity integrity,
601                    sp<IDir>* out) final {
602         if (!file_name.empty()) {
603             return Status::fromExceptionCode(
604                     Status::EX_ILLEGAL_ARGUMENT,
605                     "Service currently only supports opening the root dir.");
606         }
607         if (session_->get() == nullptr) {
608             return Status::fromExceptionCode(
609                     Status::EX_ILLEGAL_STATE,
610                     "Connection to underlying filesystem lost. Start a new session.");
611         }
612 
613         // TODO: Catch tampering?
614         *out = sp<Dir>::make(session_, integrity);
615         return Status::ok();
616     }
617 
618 private:
endTransactions(bool commit_changes)619     Status endTransactions(bool commit_changes) {
620         storage_op_flags flags = {
621                 .allow_repaired = false,
622                 .complete_transaction = commit_changes,
623                 // TODO: Allow updating checkpoint
624                 .update_checkpoint = false,
625         };
626 
627         storage_client_session* client_session = session_->get();
628         if (client_session == nullptr) {
629             return Status::fromExceptionCode(
630                     Status::EX_ILLEGAL_STATE,
631                     "Connection to underlying filesystem lost. Start a new session.");
632         }
633         storage_err result = storage_transaction_end(client_session, flags);
634         return status_from_storage_err(result);
635     }
636 
637     std::shared_ptr<StorageClientSession> session_;
638 };
639 
640 class StorageService {
641 public:
MakeSession(const FileProperties & file_properties,const uuid_t * peer,std::shared_ptr<StorageClientSession> * out)642     Status MakeSession(const FileProperties& file_properties,
643                        const uuid_t* peer,
644                        std::shared_ptr<StorageClientSession>* out) {
645         storage_aidl_filesystem fs_type;
646         Status result = get_fs(file_properties, &fs_type);
647         if (!result.isOk()) {
648             return result;
649         }
650 
651         struct fs* fs = filesystems_[fs_type];
652         if (fs == nullptr) {
653             return Status::fromStatusT(android::WOULD_BLOCK);
654         }
655 
656         std::erase_if(sessions_,
657                       [](const std::weak_ptr<StorageClientSession>& session) {
658                           return session.expired();
659                       });
660 
661         *out = std::make_shared<StorageClientSession>(fs, fs_type, peer);
662         sessions_.emplace_back(*out);
663         return Status::ok();
664     }
665 
DeactivateFilesystem(storage_aidl_filesystem fs_type)666     void DeactivateFilesystem(storage_aidl_filesystem fs_type) {
667         if (filesystems_[fs_type] == nullptr) {
668             SS_ERR("Deactivating fs that's already inactive: %d", fs_type);
669             return;
670         }
671 
672         filesystems_[fs_type] = nullptr;
673 
674         for (auto it = sessions_.begin(); it != sessions_.end();) {
675             auto session = it->lock();
676             if (session == nullptr) {
677                 it = sessions_.erase(it);
678                 continue;
679             }
680 
681             if (session->fs_type() == fs_type) {
682                 session->Deactivate();
683             }
684             ++it;
685         }
686     }
687 
ActivateFilesystem(struct fs * fs,storage_aidl_filesystem fs_type)688     void ActivateFilesystem(struct fs* fs, storage_aidl_filesystem fs_type) {
689         if (filesystems_[fs_type] != nullptr) {
690             SS_ERR("Reactivating fs that's already active: %d", fs_type);
691             DeactivateFilesystem(fs_type);
692         }
693 
694         filesystems_[fs_type] = fs;
695 
696         std::erase_if(sessions_,
697                       [](const std::weak_ptr<StorageClientSession>& session) {
698                           return session.expired();
699                       });
700     }
701 
702 private:
703     std::array<struct fs*, STORAGE_AIDL_FILESYSTEMS_COUNT> filesystems_;
704     std::vector<std::weak_ptr<StorageClientSession>> sessions_;
705 };
706 
707 class SecureStorage : public BnSecureStorage {
708 public:
SecureStorage(StorageService * service,uuid_t peer)709     SecureStorage(StorageService* service, uuid_t peer)
710             : service_(service), peer_(peer) {}
711 
startSession(const FileProperties & file_properties,sp<IStorageSession> * out)712     Status startSession(const FileProperties& file_properties,
713                         sp<IStorageSession>* out) final {
714         std::shared_ptr<StorageClientSession> session;
715         Status result =
716                 service_->MakeSession(file_properties, &peer_, &session);
717         if (!result.isOk()) {
718             return result;
719         }
720 
721         *out = sp<StorageSession>::make(std::move(session));
722         return Status::ok();
723     }
724 
725 private:
726     StorageService* service_;
727     uuid_t peer_;
728 };
729 
730 }  // namespace
731 }  // namespace storage_service
732 
733 struct storage_service_aidl_context_inner {
734     sp<RpcServerTrusty> aidl_srv;
735     storage_service::StorageService service;
736 };
737 
storage_aidl_create_service(struct storage_service_aidl_context * ctx,struct tipc_hset * hset)738 int storage_aidl_create_service(struct storage_service_aidl_context* ctx,
739                                 struct tipc_hset* hset) {
740     auto result = std::make_unique<storage_service_aidl_context_inner>();
741     auto& service = result->service;
742 
743     auto port_acl =
744             RpcServerTrusty::PortAcl{.flags = storage_service::kAclFlags};
745     auto aidl_srv = RpcServerTrusty::make(
746             hset, STORAGE_ISECURE_STORAGE_PORT,
747             std::make_shared<const RpcServerTrusty::PortAcl>(port_acl),
748             storage_service::kMaxBufferSize);
749     if (aidl_srv == nullptr) {
750         return EXIT_FAILURE;
751     }
752 
753     aidl_srv->setPerSessionRootObject([&service](wp<RpcSession> session,
754                                                  const void* peer,
755                                                  size_t peer_size)
756                                               -> sp<storage_service::
757                                                             SecureStorage> {
758         if (peer_size != sizeof(uuid_t)) {
759             SS_ERR("Creating binder root object, but peer id had unexpected size %zu (expected %zu)",
760                    peer_size, sizeof(uuid_t));
761             return nullptr;
762         }
763         uuid_t peer_uuid = *static_cast<const uuid_t*>(peer);
764 
765         return sp<storage_service::SecureStorage>::make(&service,
766                                                         std::move(peer_uuid));
767     });
768     result->aidl_srv = std::move(aidl_srv);
769 
770     // Caller now owns underlying storage_service_aidl_context
771     ctx->inner = result.release();
772     return EXIT_SUCCESS;
773 }
774 
storage_aidl_delete_service(struct storage_service_aidl_context * ctx)775 void storage_aidl_delete_service(struct storage_service_aidl_context* ctx) {
776     delete ctx->inner;
777     ctx->inner = nullptr;
778 }
779 
storage_aidl_enable_filesystem(struct storage_service_aidl_context * ctx,struct fs * fs,enum storage_aidl_filesystem fs_type)780 void storage_aidl_enable_filesystem(struct storage_service_aidl_context* ctx,
781                                     struct fs* fs,
782                                     enum storage_aidl_filesystem fs_type) {
783     ctx->inner->service.ActivateFilesystem(fs, fs_type);
784 }
785 
storage_aidl_disable_filesystem(struct storage_service_aidl_context * ctx,enum storage_aidl_filesystem fs_type)786 void storage_aidl_disable_filesystem(struct storage_service_aidl_context* ctx,
787                                      enum storage_aidl_filesystem fs_type) {
788     ctx->inner->service.DeactivateFilesystem(fs_type);
789 }
790