summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2013-11-30 07:51:47 +0400
committerAl Viro <viro@zeniv.linux.org.uk>2014-01-25 12:13:00 +0400
commitb22e8fedc19588864a6ba0acefbbed06f05ba713 (patch)
treedb6badfb305598e47a867f399fe30ec38c304cb6
parentd8ec26d7f8287f5788a494f56e8814210f0e64be (diff)
downloadlinux-b22e8fedc19588864a6ba0acefbbed06f05ba713.tar.xz
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>
-rw-r--r--fs/ecryptfs/inode.c29
1 files changed, 13 insertions, 16 deletions
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index c36c44824471..b167ca48b8ee 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -659,19 +659,17 @@ out_lock:
return rc;
}
-static int ecryptfs_readlink_lower(struct dentry *dentry, char **buf,
- size_t *bufsiz)
+static char *ecryptfs_readlink_lower(struct dentry *dentry, size_t *bufsiz)
{
struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
char *lower_buf;
+ char *buf;
mm_segment_t old_fs;
int rc;
lower_buf = kmalloc(PATH_MAX, GFP_KERNEL);
- if (!lower_buf) {
- rc = -ENOMEM;
- goto out;
- }
+ if (!lower_buf)
+ return ERR_PTR(-ENOMEM);
old_fs = get_fs();
set_fs(get_ds());
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);
if (rc < 0)
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);
out:
kfree(lower_buf);
- return rc;
+ return rc ? ERR_PTR(rc) : buf;
}
static void *ecryptfs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
- char *buf;
- size_t len = PATH_MAX;
- int rc;
-
- rc = ecryptfs_readlink_lower(dentry, &buf, &len);
- if (rc)
+ size_t len;
+ char *buf = ecryptfs_readlink_lower(dentry, &len);
+ if (IS_ERR(buf))
goto out;
fsstack_copy_attr_atime(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;
size_t targetsiz;
- rc = ecryptfs_readlink_lower(dentry, &target, &targetsiz);
- if (!rc) {
+ target = ecryptfs_readlink_lower(dentry, &targetsiz);
+ if (!IS_ERR(target)) {
kfree(target);
stat->size = targetsiz;
+ } else {
+ rc = PTR_ERR(target);
}
}
return rc;