Commit b22e8fed authored by Al Viro's avatar Al Viro

ecryptfs: fix failure handling in ->readlink()

If ecryptfs_readlink_lower() fails, buf remains an uninitialized
pointer and passing it nd_set_link() won't do anything good.

Fixed by switching ecryptfs_readlink_lower() to saner API - make it
return buf or ERR_PTR(...) and update callers.
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent d8ec26d7
...@@ -659,19 +659,17 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -659,19 +659,17 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
return rc; return rc;
} }
static int ecryptfs_readlink_lower(struct dentry *dentry, char **buf, static char *ecryptfs_readlink_lower(struct dentry *dentry, size_t *bufsiz)
size_t *bufsiz)
{ {
struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
char *lower_buf; char *lower_buf;
char *buf;
mm_segment_t old_fs; mm_segment_t old_fs;
int rc; int rc;
lower_buf = kmalloc(PATH_MAX, GFP_KERNEL); lower_buf = kmalloc(PATH_MAX, GFP_KERNEL);
if (!lower_buf) { if (!lower_buf)
rc = -ENOMEM; return ERR_PTR(-ENOMEM);
goto out;
}
old_fs = get_fs(); old_fs = get_fs();
set_fs(get_ds()); set_fs(get_ds());
rc = lower_dentry->d_inode->i_op->readlink(lower_dentry, rc = lower_dentry->d_inode->i_op->readlink(lower_dentry,
...@@ -680,21 +678,18 @@ static int ecryptfs_readlink_lower(struct dentry *dentry, char **buf, ...@@ -680,21 +678,18 @@ static int ecryptfs_readlink_lower(struct dentry *dentry, char **buf,
set_fs(old_fs); set_fs(old_fs);
if (rc < 0) if (rc < 0)
goto out; goto out;
rc = ecryptfs_decode_and_decrypt_filename(buf, bufsiz, dentry->d_sb, rc = ecryptfs_decode_and_decrypt_filename(&buf, bufsiz, dentry->d_sb,
lower_buf, rc); lower_buf, rc);
out: out:
kfree(lower_buf); kfree(lower_buf);
return rc; return rc ? ERR_PTR(rc) : buf;
} }
static void *ecryptfs_follow_link(struct dentry *dentry, struct nameidata *nd) static void *ecryptfs_follow_link(struct dentry *dentry, struct nameidata *nd)
{ {
char *buf; size_t len;
size_t len = PATH_MAX; char *buf = ecryptfs_readlink_lower(dentry, &len);
int rc; if (IS_ERR(buf))
rc = ecryptfs_readlink_lower(dentry, &buf, &len);
if (rc)
goto out; goto out;
fsstack_copy_attr_atime(dentry->d_inode, fsstack_copy_attr_atime(dentry->d_inode,
ecryptfs_dentry_to_lower(dentry)->d_inode); ecryptfs_dentry_to_lower(dentry)->d_inode);
...@@ -1003,10 +998,12 @@ static int ecryptfs_getattr_link(struct vfsmount *mnt, struct dentry *dentry, ...@@ -1003,10 +998,12 @@ static int ecryptfs_getattr_link(struct vfsmount *mnt, struct dentry *dentry,
char *target; char *target;
size_t targetsiz; size_t targetsiz;
rc = ecryptfs_readlink_lower(dentry, &target, &targetsiz); target = ecryptfs_readlink_lower(dentry, &targetsiz);
if (!rc) { if (!IS_ERR(target)) {
kfree(target); kfree(target);
stat->size = targetsiz; stat->size = targetsiz;
} else {
rc = PTR_ERR(target);
} }
} }
return rc; return rc;
......
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