diff options
author | VMware, Inc <> | 2013-09-17 20:32:40 -0700 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2013-09-22 22:19:59 -0700 |
commit | e55039cb8452777c2024ce3a13cd3439f36fd554 (patch) | |
tree | 106230286f48ba51e55dd9b0e59b748091cf21db | |
parent | 0d5581ae35aaca0a1e645d8ffccaae77c0e39d4a (diff) |
HGFS: Fix Linux client symlinks
The kernel buffer holding the symlink name was being freed incorrectly
when it was used by the VFS layer. This resulted in corruption and
invalid names being used when trying to lookup the symlink's target.
The HgfsFollowlink should not be calling vfs_follow_link but calling
nd_set_link to save the link target name that HGFS allocated. To deal
with the release of the name, HgfsPutlink has now been added which the
VFS layer will call as needed and this function retrieves the name from
the name structure using nd_get_link and releases the buffer. Then for
completeness calls nd_set_link with NULL to clear it from the name
structure. The VFS layer internally calls vfs_follow_link after the
HgfsFollowlink call passing the link target name from the name object
that HGFS stored. Hence, why HGFS should not call it directly.
Signed-off-by: Dmitry Torokhov <dtor@vmware.com>
-rw-r--r-- | open-vm-tools/modules/linux/vmhgfs/link.c | 60 |
1 files changed, 55 insertions, 5 deletions
diff --git a/open-vm-tools/modules/linux/vmhgfs/link.c b/open-vm-tools/modules/linux/vmhgfs/link.c index 8434813c..65d8a237 100644 --- a/open-vm-tools/modules/linux/vmhgfs/link.c +++ b/open-vm-tools/modules/linux/vmhgfs/link.c @@ -45,11 +45,20 @@ static int HgfsFollowlink(struct dentry *dentry, static int HgfsReadlink(struct dentry *dentry, char __user *buffer, int buflen); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) +static void HgfsPutlink(struct dentry *dentry, + struct nameidata *nd, + void *cookie); +#else +static void HgfsPutlink(struct dentry *dentry, + struct nameidata *nd); +#endif /* HGFS inode operations structure for symlinks. */ struct inode_operations HgfsLinkInodeOperations = { .follow_link = HgfsFollowlink, .readlink = HgfsReadlink, + .put_link = HgfsPutlink, }; /* @@ -111,14 +120,12 @@ HgfsFollowlink(struct dentry *dentry, // IN: Dentry containing link LOG(6, (KERN_DEBUG "VMware hgfs: HgfsFollowlink: got called " "on something that wasn't a symlink\n")); error = -EINVAL; + kfree(fileName); } else { - LOG(6, (KERN_DEBUG "VMware hgfs: %s: calling vfs_follow_link %s\n", + LOG(6, (KERN_DEBUG "VMware hgfs: %s: calling nd_set_link %s\n", __func__, fileName)); - error = vfs_follow_link(nd, fileName); - LOG(6, (KERN_DEBUG "VMware hgfs: %s: vfs_follow_link %s ret %d\n", - __func__, fileName, error)); + nd_set_link(nd, fileName); } - kfree(fileName); } out: @@ -186,3 +193,46 @@ HgfsReadlink(struct dentry *dentry, // IN: Dentry containing link } return error; } + + +/* + *---------------------------------------------------------------------- + * + * HgfsPutlink -- + * + * Modeled after page_put_link from a 2.6.9 kernel so it'll work + * across all kernel revisions we care about. + * + * Results: + * None + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) +static void +HgfsPutlink(struct dentry *dentry, // dentry + struct nameidata *nd, // lookup name information + void *cookie) // cookie +#else +static void +HgfsPutlink(struct dentry *dentry, // dentry + struct nameidata *nd) // lookup name information +#endif +{ + char *fileName = NULL; + + LOG(6, (KERN_DEBUG "VMware hgfs: %s: put for %s\n", + __func__, dentry->d_name.name)); + + fileName = nd_get_link(nd); + if (!IS_ERR(fileName)) { + LOG(6, (KERN_DEBUG "VMware hgfs: %s: putting %s\n", + __func__, fileName)); + kfree(fileName); + nd_set_link(nd, NULL); + } +} |