diff options
| author | Michael Halcrow <mhalcrow@google.com> | 2015-04-12 01:09:03 -0400 |
|---|---|---|
| committer | Theodore Ts'o <tytso@mit.edu> | 2015-04-12 01:09:03 -0400 |
| commit | 1f3862b5575b138e83080232706e37ee24b8093e (patch) | |
| tree | 633ea79c868c96823445e2386ab68e978f3b5136 | |
| parent | b30984864406ad01b72eee486add103e9cb3526f (diff) | |
ext4 crypto: filename encryption modifications
Modifies htree_dirblock_to_tree, dx_make_map, ext4_match search_dir,
and ext4_find_dest_de to support fname crypto. Filename encryption
feature is not yet enabled at this patch.
Signed-off-by: Uday Savagaonkar <savagaon@google.com>
Signed-off-by: Ildar Muslukhov <ildarm@google.com>
Signed-off-by: Michael Halcrow <mhalcrow@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
| -rw-r--r-- | fs/ext4/namei.c | 248 |
1 files changed, 204 insertions, 44 deletions
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 85add9a9e1cd..4c84db862891 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
| @@ -253,8 +253,9 @@ static struct dx_frame *dx_probe(const struct qstr *d_name, | |||
| 253 | struct dx_hash_info *hinfo, | 253 | struct dx_hash_info *hinfo, |
| 254 | struct dx_frame *frame); | 254 | struct dx_frame *frame); |
| 255 | static void dx_release(struct dx_frame *frames); | 255 | static void dx_release(struct dx_frame *frames); |
| 256 | static int dx_make_map(struct ext4_dir_entry_2 *de, unsigned blocksize, | 256 | static int dx_make_map(struct inode *dir, struct ext4_dir_entry_2 *de, |
| 257 | struct dx_hash_info *hinfo, struct dx_map_entry map[]); | 257 | unsigned blocksize, struct dx_hash_info *hinfo, |
| 258 | struct dx_map_entry map[]); | ||
| 258 | static void dx_sort_map(struct dx_map_entry *map, unsigned count); | 259 | static void dx_sort_map(struct dx_map_entry *map, unsigned count); |
| 259 | static struct ext4_dir_entry_2 *dx_move_dirents(char *from, char *to, | 260 | static struct ext4_dir_entry_2 *dx_move_dirents(char *from, char *to, |
| 260 | struct dx_map_entry *offsets, int count, unsigned blocksize); | 261 | struct dx_map_entry *offsets, int count, unsigned blocksize); |
| @@ -968,7 +969,8 @@ static int htree_dirblock_to_tree(struct file *dir_file, | |||
| 968 | struct buffer_head *bh; | 969 | struct buffer_head *bh; |
| 969 | struct ext4_dir_entry_2 *de, *top; | 970 | struct ext4_dir_entry_2 *de, *top; |
| 970 | int err = 0, count = 0; | 971 | int err = 0, count = 0; |
| 971 | struct ext4_str tmp_str; | 972 | struct ext4_fname_crypto_ctx *ctx = NULL; |
| 973 | struct ext4_str fname_crypto_str = {.name = NULL, .len = 0}, tmp_str; | ||
| 972 | 974 | ||
| 973 | dxtrace(printk(KERN_INFO "In htree dirblock_to_tree: block %lu\n", | 975 | dxtrace(printk(KERN_INFO "In htree dirblock_to_tree: block %lu\n", |
| 974 | (unsigned long)block)); | 976 | (unsigned long)block)); |
| @@ -980,6 +982,24 @@ static int htree_dirblock_to_tree(struct file *dir_file, | |||
| 980 | top = (struct ext4_dir_entry_2 *) ((char *) de + | 982 | top = (struct ext4_dir_entry_2 *) ((char *) de + |
| 981 | dir->i_sb->s_blocksize - | 983 | dir->i_sb->s_blocksize - |
| 982 | EXT4_DIR_REC_LEN(0)); | 984 | EXT4_DIR_REC_LEN(0)); |
| 985 | #ifdef CONFIG_EXT4_FS_ENCRYPTION | ||
| 986 | /* Check if the directory is encrypted */ | ||
| 987 | ctx = ext4_get_fname_crypto_ctx(dir, EXT4_NAME_LEN); | ||
| 988 | if (IS_ERR(ctx)) { | ||
| 989 | err = PTR_ERR(ctx); | ||
| 990 | brelse(bh); | ||
| 991 | return err; | ||
| 992 | } | ||
| 993 | if (ctx != NULL) { | ||
| 994 | err = ext4_fname_crypto_alloc_buffer(ctx, EXT4_NAME_LEN, | ||
| 995 | &fname_crypto_str); | ||
| 996 | if (err < 0) { | ||
| 997 | ext4_put_fname_crypto_ctx(&ctx); | ||
| 998 | brelse(bh); | ||
| 999 | return err; | ||
| 1000 | } | ||
| 1001 | } | ||
| 1002 | #endif | ||
| 983 | for (; de < top; de = ext4_next_entry(de, dir->i_sb->s_blocksize)) { | 1003 | for (; de < top; de = ext4_next_entry(de, dir->i_sb->s_blocksize)) { |
| 984 | if (ext4_check_dir_entry(dir, NULL, de, bh, | 1004 | if (ext4_check_dir_entry(dir, NULL, de, bh, |
| 985 | bh->b_data, bh->b_size, | 1005 | bh->b_data, bh->b_size, |
| @@ -988,24 +1008,52 @@ static int htree_dirblock_to_tree(struct file *dir_file, | |||
| 988 | /* silently ignore the rest of the block */ | 1008 | /* silently ignore the rest of the block */ |
| 989 | break; | 1009 | break; |
| 990 | } | 1010 | } |
| 1011 | #ifdef CONFIG_EXT4_FS_ENCRYPTION | ||
| 1012 | err = ext4_fname_disk_to_hash(ctx, de, hinfo); | ||
| 1013 | if (err < 0) { | ||
| 1014 | count = err; | ||
| 1015 | goto errout; | ||
| 1016 | } | ||
| 1017 | #else | ||
| 991 | ext4fs_dirhash(de->name, de->name_len, hinfo); | 1018 | ext4fs_dirhash(de->name, de->name_len, hinfo); |
| 1019 | #endif | ||
| 992 | if ((hinfo->hash < start_hash) || | 1020 | if ((hinfo->hash < start_hash) || |
| 993 | ((hinfo->hash == start_hash) && | 1021 | ((hinfo->hash == start_hash) && |
| 994 | (hinfo->minor_hash < start_minor_hash))) | 1022 | (hinfo->minor_hash < start_minor_hash))) |
| 995 | continue; | 1023 | continue; |
| 996 | if (de->inode == 0) | 1024 | if (de->inode == 0) |
| 997 | continue; | 1025 | continue; |
| 998 | tmp_str.name = de->name; | 1026 | if (ctx == NULL) { |
| 999 | tmp_str.len = de->name_len; | 1027 | /* Directory is not encrypted */ |
| 1000 | err = ext4_htree_store_dirent(dir_file, | 1028 | tmp_str.name = de->name; |
| 1001 | hinfo->hash, hinfo->minor_hash, de, &tmp_str); | 1029 | tmp_str.len = de->name_len; |
| 1030 | err = ext4_htree_store_dirent(dir_file, | ||
| 1031 | hinfo->hash, hinfo->minor_hash, de, | ||
| 1032 | &tmp_str); | ||
| 1033 | } else { | ||
| 1034 | /* Directory is encrypted */ | ||
| 1035 | err = ext4_fname_disk_to_usr(ctx, de, | ||
| 1036 | &fname_crypto_str); | ||
| 1037 | if (err < 0) { | ||
| 1038 | count = err; | ||
| 1039 | goto errout; | ||
| 1040 | } | ||
| 1041 | err = ext4_htree_store_dirent(dir_file, | ||
| 1042 | hinfo->hash, hinfo->minor_hash, de, | ||
| 1043 | &fname_crypto_str); | ||
| 1044 | } | ||
| 1002 | if (err != 0) { | 1045 | if (err != 0) { |
| 1003 | brelse(bh); | 1046 | count = err; |
| 1004 | return err; | 1047 | goto errout; |
| 1005 | } | 1048 | } |
| 1006 | count++; | 1049 | count++; |
| 1007 | } | 1050 | } |
| 1051 | errout: | ||
| 1008 | brelse(bh); | 1052 | brelse(bh); |
| 1053 | #ifdef CONFIG_EXT4_FS_ENCRYPTION | ||
| 1054 | ext4_put_fname_crypto_ctx(&ctx); | ||
| 1055 | ext4_fname_crypto_free_buffer(&fname_crypto_str); | ||
| 1056 | #endif | ||
| 1009 | return count; | 1057 | return count; |
| 1010 | } | 1058 | } |
| 1011 | 1059 | ||
| @@ -1138,17 +1186,33 @@ static inline int search_dirblock(struct buffer_head *bh, | |||
| 1138 | * Create map of hash values, offsets, and sizes, stored at end of block. | 1186 | * Create map of hash values, offsets, and sizes, stored at end of block. |
| 1139 | * Returns number of entries mapped. | 1187 | * Returns number of entries mapped. |
| 1140 | */ | 1188 | */ |
| 1141 | static int dx_make_map(struct ext4_dir_entry_2 *de, unsigned blocksize, | 1189 | static int dx_make_map(struct inode *dir, struct ext4_dir_entry_2 *de, |
| 1142 | struct dx_hash_info *hinfo, | 1190 | unsigned blocksize, struct dx_hash_info *hinfo, |
| 1143 | struct dx_map_entry *map_tail) | 1191 | struct dx_map_entry *map_tail) |
| 1144 | { | 1192 | { |
| 1145 | int count = 0; | 1193 | int count = 0; |
| 1146 | char *base = (char *) de; | 1194 | char *base = (char *) de; |
| 1147 | struct dx_hash_info h = *hinfo; | 1195 | struct dx_hash_info h = *hinfo; |
| 1196 | #ifdef CONFIG_EXT4_FS_ENCRYPTION | ||
| 1197 | struct ext4_fname_crypto_ctx *ctx = NULL; | ||
| 1198 | int err; | ||
| 1199 | |||
| 1200 | ctx = ext4_get_fname_crypto_ctx(dir, EXT4_NAME_LEN); | ||
| 1201 | if (IS_ERR(ctx)) | ||
| 1202 | return PTR_ERR(ctx); | ||
| 1203 | #endif | ||
| 1148 | 1204 | ||
| 1149 | while ((char *) de < base + blocksize) { | 1205 | while ((char *) de < base + blocksize) { |
| 1150 | if (de->name_len && de->inode) { | 1206 | if (de->name_len && de->inode) { |
| 1207 | #ifdef CONFIG_EXT4_FS_ENCRYPTION | ||
| 1208 | err = ext4_fname_disk_to_hash(ctx, de, &h); | ||
| 1209 | if (err < 0) { | ||
| 1210 | ext4_put_fname_crypto_ctx(&ctx); | ||
| 1211 | return err; | ||
| 1212 | } | ||
| 1213 | #else | ||
| 1151 | ext4fs_dirhash(de->name, de->name_len, &h); | 1214 | ext4fs_dirhash(de->name, de->name_len, &h); |
| 1215 | #endif | ||
| 1152 | map_tail--; | 1216 | map_tail--; |
| 1153 | map_tail->hash = h.hash; | 1217 | map_tail->hash = h.hash; |
| 1154 | map_tail->offs = ((char *) de - base)>>2; | 1218 | map_tail->offs = ((char *) de - base)>>2; |
| @@ -1159,6 +1223,9 @@ static int dx_make_map(struct ext4_dir_entry_2 *de, unsigned blocksize, | |||
| 1159 | /* XXX: do we need to check rec_len == 0 case? -Chris */ | 1223 | /* XXX: do we need to check rec_len == 0 case? -Chris */ |
| 1160 | de = ext4_next_entry(de, blocksize); | 1224 | de = ext4_next_entry(de, blocksize); |
| 1161 | } | 1225 | } |
| 1226 | #ifdef CONFIG_EXT4_FS_ENCRYPTION | ||
| 1227 | ext4_put_fname_crypto_ctx(&ctx); | ||
| 1228 | #endif | ||
| 1162 | return count; | 1229 | return count; |
| 1163 | } | 1230 | } |
| 1164 | 1231 | ||
| @@ -1209,57 +1276,107 @@ static void dx_insert_block(struct dx_frame *frame, u32 hash, ext4_lblk_t block) | |||
| 1209 | * `len <= EXT4_NAME_LEN' is guaranteed by caller. | 1276 | * `len <= EXT4_NAME_LEN' is guaranteed by caller. |
| 1210 | * `de != NULL' is guaranteed by caller. | 1277 | * `de != NULL' is guaranteed by caller. |
| 1211 | */ | 1278 | */ |
| 1212 | static inline int ext4_match (int len, const char * const name, | 1279 | static inline int ext4_match(struct ext4_fname_crypto_ctx *ctx, |
| 1213 | struct ext4_dir_entry_2 * de) | 1280 | struct ext4_str *fname_crypto_str, |
| 1281 | int len, const char * const name, | ||
| 1282 | struct ext4_dir_entry_2 *de) | ||
| 1214 | { | 1283 | { |
| 1215 | if (len != de->name_len) | 1284 | int res; |
| 1216 | return 0; | 1285 | |
| 1217 | if (!de->inode) | 1286 | if (!de->inode) |
| 1218 | return 0; | 1287 | |
