Commit d0352d3e authored by Al Viro's avatar Al Viro

hostfs: sanitize symlinks

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent c5322220
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/namei.h>
#include "hostfs.h" #include "hostfs.h"
#include "init.h" #include "init.h"
#include "kern.h" #include "kern.h"
...@@ -48,7 +49,7 @@ static int append = 0; ...@@ -48,7 +49,7 @@ static int append = 0;
static const struct inode_operations hostfs_iops; static const struct inode_operations hostfs_iops;
static const struct inode_operations hostfs_dir_iops; static const struct inode_operations hostfs_dir_iops;
static const struct address_space_operations hostfs_link_aops; static const struct inode_operations hostfs_link_iops;
#ifndef MODULE #ifndef MODULE
static int __init hostfs_args(char *options, int *add) static int __init hostfs_args(char *options, int *add)
...@@ -471,8 +472,7 @@ static int read_name(struct inode *ino, char *name) ...@@ -471,8 +472,7 @@ static int read_name(struct inode *ino, char *name)
switch (st.mode & S_IFMT) { switch (st.mode & S_IFMT) {
case S_IFLNK: case S_IFLNK:
ino->i_op = &page_symlink_inode_operations; ino->i_op = &hostfs_link_iops;
ino->i_mapping->a_ops = &hostfs_link_aops;
break; break;
case S_IFDIR: case S_IFDIR:
ino->i_op = &hostfs_dir_iops; ino->i_op = &hostfs_dir_iops;
...@@ -835,32 +835,41 @@ static const struct inode_operations hostfs_dir_iops = { ...@@ -835,32 +835,41 @@ static const struct inode_operations hostfs_dir_iops = {
.setattr = hostfs_setattr, .setattr = hostfs_setattr,
}; };
int hostfs_link_readpage(struct file *file, struct page *page) static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
{ {
char *buffer, *name; char *link = __getname();
int err; if (link) {
char *path = dentry_name(dentry);
buffer = kmap(page); int err = -ENOMEM;
name = inode_name(page->mapping->host); if (path) {
if (name == NULL) int err = hostfs_do_readlink(path, link, PATH_MAX);
return -ENOMEM; if (err == PATH_MAX)
err = hostfs_do_readlink(name, buffer, PAGE_CACHE_SIZE); err = -E2BIG;
kfree(name); kfree(path);
if (err == PAGE_CACHE_SIZE) }
err = -E2BIG; if (err < 0) {
else if (err > 0) { __putname(link);
flush_dcache_page(page); link = ERR_PTR(err);
SetPageUptodate(page); }
if (PageError(page)) ClearPageError(page); } else {
err = 0; link = ERR_PTR(-ENOMEM);
} }
kunmap(page);
unlock_page(page); nd_set_link(nd, link);
return err; return NULL;
}
static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
{
char *s = nd_get_link(nd);
if (!IS_ERR(s))
__putname(s);
} }
static const struct address_space_operations hostfs_link_aops = { static const struct inode_operations hostfs_link_iops = {
.readpage = hostfs_link_readpage, .readlink = generic_readlink,
.follow_link = hostfs_follow_link,
.put_link = hostfs_put_link,
}; };
static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent) static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment