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: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
d8ec26d7f8
commit
b22e8fedc1
|
@ -659,19 +659,17 @@ out_lock:
|
||||||
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,
|
||||||
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,
|
||||||
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;
|
||||||
|
|
Loading…
Reference in New Issue