summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVMware, Inc <>2013-09-17 20:32:40 -0700
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2013-09-22 22:19:59 -0700
commite55039cb8452777c2024ce3a13cd3439f36fd554 (patch)
tree106230286f48ba51e55dd9b0e59b748091cf21db
parent0d5581ae35aaca0a1e645d8ffccaae77c0e39d4a (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.c60
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);
+ }
+}