| /* |
| * Copyright (C) 2015 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #pragma once |
| |
| #include <stdbool.h> |
| |
| #if BUILD_STORAGE_TEST |
| #define FULL_ASSERT 1 |
| #else |
| #define FULL_ASSERT 0 |
| #endif |
| #if FULL_ASSERT |
| #define full_assert assert |
| #else |
| #define full_assert(x) \ |
| do { \ |
| } while (0) |
| #endif |
| |
| #include "block_mac.h" |
| #include "block_set.h" |
| #include "block_tree.h" |
| |
| /** |
| * struct super_block_backup - Backup of root block for file system state |
| * @flags: Super-block flags for the backup, with the bits in |
| * SUPER_BLOCK_VERSION_MASK set to 0 (i.e. the backup does not |
| * contain a version). |
| * @free: Block and mac of backup free set root node. |
| * @files: Block and mac of backup files tree root node. |
| * @checkpoint: Block and mac of the backup checkpoint metadata block, if |
| * any. |
| * |
| * Block numbers and macs in @free and @files are packed as indicated by |
| * @block_num_size and @mac_size, but unlike other on-disk data, the size of the |
| * whole field is always the full 24 bytes needed for a 8 byte block number and |
| * 16 byte mac so this structure is always a fixed size. |
| */ |
| struct super_block_backup { |
| uint32_t flags; |
| struct block_mac free; |
| struct block_mac files; |
| struct block_mac checkpoint; |
| }; |
| STATIC_ASSERT(sizeof(struct super_block_backup) == 76); |
| |
| /** |
| * struct fs - File system state |
| * @node: List node for fs_list. |
| * @dev: Main block device. |
| * @transactions: Transaction list. |
| * @allocated: List of block sets containing blocks |
| * allocated by active transactions. |
| * @free: Block set of free blocks. |
| * @files: B+ tree of all files. |
| * @checkpoint: Block and mac of the latest committed |
| * checkpoint metadata. Points to a block that |
| * holds the files root and free set at the |
| * time of the most recent checkpoint. |
| * @checkpoint_free: Block set of free blocks at the time of the |
| * last committed checkpoint. A block is only |
| * free if it is in both @free and |
| * @checkpoint_free. |
| * @super_dev: Block device used to store super blocks. |
| * @readable: %true if the file system is initialized and |
| * readable. If false, no reads are valid and |
| * @writable must be %false. |
| * @writable: %true if the file system may be modified. If |
| * %false, filesystem contents may be readable, |
| * but no superblock or block changes are |
| * permitted. |
| * @allow_tampering: %false if the filesystem must detect |
| * tampering of read and write operations. |
| * %true otherwise. If %false, when a write |
| * operation is reported as successfully |
| * completed it should not be possible for |
| * non-secure code to modify the stored data. |
| * @key: Key to use for encrypt, decrypt and mac. |
| * @super_block: Block numbers in @super_dev to store |
| * super-block in. |
| * @super_block_version: Last read or written super block version. |
| * @written_super_block_version: Last written super block version. |
| * @main_repaired: %true if main file system has been repaired |
| * since being wiped. In alternate state only |
| * used to persist this flag in the super |
| * block. |
| * @alternate_data: If true, the current superblock is for a |
| * filesystem with a backing store in an |
| * alternate data location and @backup contains |
| * the superblock of the normal filesystem. If |
| * false, @backup may contain a backup of the |
| * superblock for an alternate filesystem, but |
| * it may be outdated. |
| * @needs_full_scan: %true if an error was detected in this file |
| * system data and the file system should be |
| * scanned on the next mount. Persisted to the |
| * super block so that we can initiate a scan |
| * the next time we mount the file system. |
| * @checkpoint_required: %true if a checkpoint must be created before |
| * committing any changes to the file system. |
| * @backup: Backup superblock of other filesystem state |
| * (alternate if @alternate_data is false, main |
| * otherwise) Should be preserved across all |
| * filesystem operations after initialization. |
| * @min_block_num: First block number that can store non |
| * super blocks. |
| * @block_num_size: Number of bytes used to store block numbers. |
| * @mac_size: Number of bytes used to store mac values. |
| * Must be 16 if @dev is not tamper_detecting. |
| * @reserved_count: Number of free blocks reserved for active |
| * transactions. |
| * @initial_super_block_tr: Internal transaction containing initial |
| * super block that must be written before any |
| * other data. If %NULL superblock is already |
| * a safe state. |
| * @name: File system name, used to identify the file |
| * system in debugging and error reporting |
| * messages. |
| */ |
| |
| struct fs { |
| struct list_node node; |
| struct block_device* dev; |
| struct list_node transactions; |
| struct list_node allocated; |
| struct block_set free; |
| struct block_tree files; |
| struct block_mac checkpoint; |
| struct block_set checkpoint_free; |
| struct block_device* super_dev; |
| bool readable; |
| bool writable; |
| bool allow_tampering; |
| const struct key* key; |
| data_block_t super_block[2]; |
| unsigned int super_block_version; |
| unsigned int written_super_block_version; |
| bool main_repaired; |
| bool alternate_data; |
| bool needs_full_scan; |
| bool checkpoint_required; |
| struct super_block_backup backup; |
| data_block_t min_block_num; |
| size_t block_num_size; |
| size_t mac_size; |
| data_block_t reserved_count; |
| struct transaction* initial_super_block_tr; |
| const char* name; |
| }; |
| |
| bool update_super_block(struct transaction* tr, |
| const struct block_mac* free, |
| const struct block_mac* files, |
| const struct block_mac* checkpoint); |
| |
| void fs_mark_scan_required(struct fs* fs); |
| |
| /** |
| * typedef fs_init_flags32_t - Flags that control filesystem clearing and |
| * backups. These flags may be ORed together. |
| * |
| * %FS_INIT_FLAGS_NONE |
| * No flags set |
| * |
| * %FS_INIT_FLAGS_DO_CLEAR |
| * Unconditionally clear the filesystem, regardless of corruption state. |
| * %FS_INIT_FLAGS_RECOVERY_* flags are ignored when combined with this flag. |
| * |
| * %FS_INIT_FLAGS_RECOVERY_CLEAR_ALLOWED |
| * Allows clearing of corrupt filesystem. |
| * |
| * %FS_INIT_FLAGS_ALTERNATE_DATA |
| * Indicates that the filesystem is temporarily running on top of an alternate |
| * location for the @dev block device and rollback should be enforced |
| * separately from the normal mode. |
| * |
| * %FS_INIT_FLAGS_ALLOW_TAMPERING |
| * Allow this filesystem to be initialized with the super block not stored on |
| * a tamper-detecting block device. This filesystem WILL NOT detect any |
| * tampering and a malicious actor may arbitrarily roll it back to any |
| * previous state. |
| * |
| * %FS_INIT_FLAGS_RESTORE_CHECKPOINT |
| * Restore this filesystem to the current checkpointed state, discarding any |
| * changes since that checkpoint was made. |
| * |
| * %FS_INIT_FLAGS_AUTO_CHECKPOINT |
| * Automatically create a checkpoint of the filesystem state on mount. |
| */ |
| typedef uint32_t fs_init_flags32_t; |
| #define FS_INIT_FLAGS_NONE 0U |
| #define FS_INIT_FLAGS_DO_CLEAR (1U << 0) |
| #define FS_INIT_FLAGS_RECOVERY_CLEAR_ALLOWED (1U << 1) |
| #define FS_INIT_FLAGS_ALTERNATE_DATA (1U << 2) |
| #define FS_INIT_FLAGS_ALLOW_TAMPERING (1U << 3) |
| #define FS_INIT_FLAGS_RESTORE_CHECKPOINT (1U << 4) |
| #define FS_INIT_FLAGS_AUTO_CHECKPOINT (1U << 5) |
| #define FS_INIT_FLAGS_MASK \ |
| (FS_INIT_FLAGS_DO_CLEAR | FS_INIT_FLAGS_RECOVERY_CLEAR_ALLOWED | \ |
| FS_INIT_FLAGS_ALTERNATE_DATA | FS_INIT_FLAGS_ALLOW_TAMPERING | \ |
| FS_INIT_FLAGS_RESTORE_CHECKPOINT | FS_INIT_FLAGS_AUTO_CHECKPOINT) |
| |
| int fs_init(struct fs* fs, |
| const char* name, |
| const struct key* key, |
| struct block_device* dev, |
| struct block_device* super_dev, |
| fs_init_flags32_t flags); |
| |
| static inline bool fs_is_repaired(struct fs* fs) { |
| return fs->main_repaired && !fs->alternate_data; |
| } |
| |
| static inline bool fs_is_readable(struct fs* fs) { |
| return fs->readable; |
| } |
| |
| static inline bool fs_is_writable(struct fs* fs) { |
| return fs->writable; |
| } |
| |
| /** |
| * enum fs_check_result - Result of a filesystem check |
| * @FS_CHECK_NO_ERROR: No error was enountered in the checked blocks. |
| * @FS_CHECK_INVALID_BLOCK: A MAC mismatch error or invalid block was |
| * encountered while trying to load a block in the |
| * file-system. This type of error may indicate that |
| * the non-secure data is out of sync with the RPMB |
| * superblock. The file-system is likely corrupt. |
| * @FS_CHECK_INVALID_FREE_SET: The free set was not internally valid or invalid |
| * blocks were encountered in the free set tree. |
| * @FS_CHECK_INVALID_FILE_TREE: The file tree was not internally valid but no |
| * invalid blocks were encountered. |
| * @FS_CHECK_UNKNOWN: An unknown error was encountered while checking the |
| * file-system. The file-system may not be entirely |
| * readable or valid. |
| */ |
| enum fs_check_result { |
| FS_CHECK_NO_ERROR = 0, |
| FS_CHECK_INVALID_BLOCK, |
| FS_CHECK_INVALID_FREE_SET, |
| FS_CHECK_INVALID_FILE_TREE, |
| FS_CHECK_UNKNOWN, |
| }; |
| |
| /** |
| * fs_check_full - Check the file system tree |
| * @fs: File system state object. |
| * |
| * Walk the filesystem tree and visit each file, checking the file tree and each |
| * file block map for consistency. |
| * |
| * Returns @fs_check_result.FS_CHECK_NO_ERROR if no corruption was encountered |
| * or any encountered corruption was repaired. Returns another @fs_check_result |
| * variant describing the error if the filesystem remains corrupted after this |
| * operation. Errors are prioritized in the following order (highest to lowest): |
| * %FS_CHECK_INVALID_BLOCK (except in the free set, which is reported |
| * separately), %FS_CHECK_INVALID_FILE_TREE, %FS_CHECK_INVALID_FREE_SET, |
| * %FS_CHECK_UNKNOWN. This ordering is intended to allow callers to |
| * differentiate between invalid blocks that indicate corruption and possibly |
| * transient communication errors with the storage proxy. |
| */ |
| enum fs_check_result fs_check_full(struct fs* fs); |
| |
| /** |
| * fs_check_quick - Quickly check the file-system tree |
| * @fs: File system state object. |
| * |
| * Perform a basic check that the file-system roots are valid. Suitable for use |
| * while mounting file-systems where we don't want to pay the cost to walk the |
| * entire file-system tree. |
| * |
| * Returns @fs_check_result.FS_CHECK_NO_ERROR if no corruption was encountered, |
| * or another @fs_check_result variant describing the error. |
| */ |
| enum fs_check_result fs_check_quick(struct fs* fs); |
| |
| /** |
| * fs_check - Check the file system tree |
| * @fs: File system state object. |
| * |
| * If the filesystem was not previously marked as requiring a full scan, perform |
| * a quick check (i.e. behave the same as fs_check_quick()). If the file system |
| * has been marked as potentially having an error, do a full scan using |
| * fs_check_full(). |
| * |
| * Returns an @fs_check_result variant, see fs_check_quick() and fs_check_full() |
| * for details. |
| */ |
| enum fs_check_result fs_check(struct fs* fs); |
| |
| void fs_file_tree_init(const struct fs* fs, struct block_tree* tree); |
| |
| void fs_unknown_super_block_state_all(void); |
| void write_current_super_block(struct fs* fs, bool reinitialize); |
| |
| void fs_destroy(struct fs* fs); |
| |
| /** |
| * fs_fail_all_transactions - Fail all pending transactions in all filesystems |
| * |
| * This functions fails any pending transactions that have not already failed. |
| */ |
| void fs_fail_all_transactions(void); |