Commit 5de0b4d0 authored by Theodore Ts'o's avatar Theodore Ts'o

ext4 crypto: simplify and speed up filename encryption

Avoid using SHA-1 when calculating the user-visible filename when the
encryption key is available, and avoid decrypting lots of filenames
when searching for a directory entry in a directory block.

Change-Id: If4655f144784978ba0305b597bfa1c8d7bb69e63
Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
parent 6ddb2447
...@@ -198,106 +198,57 @@ static int ext4_fname_decrypt(struct ext4_fname_crypto_ctx *ctx, ...@@ -198,106 +198,57 @@ static int ext4_fname_decrypt(struct ext4_fname_crypto_ctx *ctx,
return oname->len; return oname->len;
} }
static const char *lookup_table =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
/** /**
* ext4_fname_encode_digest() - * ext4_fname_encode_digest() -
* *
* Encodes the input digest using characters from the set [a-zA-Z0-9_+]. * Encodes the input digest using characters from the set [a-zA-Z0-9_+].
* The encoded string is roughly 4/3 times the size of the input string. * The encoded string is roughly 4/3 times the size of the input string.
*/ */
int ext4_fname_encode_digest(char *dst, char *src, u32 len) static int digest_encode(const char *src, int len, char *dst)
{ {
static const char *lookup_table = int i = 0, bits = 0, ac = 0;
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_+"; char *cp = dst;
u32 current_chunk, num_chunks, i;
char tmp_buf[3]; while (i < len) {
u32 c0, c1, c2, c3; ac += (((unsigned char) src[i]) << bits);
bits += 8;
current_chunk = 0; do {
num_chunks = len/3; *cp++ = lookup_table[ac & 0x3f];
for (i = 0; i < num_chunks; i++) { ac >>= 6;
c0 = src[3*i] & 0x3f; bits -= 6;
c1 = (((src[3*i]>>6)&0x3) | ((src[3*i+1] & 0xf)<<2)) & 0x3f; } while (bits >= 6);
c2 = (((src[3*i+1]>>4)&0xf) | ((src[3*i+2] & 0x3)<<4)) & 0x3f;
c3 = (src[3*i+2]>>2) & 0x3f;
dst[4*i] = lookup_table[c0];
dst[4*i+1] = lookup_table[c1];
dst[4*i+2] = lookup_table[c2];
dst[4*i+3] = lookup_table[c3];
}
if (i*3 < len) {
memset(tmp_buf, 0, 3);
memcpy(tmp_buf, &src[3*i], len-3*i);
c0 = tmp_buf[0] & 0x3f;
c1 = (((tmp_buf[0]>>6)&0x3) | ((tmp_buf[1] & 0xf)<<2)) & 0x3f;
c2 = (((tmp_buf[1]>>4)&0xf) | ((tmp_buf[2] & 0x3)<<4)) & 0x3f;
c3 = (tmp_buf[2]>>2) & 0x3f;
dst[4*i] = lookup_table[c0];
dst[4*i+1] = lookup_table[c1];
dst[4*i+2] = lookup_table[c2];
dst[4*i+3] = lookup_table[c3];
i++; i++;
} }
return (i * 4); if (bits)
*cp++ = lookup_table[ac & 0x3f];
return cp - dst;
} }
/** static int digest_decode(const char *src, int len, char *dst)
* ext4_fname_hash() -
*
* This function computes the hash of the input filename, and sets the output
* buffer to the *encoded* digest. It returns the length of the digest as its
* return value. Errors are returned as negative numbers. We trust the caller
* to allocate sufficient memory to oname string.
*/
static int ext4_fname_hash(struct ext4_fname_crypto_ctx *ctx,
const struct ext4_str *iname,
struct ext4_str *oname)
{ {
struct scatterlist sg; int i = 0, bits = 0, ac = 0;
struct hash_desc desc = { const char *p;
.tfm = (struct crypto_hash *)ctx->htfm, char *cp = dst;
.flags = CRYPTO_TFM_REQ_MAY_SLEEP
}; while (i < len) {
int res = 0; p = strchr(lookup_table, src[i]);
if (p == NULL || src[i] == 0)
if (iname->len <= EXT4_FNAME_CRYPTO_DIGEST_SIZE) { return -2;
res = ext4_fname_encode_digest(oname->name, iname->name, ac += (p - lookup_table) << bits;
iname->len); bits += 6;
oname->len = res; if (bits >= 8) {
return res; *cp++ = ac & 0xff;
ac >>= 8;
bits -= 8;
} }
i++;
sg_init_one(&sg, iname->name, iname->len);
res = crypto_hash_init(&desc);
if (res) {
printk(KERN_ERR
"%s: Error initializing crypto hash; res = [%d]\n",
__func__, res);
goto out;
}
res = crypto_hash_update(&desc, &sg, iname->len);
if (res) {
printk(KERN_ERR
"%s: Error updating crypto hash; res = [%d]\n",
__func__, res);
goto out;
} }
res = crypto_hash_final(&desc, if (ac)
&oname->name[EXT4_FNAME_CRYPTO_DIGEST_SIZE]); return -1;
if (res) { return cp - dst;
printk(KERN_ERR
"%s: Error finalizing crypto hash; res = [%d]\n",
__func__, res);
goto out;
}
/* Encode the digest as a printable string--this will increase the
* size of the digest */
oname->name[0] = 'I';
res = ext4_fname_encode_digest(oname->name+1,
&oname->name[EXT4_FNAME_CRYPTO_DIGEST_SIZE],
EXT4_FNAME_CRYPTO_DIGEST_SIZE) + 1;
oname->len = res;
out:
return res;
} }
/** /**
...@@ -571,9 +522,13 @@ void ext4_fname_crypto_free_buffer(struct ext4_str *crypto_str) ...@@ -571,9 +522,13 @@ void ext4_fname_crypto_free_buffer(struct ext4_str *crypto_str)
* ext4_fname_disk_to_usr() - converts a filename from disk space to user space * ext4_fname_disk_to_usr() - converts a filename from disk space to user space
*/ */
int _ext4_fname_disk_to_usr(struct ext4_fname_crypto_ctx *ctx, int _ext4_fname_disk_to_usr(struct ext4_fname_crypto_ctx *ctx,
struct dx_hash_info *hinfo,
const struct ext4_str *iname, const struct ext4_str *iname,
struct ext4_str *oname) struct ext4_str *oname)
{ {
char buf[24];
int ret;
if (ctx == NULL) if (ctx == NULL)
return -EIO; return -EIO;
if (iname->len < 3) { if (iname->len < 3) {
...@@ -587,18 +542,33 @@ int _ext4_fname_disk_to_usr(struct ext4_fname_crypto_ctx *ctx, ...@@ -587,18 +542,33 @@ int _ext4_fname_disk_to_usr(struct ext4_fname_crypto_ctx *ctx,
} }
if (ctx->has_valid_key) if (ctx->has_valid_key)
return ext4_fname_decrypt(ctx, iname, oname); return ext4_fname_decrypt(ctx, iname, oname);
else
return ext4_fname_hash(ctx, iname, oname); if (iname->len <= EXT4_FNAME_CRYPTO_DIGEST_SIZE) {
ret = digest_encode(iname->name, iname->len, oname->name);
oname->len = ret;
return ret;
}
if (hinfo) {
memcpy(buf, &hinfo->hash, 4);
memcpy(buf+4, &hinfo->minor_hash, 4);
} else
memset(buf, 0, 8);
memcpy(buf + 8, iname->name + iname->len - 16, 16);
oname->name[0] = '_';
ret = digest_encode(buf, 24, oname->name+1);
oname->len = ret + 1;
return ret + 1;
} }
int ext4_fname_disk_to_usr(struct ext4_fname_crypto_ctx *ctx, int ext4_fname_disk_to_usr(struct ext4_fname_crypto_ctx *ctx,
struct dx_hash_info *hinfo,
const struct ext4_dir_entry_2 *de, const struct ext4_dir_entry_2 *de,
struct ext4_str *oname) struct ext4_str *oname)
{ {
struct ext4_str iname = {.name = (unsigned char *) de->name, struct ext4_str iname = {.name = (unsigned char *) de->name,
.len = de->name_len }; .len = de->name_len };
return _ext4_fname_disk_to_usr(ctx, &iname, oname); return _ext4_fname_disk_to_usr(ctx, hinfo, &iname, oname);
} }
...@@ -640,10 +610,11 @@ int ext4_fname_usr_to_hash(struct ext4_fname_crypto_ctx *ctx, ...@@ -640,10 +610,11 @@ int ext4_fname_usr_to_hash(struct ext4_fname_crypto_ctx *ctx,
const struct qstr *iname, const struct qstr *iname,
struct dx_hash_info *hinfo) struct dx_hash_info *hinfo)
{ {
struct ext4_str tmp, tmp2; struct ext4_str tmp;
int ret = 0; int ret = 0;
char buf[EXT4_FNAME_CRYPTO_DIGEST_SIZE+1];
if (!ctx || !ctx->has_valid_key || if (!ctx ||
((iname->name[0] == '.') && ((iname->name[0] == '.') &&
((iname->len == 1) || ((iname->len == 1) ||
((iname->name[1] == '.') && (iname->len == 2))))) { ((iname->name[1] == '.') && (iname->len == 2))))) {
...@@ -651,59 +622,90 @@ int ext4_fname_usr_to_hash(struct ext4_fname_crypto_ctx *ctx, ...@@ -651,59 +622,90 @@ int ext4_fname_usr_to_hash(struct ext4_fname_crypto_ctx *ctx,
return 0; return 0;
} }
if (!ctx->has_valid_key && iname->name[0] == '_') {
if (iname->len != 33)
return -ENOENT;
ret = digest_decode(iname->name+1, iname->len, buf);
if (ret != 24)
return -ENOENT;
memcpy(&hinfo->hash, buf, 4);
memcpy(&hinfo->minor_hash, buf + 4, 4);
return 0;
}
if (!ctx->has_valid_key && iname->name[0] != '_') {
if (iname->len > 43)
return -ENOENT;
ret = digest_decode(iname->name, iname->len, buf);
ext4fs_dirhash(buf, ret, hinfo);
return 0;
}
/* First encrypt the plaintext name */ /* First encrypt the plaintext name */
ret = ext4_fname_crypto_alloc_buffer(ctx, iname->len, &tmp); ret = ext4_fname_crypto_alloc_buffer(ctx, iname->len, &tmp);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = ext4_fname_encrypt(ctx, iname, &tmp); ret = ext4_fname_encrypt(ctx, iname, &tmp);
if (ret < 0) if (ret >= 0) {
goto out; ext4fs_dirhash(tmp.name, tmp.len, hinfo);
ret = 0;
tmp2.len = (4 * ((EXT4_FNAME_CRYPTO_DIGEST_SIZE + 2) / 3)) + 1;
tmp2.name = kmalloc(tmp2.len + 1, GFP_KERNEL);
if (tmp2.name == NULL) {
ret = -ENOMEM;
goto out;
} }
ret = ext4_fname_hash(ctx, &tmp, &tmp2);
if (ret > 0)
ext4fs_dirhash(tmp2.name, tmp2.len, hinfo);
ext4_fname_crypto_free_buffer(&tmp2);
out:
ext4_fname_crypto_free_buffer(&tmp); ext4_fname_crypto_free_buffer(&tmp);
return ret; return ret;
} }
/** int ext4_fname_match(struct ext4_fname_crypto_ctx *ctx, struct ext4_str *cstr,
* ext4_fname_disk_to_htree() - converts a filename from disk space to htree-access string int len, const char * const name,
*/ struct ext4_dir_entry_2 *de)
int ext4_fname_disk_to_hash(struct ext4_fname_crypto_ctx *ctx,
const struct ext4_dir_entry_2 *de,
struct dx_hash_info *hinfo)
{ {
struct ext4_str iname = {.name = (unsigned char *) de->name, int ret = -ENOENT;
.len = de->name_len}; int bigname = (*name == '_');
struct ext4_str tmp;
int ret;
if (!ctx || if (ctx->has_valid_key) {
((iname.name[0] == '.') && if (cstr->name == NULL) {
((iname.len == 1) || struct qstr istr;
((iname.name[1] == '.') && (iname.len == 2))))) {
ext4fs_dirhash(iname.name, iname.len, hinfo);
return 0;
}
tmp.len = (4 * ((EXT4_FNAME_CRYPTO_DIGEST_SIZE + 2) / 3)) + 1; ret = ext4_fname_crypto_alloc_buffer(ctx, len, cstr);
tmp.name = kmalloc(tmp.len + 1, GFP_KERNEL); if (ret < 0)
if (tmp.name == NULL) goto errout;
istr.name = name;
istr.len = len;
ret = ext4_fname_encrypt(ctx, &istr, cstr);
if (ret < 0)
goto errout;
}
} else {
if (cstr->name == NULL) {
cstr->name = kmalloc(32, GFP_KERNEL);
if (cstr->name == NULL)
return -ENOMEM; return -ENOMEM;
if ((bigname && (len != 33)) ||
ret = ext4_fname_hash(ctx, &iname, &tmp); (!bigname && (len > 43)))
if (ret > 0) goto errout;
ext4fs_dirhash(tmp.name, tmp.len, hinfo); ret = digest_decode(name+bigname, len-bigname,
ext4_fname_crypto_free_buffer(&tmp); cstr->name);
if (ret < 0) {
ret = -ENOENT;
goto errout;
}
cstr->len = ret;
}
if (bigname) {
if (de->name_len < 16)
return 0;
ret = memcmp(de->name + de->name_len - 16,
cstr->name + 8, 16);
return (ret == 0) ? 1 : 0;
}
}
if (de->name_len != cstr->len)
return 0;
ret = memcmp(de->name, cstr->name, cstr->len);
return (ret == 0) ? 1 : 0;
errout:
kfree(cstr->name);
cstr->name = NULL;
return ret; return ret;
} }
...@@ -249,7 +249,7 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx) ...@@ -249,7 +249,7 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
} else { } else {
/* Directory is encrypted */ /* Directory is encrypted */
err = ext4_fname_disk_to_usr(enc_ctx, err = ext4_fname_disk_to_usr(enc_ctx,
de, &fname_crypto_str); NULL, de, &fname_crypto_str);
if (err < 0) if (err < 0)
goto errout; goto errout;
if (!dir_emit(ctx, if (!dir_emit(ctx,
......
...@@ -2093,9 +2093,11 @@ u32 ext4_fname_crypto_round_up(u32 size, u32 blksize); ...@@ -2093,9 +2093,11 @@ u32 ext4_fname_crypto_round_up(u32 size, u32 blksize);
int ext4_fname_crypto_alloc_buffer(struct ext4_fname_crypto_ctx *ctx, int ext4_fname_crypto_alloc_buffer(struct ext4_fname_crypto_ctx *ctx,
u32 ilen, struct ext4_str *crypto_str); u32 ilen, struct ext4_str *crypto_str);
int _ext4_fname_disk_to_usr(struct ext4_fname_crypto_ctx *ctx, int _ext4_fname_disk_to_usr(struct ext4_fname_crypto_ctx *ctx,
struct dx_hash_info *hinfo,
const struct ext4_str *iname, const struct ext4_str *iname,
struct ext4_str *oname); struct ext4_str *oname);
int ext4_fname_disk_to_usr(struct ext4_fname_crypto_ctx *ctx, int ext4_fname_disk_to_usr(struct ext4_fname_crypto_ctx *ctx,
struct dx_hash_info *hinfo,
const struct ext4_dir_entry_2 *de, const struct ext4_dir_entry_2 *de,
struct ext4_str *oname); struct ext4_str *oname);
int ext4_fname_usr_to_disk(struct ext4_fname_crypto_ctx *ctx, int ext4_fname_usr_to_disk(struct ext4_fname_crypto_ctx *ctx,
...@@ -2104,11 +2106,12 @@ int ext4_fname_usr_to_disk(struct ext4_fname_crypto_ctx *ctx, ...@@ -2104,11 +2106,12 @@ int ext4_fname_usr_to_disk(struct ext4_fname_crypto_ctx *ctx,
int ext4_fname_usr_to_hash(struct ext4_fname_crypto_ctx *ctx, int ext4_fname_usr_to_hash(struct ext4_fname_crypto_ctx *ctx,
const struct qstr *iname, const struct qstr *iname,
struct dx_hash_info *hinfo); struct dx_hash_info *hinfo);
int ext4_fname_disk_to_hash(struct ext4_fname_crypto_ctx *ctx,
const struct ext4_dir_entry_2 *de,
struct dx_hash_info *hinfo);
int ext4_fname_crypto_namelen_on_disk(struct ext4_fname_crypto_ctx *ctx, int ext4_fname_crypto_namelen_on_disk(struct ext4_fname_crypto_ctx *ctx,
u32 namelen); u32 namelen);
int ext4_fname_match(struct ext4_fname_crypto_ctx *ctx, struct ext4_str *cstr,
int len, const char * const name,
struct ext4_dir_entry_2 *de);
#ifdef CONFIG_EXT4_FS_ENCRYPTION #ifdef CONFIG_EXT4_FS_ENCRYPTION
void ext4_put_fname_crypto_ctx(struct ext4_fname_crypto_ctx **ctx); void ext4_put_fname_crypto_ctx(struct ext4_fname_crypto_ctx **ctx);
......
...@@ -640,7 +640,7 @@ static struct stats dx_show_leaf(struct inode *dir, ...@@ -640,7 +640,7 @@ static struct stats dx_show_leaf(struct inode *dir,
ext4_put_fname_crypto_ctx(&ctx); ext4_put_fname_crypto_ctx(&ctx);
ctx = NULL; ctx = NULL;
} }
res = ext4_fname_disk_to_usr(ctx, de, res = ext4_fname_disk_to_usr(ctx, NULL, de,
&fname_crypto_str); &fname_crypto_str);
if (res < 0) { if (res < 0) {
printk(KERN_WARNING "Error " printk(KERN_WARNING "Error "
...@@ -653,15 +653,8 @@ static struct stats dx_show_leaf(struct inode *dir, ...@@ -653,15 +653,8 @@ static struct stats dx_show_leaf(struct inode *dir,
name = fname_crypto_str.name; name = fname_crypto_str.name;
len = fname_crypto_str.len; len = fname_crypto_str.len;
} }
res = ext4_fname_disk_to_hash(ctx, de, ext4fs_dirhash(de->name, de->name_len,
&h); &h);
if (res < 0) {
printk(KERN_WARNING "Error "
"converting filename "
"from disk to htree"
"\n");
h.hash = 0xDEADBEEF;
}
printk("%*.s:(E)%x.%u ", len, name, printk("%*.s:(E)%x.%u ", len, name,
h.hash, (unsigned) ((char *) de h.hash, (unsigned) ((char *) de
- base)); - base));
...@@ -1008,15 +1001,7 @@ static int htree_dirblock_to_tree(struct file *dir_file, ...@@ -1008,15 +1001,7 @@ static int htree_dirblock_to_tree(struct file *dir_file,
/* silently ignore the rest of the block */ /* silently ignore the rest of the block */
break; break;
} }
#ifdef CONFIG_EXT4_FS_ENCRYPTION
err = ext4_fname_disk_to_hash(ctx, de, hinfo);
if (err < 0) {
count = err;
goto errout;
}
#else
ext4fs_dirhash(de->name, de->name_len, hinfo); ext4fs_dirhash(de->name, de->name_len, hinfo);
#endif
if ((hinfo->hash < start_hash) || if ((hinfo->hash < start_hash) ||
((hinfo->hash == start_hash) && ((hinfo->hash == start_hash) &&
(hinfo->minor_hash < start_minor_hash))) (hinfo->minor_hash < start_minor_hash)))
...@@ -1032,7 +1017,7 @@ static int htree_dirblock_to_tree(struct file *dir_file, ...@@ -1032,7 +1017,7 @@ static int htree_dirblock_to_tree(struct file *dir_file,
&tmp_str); &tmp_str);
} else { } else {
/* Directory is encrypted */ /* Directory is encrypted */
err = ext4_fname_disk_to_usr(ctx, de, err = ext4_fname_disk_to_usr(ctx, hinfo, de,
&fname_crypto_str); &fname_crypto_str);
if (err < 0) { if (err < 0) {
count = err; count = err;
...@@ -1193,26 +1178,10 @@ static int dx_make_map(struct inode *dir, struct ext4_dir_entry_2 *de, ...@@ -1193,26 +1178,10 @@ static int dx_make_map(struct inode *dir, struct ext4_dir_entry_2 *de,
int count = 0; int count = 0;
char *base = (char *) de; char *base = (char *) de;
struct dx_hash_info h = *hinfo; struct dx_hash_info h = *hinfo;
#ifdef CONFIG_EXT4_FS_ENCRYPTION
struct ext4_fname_crypto_ctx *ctx = NULL;
int err;
ctx = ext4_get_fname_crypto_ctx(dir, EXT4_NAME_LEN);
if (IS_ERR(ctx))
return PTR_ERR(ctx);
#endif
while ((char *) de < base + blocksize) { while ((char *) de < base + blocksize) {
if (de->name_len && de->inode) { if (de->name_len && de->inode) {
#ifdef CONFIG_EXT4_FS_ENCRYPTION
err = ext4_fname_disk_to_hash(ctx, de, &h);
if (err < 0) {
ext4_put_fname_crypto_ctx(&ctx);
return err;
}
#else
ext4fs_dirhash(de->name, de->name_len, &h); ext4fs_dirhash(de->name, de->name_len, &h);
#endif
map_tail--; map_tail--;
map_tail->hash = h.hash; map_tail->hash = h.hash;
map_tail->offs = ((char *) de - base)>>2; map_tail->offs = ((char *) de - base)>>2;
...@@ -1223,9 +1192,6 @@ static int dx_make_map(struct inode *dir, struct ext4_dir_entry_2 *de, ...@@ -1223,9 +1192,6 @@ static int dx_make_map(struct inode *dir, struct ext4_dir_entry_2 *de,
/* XXX: do we need to check rec_len == 0 case? -Chris */ /* XXX: do we need to check rec_len == 0 case? -Chris */
de = ext4_next_entry(de, blocksize); de = ext4_next_entry(de, blocksize);
} }
#ifdef CONFIG_EXT4_FS_ENCRYPTION
ext4_put_fname_crypto_ctx(&ctx);
#endif
return count; return count;
} }
...@@ -1287,16 +1253,8 @@ static inline int ext4_match(struct ext4_fname_crypto_ctx *ctx, ...@@ -1287,16 +1253,8 @@ static inline int ext4_match(struct ext4_fname_crypto_ctx *ctx,
return 0; return 0;
#ifdef CONFIG_EXT4_FS_ENCRYPTION #ifdef CONFIG_EXT4_FS_ENCRYPTION
if (ctx) { if (ctx)
/* Directory is encrypted */ return ext4_fname_match(ctx, fname_crypto_str, len, name, de);
res = ext4_fname_disk_to_usr(ctx, de, fname_crypto_str);
if (res < 0)
return res;
if (len != res)
return 0;
res = memcmp(name, fname_crypto_str->name, len);
return (res == 0) ? 1 : 0;
}
#endif #endif
if (len != de->name_len) if (len != de->name_len)
return 0; return 0;
...@@ -1324,16 +1282,6 @@ int search_dir(struct buffer_head *bh, char *search_buf, int buf_size, ...@@ -1324,16 +1282,6 @@ int search_dir(struct buffer_head *bh, char *search_buf, int buf_size,
if (IS_ERR(ctx)) if (IS_ERR(ctx))
return -1; return -1;
if (ctx != NULL) {
/* Allocate buffer to hold maximum name length */
res = ext4_fname_crypto_alloc_buffer(ctx, EXT4_NAME_LEN,
&fname_crypto_str);
if (res < 0) {
ext4_put_fname_crypto_ctx(&ctx);
return -1;
}
}
de = (struct ext4_dir_entry_2 *)search_buf; de = (struct ext4_dir_entry_2 *)search_buf;
dlimit = search_buf + buf_size; dlimit = search_buf + buf_size;
while ((char *) de < dlimit) { while ((char *) de < dlimit) {
...@@ -1872,14 +1820,6 @@ int ext4_find_dest_de(struct inode *dir, struct inode *inode, ...@@ -1872,14 +1820,6 @@ int ext4_find_dest_de(struct inode *dir, struct inode *inode,
return res; return res;
} }
reclen = EXT4_DIR_REC_LEN(res); reclen = EXT4_DIR_REC_LEN(res);
/* Allocate buffer to hold maximum name length */
res = ext4_fname_crypto_alloc_buffer(ctx, EXT4_NAME_LEN,
&fname_crypto_str);
if (res < 0) {
ext4_put_fname_crypto_ctx(&ctx);
return -1;
}
} }
de = (struct ext4_dir_entry_2 *)buf; de = (struct ext4_dir_entry_2 *)buf;
......
...@@ -74,7 +74,7 @@ static void *ext4_follow_link(struct dentry *dentry, struct nameidata *nd) ...@@ -74,7 +74,7 @@ static void *ext4_follow_link(struct dentry *dentry, struct nameidata *nd)
goto errout; goto errout;
} }
pstr.name = paddr; pstr.name = paddr;
res = _ext4_fname_disk_to_usr(ctx, &cstr, &pstr); res = _ext4_fname_disk_to_usr(ctx, NULL, &cstr, &pstr);
if (res < 0) if (res < 0)
goto errout; goto errout;
/* Null-terminate the name */ /* Null-terminate the name */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment