From: Theodore Ts'o Date: Sun, 8 Mar 2015 23:09:52 +0000 (-0400) Subject: e2fsck: handle encrypted directories which are indexed using htree X-Git-Tag: v1.43-WIP-2015-05-18~61 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=62ad24802c6e9abd0acf3e6d12aeaab3ae8c6f5a;p=thirdparty%2Fe2fsprogs.git e2fsck: handle encrypted directories which are indexed using htree Signed-off-by: Theodore Ts'o --- diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h index b895f1ee6..e0a9239fa 100644 --- a/e2fsck/e2fsck.h +++ b/e2fsck/e2fsck.h @@ -482,6 +482,10 @@ extern void e2fsck_intercept_block_allocations(e2fsck_t ctx); /* pass2.c */ extern int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir, ext2_ino_t ino, char *buf); +extern int get_filename_hash(ext2_filsys fs, int encrypted, int version, + const char *name, int len, + ext2_dirhash_t *ret_hash, + ext2_dirhash_t *ret_minor_hash); /* pass3.c */ extern int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t inode); diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c index 78a4c7117..319d23b84 100644 --- a/e2fsck/pass1.c +++ b/e2fsck/pass1.c @@ -178,6 +178,7 @@ int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino, ext2_extent_handle_t handle; struct ext2_extent_info info; struct ext2fs_extent extent; + int encrypted = 0; if ((inode->i_size_high || inode->i_size == 0) || (inode->i_flags & EXT2_INDEX_FL)) @@ -235,7 +236,11 @@ int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino, if (io_channel_read_blk64(fs->io, inode->i_block[0], 1, buf)) return 0; - len = strnlen(buf, fs->blocksize); + if (inode->i_flags & EXT4_ENCRYPT_FL) { + len = ext2fs_le32_to_cpu(*((__u32 *)buf)) + 4; + } else { + len = strnlen(buf, fs->blocksize); + } if (len == fs->blocksize) return 0; } else if (inode->i_flags & EXT4_INLINE_DATA_FL) { @@ -268,7 +273,8 @@ exit_inline: return 0; } if (len != inode->i_size) - return 0; + if ((inode->i_flags & EXT4_ENCRYPT_FL) == 0) + return 0; return 1; } diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c index a6624f4d9..94665c6ed 100644 --- a/e2fsck/pass2.c +++ b/e2fsck/pass2.c @@ -464,23 +464,15 @@ static int check_dotdot(e2fsck_t ctx, static int check_name(e2fsck_t ctx, struct ext2_dir_entry *dirent, ext2_ino_t dir_ino, - int *encrypted, struct problem_context *pctx) { int i; int fixup = -1; int ret = 0; - if (*encrypted > 0) - return 0; for ( i = 0; i < ext2fs_dirent_name_len(dirent); i++) { if (dirent->name[i] != '/' && dirent->name[i] != '\0') continue; - if (*encrypted < 0 && ctx->encrypted_dirs) - *encrypted = ext2fs_u32_list_test(ctx->encrypted_dirs, - dir_ino); - if (*encrypted > 0) - return 0; if (fixup < 0) fixup = fix_problem(ctx, PR_2_BAD_NAME, pctx); if (fixup == 0) @@ -850,6 +842,32 @@ err: return retval; } +int get_filename_hash(ext2_filsys fs, int encrypted, int version, + const char *name, int len, ext2_dirhash_t *ret_hash, + ext2_dirhash_t *ret_minor_hash) +{ + char buf[2*EXT2FS_DIGEST_SIZE]; + int buf_len; + + if (!encrypted) + return ext2fs_dirhash(version, name, len, + fs->super->s_hash_seed, + ret_hash, ret_minor_hash); + + if (len <= EXT2FS_DIGEST_SIZE) + buf_len = ext2fs_digest_encode(name, len, buf); + else { + ext2fs_sha256(name, len, buf + EXT2FS_DIGEST_SIZE); + buf[0] = 'I'; + buf_len = ext2fs_digest_encode(buf + EXT2FS_DIGEST_SIZE, + EXT2FS_DIGEST_SIZE, buf + 1); + buf_len++; + } + return ext2fs_dirhash(version, buf, buf_len, + fs->super->s_hash_seed, + ret_hash, ret_minor_hash); +} + static int check_dir_block(ext2_filsys fs, struct ext2_db_entry2 *db, void *priv_data) @@ -883,7 +901,7 @@ static int check_dir_block(ext2_filsys fs, int is_leaf = 1; size_t inline_data_size = 0; int filetype = 0; - int encrypted = -1; + int encrypted = 0; size_t max_block_size; cd = (struct check_dir_struct *) priv_data; @@ -1095,6 +1113,9 @@ skip_checksum: } else max_block_size = fs->blocksize - de_csum_size; + if (ctx->encrypted_dirs) + encrypted = ext2fs_u32_list_test(ctx->encrypted_dirs, ino); + dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp); prev = 0; do { @@ -1357,7 +1378,7 @@ skip_checksum: } } - if (check_name(ctx, dirent, ino, &encrypted, &cd->pctx)) + if (!encrypted && check_name(ctx, dirent, ino, &cd->pctx)) dir_modified++; if (check_filetype(ctx, dirent, ino, &cd->pctx)) @@ -1365,9 +1386,10 @@ skip_checksum: #ifdef ENABLE_HTREE if (dx_db) { - ext2fs_dirhash(dx_dir->hashversion, dirent->name, - ext2fs_dirent_name_len(dirent), - fs->super->s_hash_seed, &hash, 0); + get_filename_hash(fs, encrypted, dx_dir->hashversion, + dirent->name, + ext2fs_dirent_name_len(dirent), + &hash, 0); if (hash < dx_db->min_hash) dx_db->min_hash = hash; if (hash > dx_db->max_hash) diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c index e37e87143..66e6786f2 100644 --- a/e2fsck/rehash.c +++ b/e2fsck/rehash.c @@ -74,6 +74,7 @@ int e2fsck_dir_will_be_rehashed(e2fsck_t ctx, ext2_ino_t ino) struct fill_dir_struct { char *buf; struct ext2_inode *inode; + ext2_ino_t ino; errcode_t err; e2fsck_t ctx; struct hash_entry *harray; @@ -111,6 +112,9 @@ static int fill_dir_block(ext2_filsys fs, char *dir; unsigned int offset, dir_offset, rec_len, name_len; int hash_alg; + int encrypted = 0; + char processed_filename[2*EXT2FS_DIGEST_SIZE]; + int processed_filename_len; if (blockcnt < 0) return 0; @@ -120,6 +124,12 @@ static int fill_dir_block(ext2_filsys fs, fd->err = EXT2_ET_DIR_CORRUPTED; return BLOCK_ABORT; } + + /* Determine if the directory is encrypted */ + if (fd->ctx->encrypted_dirs) + encrypted = ext2fs_u32_list_test(fd->ctx->encrypted_dirs, + fd->ino); + dir = (fd->buf+offset); if (HOLE_BLKADDR(*block_nr)) { memset(dir, 0, fs->blocksize); @@ -180,10 +190,10 @@ static int fill_dir_block(ext2_filsys fs, if (fd->compress) ent->hash = ent->minor_hash = 0; else { - fd->err = ext2fs_dirhash(hash_alg, dirent->name, - name_len, - fs->super->s_hash_seed, - &ent->hash, &ent->minor_hash); + fd->err = get_filename_hash(fs, encrypted, + hash_alg, dirent->name, + ext2fs_dirent_name_len(dirent), + &ent->hash, &ent->minor_hash); if (fd->err) return BLOCK_ABORT; } @@ -368,6 +378,9 @@ static int duplicate_search_and_fix(e2fsck_t ctx, ext2_filsys fs, char new_name[256]; unsigned int new_len; int hash_alg; + int encrypted = 0; + char processed_filename[2*EXT2FS_DIGEST_SIZE]; + int processed_filename_len; clear_problem_context(&pctx); pctx.ino = ino; @@ -377,6 +390,10 @@ static int duplicate_search_and_fix(e2fsck_t ctx, ext2_filsys fs, (fs->super->s_flags & EXT2_FLAGS_UNSIGNED_HASH)) hash_alg += 3; + /* Determine if the directory is encrypted */ + if (fd->ctx->encrypted_dirs) + encrypted = ext2fs_u32_list_test(fd->ctx->encrypted_dirs, + fd->ino); for (i=1; i < fd->num_array; i++) { ent = fd->harray + i; prev = ent - 1; @@ -412,9 +429,9 @@ static int duplicate_search_and_fix(e2fsck_t ctx, ext2_filsys fs, if (fix_problem(ctx, PR_2_NON_UNIQUE_FILE, &pctx)) { memcpy(ent->dir->name, new_name, new_len); ext2fs_dirent_set_name_len(ent->dir, new_len); - ext2fs_dirhash(hash_alg, ent->dir->name, new_len, - fs->super->s_hash_seed, - &ent->hash, &ent->minor_hash); + get_filename_hash(fs, encrypted, + hash_alg, new_name, new_len, + &ent->hash, &ent->minor_hash); fixed++; } } @@ -817,6 +834,7 @@ errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino) fd.ctx = ctx; fd.buf = dir_buf; fd.inode = &inode; + fd.ino = ino; fd.err = 0; fd.dir_size = 0; fd.compress = 0;