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