summaryrefslogtreecommitdiffstats
path: root/fs/ext4/namei.c
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2015-05-31 19:35:32 +0200
committerTheodore Ts'o <tytso@mit.edu>2015-05-31 19:35:32 +0200
commit4d3c4e5b8cae3bb45ba933a22670504239958aa1 (patch)
tree810780fe18d77d514578323183221ebbc1ced2c3 /fs/ext4/namei.c
parentext4 crypto: clean up error handling in ext4_fname_setup_filename (diff)
downloadlinux-4d3c4e5b8cae3bb45ba933a22670504239958aa1.tar.xz
linux-4d3c4e5b8cae3bb45ba933a22670504239958aa1.zip
ext4 crypto: allocate the right amount of memory for the on-disk symlink
Previously we were taking the required padding when allocating space for the on-disk symlink. This caused a buffer overrun which could trigger a krenel crash when running fsstress. Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Diffstat (limited to 'fs/ext4/namei.c')
-rw-r--r--fs/ext4/namei.c32
1 files changed, 21 insertions, 11 deletions
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 401b099e3af3..bda4a5d6f5a5 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -3039,10 +3039,23 @@ static int ext4_symlink(struct inode *dir,
encryption_required = (ext4_encrypted_inode(dir) ||
DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb)));
- if (encryption_required)
- disk_link.len = encrypted_symlink_data_len(len) + 1;
- if (disk_link.len > dir->i_sb->s_blocksize)
- return -ENAMETOOLONG;
+ if (encryption_required) {
+ err = ext4_get_encryption_info(dir);
+ if (err)
+ return err;
+ if (ext4_encryption_info(dir) == NULL)
+ return -EPERM;
+ disk_link.len = (ext4_fname_encrypted_size(dir, len) +
+ sizeof(struct ext4_encrypted_symlink_data));
+ sd = kzalloc(disk_link.len, GFP_KERNEL);
+ if (!sd)
+ return -ENOMEM;
+ }
+
+ if (disk_link.len > dir->i_sb->s_blocksize) {
+ err = -ENAMETOOLONG;
+ goto err_free_sd;
+ }
dquot_initialize(dir);
@@ -3073,18 +3086,14 @@ static int ext4_symlink(struct inode *dir,
if (IS_ERR(inode)) {
if (handle)
ext4_journal_stop(handle);
- return PTR_ERR(inode);
+ err = PTR_ERR(inode);
+ goto err_free_sd;
}
if (encryption_required) {
struct qstr istr;
struct ext4_str ostr;
- sd = kzalloc(disk_link.len, GFP_NOFS);
- if (!sd) {
- err = -ENOMEM;
- goto err_drop_inode;
- }
istr.name = (const unsigned char *) symname;
istr.len = len;
ostr.name = sd->encrypted_path;
@@ -3156,10 +3165,11 @@ static int ext4_symlink(struct inode *dir,
err_drop_inode:
if (handle)
ext4_journal_stop(handle);
- kfree(sd);
clear_nlink(inode);
unlock_new_inode(inode);
iput(inode);
+err_free_sd:
+ kfree(sd);
return err;
}