From d60874cd58fcb21372f2df698c20f8cf2f78fdcb Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 4 Oct 2016 14:40:45 +0200 Subject: [PATCH] vfs: add vfs_get_link() helper This helper is for filesystems that want to read the symlink and are better off with the get_link() interface (returning a char *) rather than the readlink() interface (copy into a userspace buffer). Also call the LSM hook for readlink (not get_link) since this is for symlink reading not following. Signed-off-by: Miklos Szeredi --- fs/namei.c | 25 +++++++++++++++++++++++++ include/linux/fs.h | 1 + 2 files changed, 26 insertions(+) diff --git a/fs/namei.c b/fs/namei.c index adb04146df09..8a2c2959da08 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -4677,6 +4677,31 @@ int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen) } EXPORT_SYMBOL(generic_readlink); +/** + * vfs_get_link - get symlink body + * @dentry: dentry on which to get symbolic link + * @done: caller needs to free returned data with this + * + * Calls security hook and i_op->get_link() on the supplied inode. + * + * It does not touch atime. That's up to the caller if necessary. + * + * Does not work on "special" symlinks like /proc/$$/fd/N + */ +const char *vfs_get_link(struct dentry *dentry, struct delayed_call *done) +{ + const char *res = ERR_PTR(-EINVAL); + struct inode *inode = d_inode(dentry); + + if (d_is_symlink(dentry)) { + res = ERR_PTR(security_inode_readlink(dentry)); + if (!res) + res = inode->i_op->get_link(dentry, inode, done); + } + return res; +} +EXPORT_SYMBOL(vfs_get_link); + /* get the link contents into pagecache */ const char *page_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *callback) diff --git a/include/linux/fs.h b/include/linux/fs.h index 901e25d495cc..bc8ac5108368 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2919,6 +2919,7 @@ extern int vfs_stat(const char __user *, struct kstat *); extern int vfs_lstat(const char __user *, struct kstat *); extern int vfs_fstat(unsigned int, struct kstat *); extern int vfs_fstatat(int , const char __user *, struct kstat *, int); +extern const char *vfs_get_link(struct dentry *, struct delayed_call *); extern int __generic_block_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, -- 2.20.1