aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2010-06-06 21:51:16 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2010-08-09 16:48:12 -0400
commitd0352d3ed722b134dacc21836c1763e7e3523662 (patch)
tree030c031e5defb8c496f1b4766056c26e5460558a /fs
parentc5322220eb91b9e56ac7b69eb690d9d20fac5725 (diff)
hostfs: sanitize symlinks
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r--fs/hostfs/hostfs_kern.c61
1 files changed, 35 insertions, 26 deletions
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index 3841fb1ca5a2..10bb71b1548b 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -14,6 +14,7 @@
14#include <linux/slab.h> 14#include <linux/slab.h>
15#include <linux/seq_file.h> 15#include <linux/seq_file.h>
16#include <linux/mount.h> 16#include <linux/mount.h>
17#include <linux/namei.h>
17#include "hostfs.h" 18#include "hostfs.h"
18#include "init.h" 19#include "init.h"
19#include "kern.h" 20#include "kern.h"
@@ -48,7 +49,7 @@ static int append = 0;
48 49
49static const struct inode_operations hostfs_iops; 50static const struct inode_operations hostfs_iops;
50static const struct inode_operations hostfs_dir_iops; 51static const struct inode_operations hostfs_dir_iops;
51static const struct address_space_operations hostfs_link_aops; 52static const struct inode_operations hostfs_link_iops;
52 53
53#ifndef MODULE 54#ifndef MODULE
54static int __init hostfs_args(char *options, int *add) 55static int __init hostfs_args(char *options, int *add)
@@ -471,8 +472,7 @@ static int read_name(struct inode *ino, char *name)
471 472
472 switch (st.mode & S_IFMT) { 473 switch (st.mode & S_IFMT) {
473 case S_IFLNK: 474 case S_IFLNK:
474 ino->i_op = &page_symlink_inode_operations; 475 ino->i_op = &hostfs_link_iops;
475 ino->i_mapping->a_ops = &hostfs_link_aops;
476 break; 476 break;
477 case S_IFDIR: 477 case S_IFDIR:
478 ino->i_op = &hostfs_dir_iops; 478 ino->i_op = &hostfs_dir_iops;
@@ -835,32 +835,41 @@ static const struct inode_operations hostfs_dir_iops = {
835 .setattr = hostfs_setattr, 835 .setattr = hostfs_setattr,
836}; 836};
837 837
838int hostfs_link_readpage(struct file *file, struct page *page) 838static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
839{ 839{
840 char *buffer, *name; 840 char *link = __getname();
841 int err; 841 if (link) {
842 842 char *path = dentry_name(dentry);
843 buffer = kmap(page); 843 int err = -ENOMEM;
844 name = inode_name(page->mapping->host); 844 if (path) {
845 if (name == NULL) 845 int err = hostfs_do_readlink(path, link, PATH_MAX);
846 return -ENOMEM; 846 if (err == PATH_MAX)
847 err = hostfs_do_readlink(name, buffer, PAGE_CACHE_SIZE); 847 err = -E2BIG;
848 kfree(name); 848 kfree(path);
849 if (err == PAGE_CACHE_SIZE) 849 }
850 err = -E2BIG; 850 if (err < 0) {
851 else if (err > 0) { 851 __putname(link);
852 flush_dcache_page(page); 852 link = ERR_PTR(err);
853 SetPageUptodate(page); 853 }
854 if (PageError(page)) ClearPageError(page); 854 } else {
855 err = 0; 855 link = ERR_PTR(-ENOMEM);
856 } 856 }
857 kunmap(page); 857
858 unlock_page(page); 858 nd_set_link(nd, link);
859 return err; 859 return NULL;
860}
861
862static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
863{
864 char *s = nd_get_link(nd);
865 if (!IS_ERR(s))
866 __putname(s);
860} 867}
861 868
862static const struct address_space_operations hostfs_link_aops = { 869static const struct inode_operations hostfs_link_iops = {
863 .readpage = hostfs_link_readpage, 870 .readlink = generic_readlink,
871 .follow_link = hostfs_follow_link,
872 .put_link = hostfs_put_link,
864}; 873};
865 874
866static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent) 875static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)