diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2010-06-06 21:51:16 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2010-08-09 16:48:12 -0400 |
commit | d0352d3ed722b134dacc21836c1763e7e3523662 (patch) | |
tree | 030c031e5defb8c496f1b4766056c26e5460558a /fs/hostfs | |
parent | c5322220eb91b9e56ac7b69eb690d9d20fac5725 (diff) |
hostfs: sanitize symlinks
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/hostfs')
-rw-r--r-- | fs/hostfs/hostfs_kern.c | 61 |
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 | ||
49 | static const struct inode_operations hostfs_iops; | 50 | static const struct inode_operations hostfs_iops; |
50 | static const struct inode_operations hostfs_dir_iops; | 51 | static const struct inode_operations hostfs_dir_iops; |
51 | static const struct address_space_operations hostfs_link_aops; | 52 | static const struct inode_operations hostfs_link_iops; |
52 | 53 | ||
53 | #ifndef MODULE | 54 | #ifndef MODULE |
54 | static int __init hostfs_args(char *options, int *add) | 55 | static 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 | ||
838 | int hostfs_link_readpage(struct file *file, struct page *page) | 838 | static 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 | |||
862 | static 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 | ||
862 | static const struct address_space_operations hostfs_link_aops = { | 869 | static 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 | ||
866 | static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent) | 875 | static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent) |