From 8d3bcd4b6a3bdf2fd1302bd6e89413ff57168e0d Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 5 Jul 2017 12:21:15 -0700 Subject: [PATCH 1/2] fs_mgr: refactor pre-mount logic into prepare_fs_for_mount() There were several duplications in the code that runs before a filesystem is mounted. This made it difficult to start running tune2fs to set the encryption feature flag. Refactor to deduplicate the logic, and improve the log messages. Bug: 36231741 Change-Id: I90846dad9c5ec85b3c5460615dec4cc19cb7e198 --- fs_mgr/fs_mgr.cpp | 374 ++++++++++++++--------------- fs_mgr/fs_mgr_fstab.cpp | 18 +- fs_mgr/include_fstab/fstab/fstab.h | 12 +- 3 files changed, 187 insertions(+), 217 deletions(-) diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index 8c19a812c..cfe796735 100644 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp @@ -78,13 +78,14 @@ enum FsStatFlags { FS_STAT_E2FSCK_F_ALWAYS = 0x0004, FS_STAT_UNCLEAN_SHUTDOWN = 0x0008, FS_STAT_QUOTA_ENABLED = 0x0010, - FS_STAT_TUNE2FS_FAILED = 0x0020, FS_STAT_RO_MOUNT_FAILED = 0x0040, FS_STAT_RO_UNMOUNT_FAILED = 0x0080, FS_STAT_FULL_MOUNT_FAILED = 0x0100, FS_STAT_E2FSCK_FAILED = 0x0200, FS_STAT_E2FSCK_FS_FIXED = 0x0400, FS_STAT_EXT4_INVALID_MAGIC = 0x0800, + FS_STAT_TOGGLE_QUOTAS_FAILED = 0x10000, + FS_STAT_SET_RESERVED_BLOCKS_FAILED = 0x20000, }; /* @@ -128,10 +129,15 @@ static void log_fs_stat(const char* blk_device, int fs_stat) } } +static bool is_extfs(const std::string& fs_type) { + return fs_type == "ext4" || fs_type == "ext3" || fs_type == "ext2"; +} + static bool should_force_check(int fs_stat) { return fs_stat & (FS_STAT_E2FSCK_F_ALWAYS | FS_STAT_UNCLEAN_SHUTDOWN | FS_STAT_QUOTA_ENABLED | - FS_STAT_TUNE2FS_FAILED | FS_STAT_RO_MOUNT_FAILED | FS_STAT_RO_UNMOUNT_FAILED | - FS_STAT_FULL_MOUNT_FAILED | FS_STAT_E2FSCK_FAILED); + FS_STAT_RO_MOUNT_FAILED | FS_STAT_RO_UNMOUNT_FAILED | + FS_STAT_FULL_MOUNT_FAILED | FS_STAT_E2FSCK_FAILED | + FS_STAT_TOGGLE_QUOTAS_FAILED | FS_STAT_SET_RESERVED_BLOCKS_FAILED); } static void check_fs(const char *blk_device, char *fs_type, char *target, int *fs_stat) @@ -144,7 +150,7 @@ static void check_fs(const char *blk_device, char *fs_type, char *target, int *f const char* e2fsck_forced_argv[] = {E2FSCK_BIN, "-f", "-y", blk_device}; /* Check for the types of filesystems we know how to check */ - if (!strcmp(fs_type, "ext2") || !strcmp(fs_type, "ext3") || !strcmp(fs_type, "ext4")) { + if (is_extfs(fs_type)) { if (*fs_stat & FS_STAT_EXT4_INVALID_MAGIC) { // will fail, so do not try return; } @@ -242,186 +248,181 @@ static void check_fs(const char *blk_device, char *fs_type, char *target, int *f return; } -/* Function to read the primary superblock */ -static int read_super_block(int fd, struct ext4_super_block *sb) -{ - off64_t ret; - - ret = lseek64(fd, 1024, SEEK_SET); - if (ret < 0) - return ret; - - ret = read(fd, sb, sizeof(*sb)); - if (ret < 0) - return ret; - if (ret != sizeof(*sb)) - return ret; - - return 0; -} - -static ext4_fsblk_t ext4_blocks_count(struct ext4_super_block *es) -{ +static ext4_fsblk_t ext4_blocks_count(const struct ext4_super_block* es) { return ((ext4_fsblk_t)le32_to_cpu(es->s_blocks_count_hi) << 32) | - le32_to_cpu(es->s_blocks_count_lo); + le32_to_cpu(es->s_blocks_count_lo); } -static ext4_fsblk_t ext4_r_blocks_count(struct ext4_super_block *es) -{ +static ext4_fsblk_t ext4_r_blocks_count(const struct ext4_super_block* es) { return ((ext4_fsblk_t)le32_to_cpu(es->s_r_blocks_count_hi) << 32) | - le32_to_cpu(es->s_r_blocks_count_lo); + le32_to_cpu(es->s_r_blocks_count_lo); } -static int do_quota_with_shutdown_check(char *blk_device, char *fs_type, - struct fstab_rec *rec, int *fs_stat) -{ - int force_check = 0; - if (!strcmp(fs_type, "ext4")) { - /* - * Some system images do not have tune2fs for licensing reasons - * Detect these and skip reserve blocks. - */ - if (access(TUNE2FS_BIN, X_OK)) { - LERROR << "Not running " << TUNE2FS_BIN << " on " - << blk_device << " (executable not in system image)"; - } else { - const char* arg1 = nullptr; - const char* arg2 = nullptr; - int status = 0; - int ret = 0; - android::base::unique_fd fd( - TEMP_FAILURE_RETRY(open(blk_device, O_RDONLY | O_CLOEXEC))); - if (fd >= 0) { - struct ext4_super_block sb; - ret = read_super_block(fd, &sb); - if (ret < 0) { - PERROR << "Can't read '" << blk_device << "' super block"; - return force_check; - } - if (sb.s_magic != EXT4_SUPER_MAGIC) { - LINFO << "Invalid ext4 magic:0x" << std::hex << sb.s_magic << "," << blk_device; - *fs_stat |= FS_STAT_EXT4_INVALID_MAGIC; - return 0; // not a valid fs, tune2fs, fsck, and mount will all fail. - } - *fs_stat |= FS_STAT_IS_EXT4; - LINFO << "superblock s_max_mnt_count:" << sb.s_max_mnt_count << "," << blk_device; - if (sb.s_max_mnt_count == 0xffff) { // -1 (int16) in ext2, but uint16 in ext4 - *fs_stat |= FS_STAT_NEW_IMAGE_VERSION; - } - if ((sb.s_feature_incompat & EXT4_FEATURE_INCOMPAT_RECOVER) != 0 || - (sb.s_state & EXT4_VALID_FS) == 0) { - LINFO << __FUNCTION__ << "(): was not clealy shutdown, state flag:" - << std::hex << sb.s_state - << "incompat flag:" << std::hex << sb.s_feature_incompat; - force_check = 1; - *fs_stat |= FS_STAT_UNCLEAN_SHUTDOWN; - } - int has_quota = (sb.s_feature_ro_compat - & cpu_to_le32(EXT4_FEATURE_RO_COMPAT_QUOTA)) != 0; - int want_quota = fs_mgr_is_quota(rec) != 0; +// Read the primary superblock from an ext4 filesystem. On failure return +// false. If it's not an ext4 filesystem, also set FS_STAT_EXT4_INVALID_MAGIC. +static bool read_ext4_superblock(const char* blk_device, struct ext4_super_block* sb, int* fs_stat) { + android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(blk_device, O_RDONLY | O_CLOEXEC))); - if (has_quota == want_quota) { - LINFO << "Requested quota status is match on " << blk_device; - return force_check; - } else if (want_quota) { - LINFO << "Enabling quota on " << blk_device; - arg1 = "-Oquota"; - arg2 = "-Qusrquota,grpquota"; - force_check = 1; - *fs_stat |= FS_STAT_QUOTA_ENABLED; - } else { - LINFO << "Disabling quota on " << blk_device; - arg1 = "-Q^usrquota,^grpquota"; - arg2 = "-O^quota"; - } - } else { - PERROR << "Failed to open '" << blk_device << "'"; - return force_check; - } - - const char *tune2fs_argv[] = { - TUNE2FS_BIN, - arg1, - arg2, - blk_device, - }; - ret = android_fork_execvp_ext(ARRAY_SIZE(tune2fs_argv), - const_cast(tune2fs_argv), - &status, true, LOG_KLOG | LOG_FILE, - true, NULL, NULL, 0); - if (ret < 0) { - /* No need to check for error in fork, we can't really handle it now */ - LERROR << "Failed trying to run " << TUNE2FS_BIN; - *fs_stat |= FS_STAT_TUNE2FS_FAILED; - } - } + if (fd < 0) { + PERROR << "Failed to open '" << blk_device << "'"; + return false; } - return force_check; + + if (pread(fd, sb, sizeof(*sb), 1024) != sizeof(*sb)) { + PERROR << "Can't read '" << blk_device << "' superblock"; + return false; + } + + if (sb->s_magic != EXT4_SUPER_MAGIC) { + LINFO << "Invalid ext4 magic:0x" << std::hex << sb->s_magic << " " + << "on '" << blk_device << "'"; + // not a valid fs, tune2fs, fsck, and mount will all fail. + *fs_stat |= FS_STAT_EXT4_INVALID_MAGIC; + return false; + } + *fs_stat |= FS_STAT_IS_EXT4; + LINFO << "superblock s_max_mnt_count:" << sb->s_max_mnt_count << "," << blk_device; + if (sb->s_max_mnt_count == 0xffff) { // -1 (int16) in ext2, but uint16 in ext4 + *fs_stat |= FS_STAT_NEW_IMAGE_VERSION; + } + return true; } -static void do_reserved_size(char *blk_device, char *fs_type, struct fstab_rec *rec, int *fs_stat) -{ - /* Check for the types of filesystems we know how to check */ - if (!strcmp(fs_type, "ext2") || !strcmp(fs_type, "ext3") || !strcmp(fs_type, "ext4")) { - /* - * Some system images do not have tune2fs for licensing reasons - * Detect these and skip reserve blocks. - */ - if (access(TUNE2FS_BIN, X_OK)) { - LERROR << "Not running " << TUNE2FS_BIN << " on " - << blk_device << " (executable not in system image)"; +// Some system images do not have tune2fs for licensing reasons. +// Detect these and skip running it. +static bool tune2fs_available(void) { + return access(TUNE2FS_BIN, X_OK) == 0; +} + +static bool run_tune2fs(const char* argv[], int argc) { + int ret; + + ret = android_fork_execvp_ext(argc, const_cast(argv), nullptr, true, + LOG_KLOG | LOG_FILE, true, nullptr, nullptr, 0); + return ret == 0; +} + +// Enable/disable quota support on the filesystem if needed. +static void tune_quota(const char* blk_device, const struct fstab_rec* rec, + const struct ext4_super_block* sb, int* fs_stat) { + bool has_quota = (sb->s_feature_ro_compat & cpu_to_le32(EXT4_FEATURE_RO_COMPAT_QUOTA)) != 0; + bool want_quota = fs_mgr_is_quota(rec) != 0; + + if (has_quota == want_quota) { + return; + } + + if (!tune2fs_available()) { + LERROR << "Unable to " << (want_quota ? "enable" : "disable") << " quotas on " << blk_device + << " because " TUNE2FS_BIN " is missing"; + return; + } + + const char* argv[] = {TUNE2FS_BIN, nullptr, nullptr, blk_device}; + + if (want_quota) { + LINFO << "Enabling quotas on " << blk_device; + argv[1] = "-Oquota"; + argv[2] = "-Qusrquota,grpquota"; + *fs_stat |= FS_STAT_QUOTA_ENABLED; + } else { + LINFO << "Disabling quotas on " << blk_device; + argv[1] = "-O^quota"; + argv[2] = "-Q^usrquota,^grpquota"; + } + + if (!run_tune2fs(argv, ARRAY_SIZE(argv))) { + LERROR << "Failed to run " TUNE2FS_BIN " to " << (want_quota ? "enable" : "disable") + << " quotas on " << blk_device; + *fs_stat |= FS_STAT_TOGGLE_QUOTAS_FAILED; + } +} + +// Set the number of reserved filesystem blocks if needed. +static void tune_reserved_size(const char* blk_device, const struct fstab_rec* rec, + const struct ext4_super_block* sb, int* fs_stat) { + if (!(rec->fs_mgr_flags & MF_RESERVEDSIZE)) { + return; + } + + // The size to reserve is given in the fstab, but we won't reserve more + // than 2% of the filesystem. + const uint64_t max_reserved_blocks = ext4_blocks_count(sb) * 0.02; + uint64_t reserved_blocks = rec->reserved_size / EXT4_BLOCK_SIZE(sb); + + if (reserved_blocks > max_reserved_blocks) { + LWARNING << "Reserved blocks " << reserved_blocks << " is too large; " + << "capping to " << max_reserved_blocks; + reserved_blocks = max_reserved_blocks; + } + + if (ext4_r_blocks_count(sb) == reserved_blocks) { + return; + } + + if (!tune2fs_available()) { + LERROR << "Unable to set the number of reserved blocks on " << blk_device + << " because " TUNE2FS_BIN " is missing"; + return; + } + + char buf[32]; + const char* argv[] = {TUNE2FS_BIN, "-r", buf, blk_device}; + + snprintf(buf, sizeof(buf), "%" PRIu64, reserved_blocks); + LINFO << "Setting reserved block count on " << blk_device << " to " << reserved_blocks; + if (!run_tune2fs(argv, ARRAY_SIZE(argv))) { + LERROR << "Failed to run " TUNE2FS_BIN " to set the number of reserved blocks on " + << blk_device; + *fs_stat |= FS_STAT_SET_RESERVED_BLOCKS_FAILED; + } +} + +// +// Prepare the filesystem on the given block device to be mounted. +// +// If the "check" option was given in the fstab record, or it seems that the +// filesystem was uncleanly shut down, we'll run fsck on the filesystem. +// +// If needed, we'll also enable (or disable) filesystem features as specified by +// the fstab record. +// +static int prepare_fs_for_mount(const char* blk_device, const struct fstab_rec* rec) { + int fs_stat = 0; + + if (is_extfs(rec->fs_type)) { + struct ext4_super_block sb; + + if (read_ext4_superblock(blk_device, &sb, &fs_stat)) { + if ((sb.s_feature_incompat & EXT4_FEATURE_INCOMPAT_RECOVER) != 0 || + (sb.s_state & EXT4_VALID_FS) == 0) { + LINFO << "Filesystem on " << blk_device << " was not cleanly shutdown; " + << "state flags: 0x" << std::hex << sb.s_state << ", " + << "incompat feature flags: 0x" << std::hex << sb.s_feature_incompat; + fs_stat |= FS_STAT_UNCLEAN_SHUTDOWN; + } + + // Note: quotas should be enabled before running fsck. + tune_quota(blk_device, rec, &sb, &fs_stat); } else { - LINFO << "Running " << TUNE2FS_BIN << " on " << blk_device; - - int status = 0; - int ret = 0; - unsigned long reserved_blocks = 0; - android::base::unique_fd fd( - TEMP_FAILURE_RETRY(open(blk_device, O_RDONLY | O_CLOEXEC))); - if (fd >= 0) { - struct ext4_super_block sb; - ret = read_super_block(fd, &sb); - if (ret < 0) { - PERROR << "Can't read '" << blk_device << "' super block"; - return; - } - reserved_blocks = rec->reserved_size / EXT4_BLOCK_SIZE(&sb); - unsigned long reserved_threshold = ext4_blocks_count(&sb) * 0.02; - if (reserved_threshold < reserved_blocks) { - LWARNING << "Reserved blocks " << reserved_blocks - << " is too large"; - reserved_blocks = reserved_threshold; - } - - if (ext4_r_blocks_count(&sb) == reserved_blocks) { - LINFO << "Have reserved same blocks"; - return; - } - } else { - PERROR << "Failed to open '" << blk_device << "'"; - return; - } - - char buf[16] = {0}; - snprintf(buf, sizeof (buf), "-r %lu", reserved_blocks); - const char *tune2fs_argv[] = { - TUNE2FS_BIN, - buf, - blk_device, - }; - - ret = android_fork_execvp_ext(ARRAY_SIZE(tune2fs_argv), - const_cast(tune2fs_argv), - &status, true, LOG_KLOG | LOG_FILE, - true, NULL, NULL, 0); - - if (ret < 0) { - /* No need to check for error in fork, we can't really handle it now */ - LERROR << "Failed trying to run " << TUNE2FS_BIN; - *fs_stat |= FS_STAT_TUNE2FS_FAILED; - } + return fs_stat; } } + + if ((rec->fs_mgr_flags & MF_CHECK) || + (fs_stat & (FS_STAT_UNCLEAN_SHUTDOWN | FS_STAT_QUOTA_ENABLED))) { + check_fs(blk_device, rec->fs_type, rec->mount_point, &fs_stat); + } + + if (is_extfs(rec->fs_type) && (rec->fs_mgr_flags & MF_RESERVEDSIZE)) { + struct ext4_super_block sb; + + if (read_ext4_superblock(blk_device, &sb, &fs_stat)) { + tune_reserved_size(blk_device, rec, &sb, &fs_stat); + } + } + + return fs_stat; } static void remove_trailing_slashes(char *n) @@ -559,10 +560,7 @@ static int mount_with_alternatives(struct fstab *fstab, int start_idx, int *end_ continue; } - int fs_stat = 0; - int force_check = do_quota_with_shutdown_check(fstab->recs[i].blk_device, - fstab->recs[i].fs_type, - &fstab->recs[i], &fs_stat); + int fs_stat = prepare_fs_for_mount(fstab->recs[i].blk_device, &fstab->recs[i]); if (fs_stat & FS_STAT_EXT4_INVALID_MAGIC) { LERROR << __FUNCTION__ << "(): skipping mount, invalid ext4, mountpoint=" << fstab->recs[i].mount_point << " rec[" << i @@ -570,15 +568,6 @@ static int mount_with_alternatives(struct fstab *fstab, int start_idx, int *end_ mount_errno = EINVAL; // continue bootup for FDE continue; } - if ((fstab->recs[i].fs_mgr_flags & MF_CHECK) || force_check) { - check_fs(fstab->recs[i].blk_device, fstab->recs[i].fs_type, - fstab->recs[i].mount_point, &fs_stat); - } - - if (fstab->recs[i].fs_mgr_flags & MF_RESERVEDSIZE) { - do_reserved_size(fstab->recs[i].blk_device, fstab->recs[i].fs_type, - &fstab->recs[i], &fs_stat); - } int retry_count = 2; while (retry_count-- > 0) { @@ -817,9 +806,7 @@ int fs_mgr_mount_all(struct fstab *fstab, int mount_mode) } /* Translate LABEL= file system labels into block devices */ - if (!strcmp(fstab->recs[i].fs_type, "ext2") || - !strcmp(fstab->recs[i].fs_type, "ext3") || - !strcmp(fstab->recs[i].fs_type, "ext4")) { + if (is_extfs(fstab->recs[i].fs_type)) { int tret = translate_ext_labels(&fstab->recs[i]); if (tret < 0) { LERROR << "Could not translate label to block device"; @@ -1035,18 +1022,7 @@ int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device, wait_for_file(n_blk_device, WAIT_TIMEOUT); } - int fs_stat = 0; - int force_check = do_quota_with_shutdown_check(n_blk_device, fstab->recs[i].fs_type, - &fstab->recs[i], &fs_stat); - - if ((fstab->recs[i].fs_mgr_flags & MF_CHECK) || force_check) { - check_fs(n_blk_device, fstab->recs[i].fs_type, - fstab->recs[i].mount_point, &fs_stat); - } - - if (fstab->recs[i].fs_mgr_flags & MF_RESERVEDSIZE) { - do_reserved_size(n_blk_device, fstab->recs[i].fs_type, &fstab->recs[i], &fs_stat); - } + int fs_stat = prepare_fs_for_mount(n_blk_device, &fstab->recs[i]); if (fstab->recs[i].fs_mgr_flags & MF_AVB) { if (!avb_handle) { diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp index 7a41b147d..b68875b97 100644 --- a/fs_mgr/fs_mgr_fstab.cpp +++ b/fs_mgr/fs_mgr_fstab.cpp @@ -810,32 +810,26 @@ int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab) return fstab->fs_mgr_flags & MF_NOEMULATEDSD; } -int fs_mgr_is_notrim(struct fstab_rec *fstab) -{ +int fs_mgr_is_notrim(const struct fstab_rec* fstab) { return fstab->fs_mgr_flags & MF_NOTRIM; } -int fs_mgr_is_formattable(struct fstab_rec *fstab) -{ +int fs_mgr_is_formattable(const struct fstab_rec* fstab) { return fstab->fs_mgr_flags & (MF_FORMATTABLE); } -int fs_mgr_is_slotselect(struct fstab_rec *fstab) -{ +int fs_mgr_is_slotselect(const struct fstab_rec* fstab) { return fstab->fs_mgr_flags & MF_SLOTSELECT; } -int fs_mgr_is_nofail(struct fstab_rec *fstab) -{ +int fs_mgr_is_nofail(const struct fstab_rec* fstab) { return fstab->fs_mgr_flags & MF_NOFAIL; } -int fs_mgr_is_latemount(struct fstab_rec *fstab) -{ +int fs_mgr_is_latemount(const struct fstab_rec* fstab) { return fstab->fs_mgr_flags & MF_LATEMOUNT; } -int fs_mgr_is_quota(struct fstab_rec *fstab) -{ +int fs_mgr_is_quota(const struct fstab_rec* fstab) { return fstab->fs_mgr_flags & MF_QUOTA; } diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h index 3ea4e038e..17e1fb176 100644 --- a/fs_mgr/include_fstab/fstab/fstab.h +++ b/fs_mgr/include_fstab/fstab/fstab.h @@ -80,12 +80,12 @@ int fs_mgr_is_file_encrypted(const struct fstab_rec* fstab); const char* fs_mgr_get_file_encryption_mode(const struct fstab_rec* fstab); int fs_mgr_is_convertible_to_fbe(const struct fstab_rec* fstab); int fs_mgr_is_noemulatedsd(const struct fstab_rec* fstab); -int fs_mgr_is_notrim(struct fstab_rec* fstab); -int fs_mgr_is_formattable(struct fstab_rec* fstab); -int fs_mgr_is_slotselect(struct fstab_rec* fstab); -int fs_mgr_is_nofail(struct fstab_rec* fstab); -int fs_mgr_is_latemount(struct fstab_rec* fstab); -int fs_mgr_is_quota(struct fstab_rec* fstab); +int fs_mgr_is_notrim(const struct fstab_rec* fstab); +int fs_mgr_is_formattable(const struct fstab_rec* fstab); +int fs_mgr_is_slotselect(const struct fstab_rec* fstab); +int fs_mgr_is_nofail(const struct fstab_rec* fstab); +int fs_mgr_is_latemount(const struct fstab_rec* fstab); +int fs_mgr_is_quota(const struct fstab_rec* fstab); __END_DECLS From e9811f36e508785504db2a87d93dbbd89bf2b9a9 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 5 Jul 2017 12:21:15 -0700 Subject: [PATCH 2/2] fs_mgr: set ext4 encryption flag with tune2fs when needed Upstream kernels (v4.9+, v4.4.67+) have started to enforce that encryption policies cannot be set on ext4 directories unless EXT4_FEATURE_INCOMPAT_ENCRYPT is set in the filesystem superblock, as was the original design. Since Android's userspace was not setting this flag, it was not possible to use "file-based encryption" (FBE) on devices whose kernels enforce this constraint. Fix this by updating fs_mgr to set the flag if needed, similar to how it enables the quota feature if needed. Note that it would, eventually, be simpler to set this flag at mkfs time. But that seems infeasible for now, given the many different ways the userdata filesystem can be formatted --- including via 'fastboot', which I believe is expected to still be compatible with old devices whose kernel and/or e2fsprogs don't support the 'encrypt' flag. Bug: 36231741 Change-Id: Ibafb9a7116fc853b62f8ee074a78499399f290a6 --- fs_mgr/fs_mgr.cpp | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index cfe796735..dbd4ec8b7 100644 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp @@ -86,6 +86,7 @@ enum FsStatFlags { FS_STAT_EXT4_INVALID_MAGIC = 0x0800, FS_STAT_TOGGLE_QUOTAS_FAILED = 0x10000, FS_STAT_SET_RESERVED_BLOCKS_FAILED = 0x20000, + FS_STAT_ENABLE_ENCRYPTION_FAILED = 0x40000, }; /* @@ -134,10 +135,11 @@ static bool is_extfs(const std::string& fs_type) { } static bool should_force_check(int fs_stat) { - return fs_stat & (FS_STAT_E2FSCK_F_ALWAYS | FS_STAT_UNCLEAN_SHUTDOWN | FS_STAT_QUOTA_ENABLED | - FS_STAT_RO_MOUNT_FAILED | FS_STAT_RO_UNMOUNT_FAILED | - FS_STAT_FULL_MOUNT_FAILED | FS_STAT_E2FSCK_FAILED | - FS_STAT_TOGGLE_QUOTAS_FAILED | FS_STAT_SET_RESERVED_BLOCKS_FAILED); + return fs_stat & + (FS_STAT_E2FSCK_F_ALWAYS | FS_STAT_UNCLEAN_SHUTDOWN | FS_STAT_QUOTA_ENABLED | + FS_STAT_RO_MOUNT_FAILED | FS_STAT_RO_UNMOUNT_FAILED | FS_STAT_FULL_MOUNT_FAILED | + FS_STAT_E2FSCK_FAILED | FS_STAT_TOGGLE_QUOTAS_FAILED | + FS_STAT_SET_RESERVED_BLOCKS_FAILED | FS_STAT_ENABLE_ENCRYPTION_FAILED); } static void check_fs(const char *blk_device, char *fs_type, char *target, int *fs_stat) @@ -378,6 +380,32 @@ static void tune_reserved_size(const char* blk_device, const struct fstab_rec* r } } +// Enable file-based encryption if needed. +static void tune_encrypt(const char* blk_device, const struct fstab_rec* rec, + const struct ext4_super_block* sb, int* fs_stat) { + bool has_encrypt = (sb->s_feature_incompat & cpu_to_le32(EXT4_FEATURE_INCOMPAT_ENCRYPT)) != 0; + bool want_encrypt = fs_mgr_is_file_encrypted(rec) != 0; + + if (has_encrypt || !want_encrypt) { + return; + } + + if (!tune2fs_available()) { + LERROR << "Unable to enable ext4 encryption on " << blk_device + << " because " TUNE2FS_BIN " is missing"; + return; + } + + const char* argv[] = {TUNE2FS_BIN, "-Oencrypt", blk_device}; + + LINFO << "Enabling ext4 encryption on " << blk_device; + if (!run_tune2fs(argv, ARRAY_SIZE(argv))) { + LERROR << "Failed to run " TUNE2FS_BIN " to enable " + << "ext4 encryption on " << blk_device; + *fs_stat |= FS_STAT_ENABLE_ENCRYPTION_FAILED; + } +} + // // Prepare the filesystem on the given block device to be mounted. // @@ -414,11 +442,12 @@ static int prepare_fs_for_mount(const char* blk_device, const struct fstab_rec* check_fs(blk_device, rec->fs_type, rec->mount_point, &fs_stat); } - if (is_extfs(rec->fs_type) && (rec->fs_mgr_flags & MF_RESERVEDSIZE)) { + if (is_extfs(rec->fs_type) && (rec->fs_mgr_flags & (MF_RESERVEDSIZE | MF_FILEENCRYPTION))) { struct ext4_super_block sb; if (read_ext4_superblock(blk_device, &sb, &fs_stat)) { tune_reserved_size(blk_device, rec, &sb, &fs_stat); + tune_encrypt(blk_device, rec, &sb, &fs_stat); } }