Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d0352d3e authored by Al Viro's avatar Al Viro
Browse files

hostfs: sanitize symlinks



Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent c5322220
Loading
Loading
Loading
Loading
+35 −26
Original line number Original line Diff line number Diff line
@@ -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;


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)


	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 = {
	.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);
	kfree(name);
	if (err == PAGE_CACHE_SIZE)
				err = -E2BIG;
				err = -E2BIG;
	else if (err > 0) {
			kfree(path);
		flush_dcache_page(page);
		SetPageUptodate(page);
		if (PageError(page)) ClearPageError(page);
		err = 0;
		}
		}
	kunmap(page);
		if (err < 0) {
	unlock_page(page);
			__putname(link);
	return err;
			link = ERR_PTR(err);
		}
	} else {
		link = ERR_PTR(-ENOMEM);
	}

	nd_set_link(nd, link);
	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)