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

Commit 1d3d752b authored by Miklos Szeredi's avatar Miklos Szeredi Committed by Linus Torvalds
Browse files

[PATCH] fuse: clean up request size limit checking



Change the way a too large request is handled.  Until now in this case the
device read returned -EINVAL and the operation returned -EIO.

Make it more flexibible by not returning -EINVAL from the read, but restarting
it instead.

Also remove the fixed limit on setxattr data and let the filesystem provide as
large a read buffer as it needs to handle the extended attribute data.

The symbolic link length is already checked by VFS to be less than PATH_MAX,
so the extra check against FUSE_SYMLINK_MAX is not needed.

The check in fuse_create_open() against FUSE_NAME_MAX is not needed, since the
dentry has already been looked up, and hence the name already checked.

Signed-off-by: default avatarMiklos Szeredi <miklos@szeredi.hu>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 248d86e8
Loading
Loading
Loading
Loading
+16 −10
Original line number Diff line number Diff line
@@ -617,6 +617,7 @@ static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov,
	struct fuse_copy_state cs;
	unsigned reqsize;

 restart:
	spin_lock(&fuse_lock);
	fc = file->private_data;
	err = -EPERM;
@@ -632,20 +633,25 @@ static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov,

	req = list_entry(fc->pending.next, struct fuse_req, list);
	list_del_init(&req->list);
	spin_unlock(&fuse_lock);

	in = &req->in;
	reqsize = req->in.h.len;
	reqsize = in->h.len;
	/* If request is too large, reply with an error and restart the read */
	if (iov_length(iov, nr_segs) < reqsize) {
		req->out.h.error = -EIO;
		/* SETXATTR is special, since it may contain too large data */
		if (in->h.opcode == FUSE_SETXATTR)
			req->out.h.error = -E2BIG;
		request_end(fc, req);
		goto restart;
	}
	spin_unlock(&fuse_lock);
	fuse_copy_init(&cs, 1, req, iov, nr_segs);
	err = -EINVAL;
	if (iov_length(iov, nr_segs) >= reqsize) {
	err = fuse_copy_one(&cs, &in->h, sizeof(in->h));
	if (!err)
		err = fuse_copy_args(&cs, in->numargs, in->argpages,
				     (struct fuse_arg *) in->args, 0);
	}
	fuse_copy_finish(&cs);

	spin_lock(&fuse_lock);
	req->locked = 0;
	if (!err && req->interrupted)
+1 −13
Original line number Diff line number Diff line
@@ -236,10 +236,6 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
	if (fc->no_create)
		goto out;

	err = -ENAMETOOLONG;
	if (entry->d_name.len > FUSE_NAME_MAX)
		goto out;

	err = -EINTR;
	req = fuse_get_request(fc);
	if (!req)
@@ -413,12 +409,7 @@ static int fuse_symlink(struct inode *dir, struct dentry *entry,
{
	struct fuse_conn *fc = get_fuse_conn(dir);
	unsigned len = strlen(link) + 1;
	struct fuse_req *req;

	if (len > FUSE_SYMLINK_MAX)
		return -ENAMETOOLONG;

	req = fuse_get_request(fc);
	struct fuse_req *req = fuse_get_request(fc);
	if (!req)
		return -EINTR;

@@ -988,9 +979,6 @@ static int fuse_setxattr(struct dentry *entry, const char *name,
	struct fuse_setxattr_in inarg;
	int err;

	if (size > FUSE_XATTR_SIZE_MAX)
		return -E2BIG;

	if (fc->no_setxattr)
		return -EOPNOTSUPP;

+6 −3
Original line number Diff line number Diff line
@@ -21,6 +21,12 @@
/** If more requests are outstanding, then the operation will block */
#define FUSE_MAX_OUTSTANDING 10

/** Maximum size of data in a write request */
#define FUSE_MAX_WRITE 4096

/** It could be as large as PATH_MAX, but would that have any uses? */
#define FUSE_NAME_MAX 1024

/** If the FUSE_DEFAULT_PERMISSIONS flag is given, the filesystem
    module will check permissions based on the file mode.  Otherwise no
    permission checking is done in the kernel */
@@ -108,9 +114,6 @@ struct fuse_out {
	struct fuse_arg args[3];
};

struct fuse_req;
struct fuse_conn;

/**
 * A request to the client
 */
+1 −1
Original line number Diff line number Diff line
@@ -485,7 +485,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
	fc->max_read = d.max_read;
	if (fc->max_read / PAGE_CACHE_SIZE < fc->bdi.ra_pages)
		fc->bdi.ra_pages = fc->max_read / PAGE_CACHE_SIZE;
	fc->max_write = FUSE_MAX_IN / 2;
	fc->max_write = FUSE_MAX_WRITE;

	err = -ENOMEM;
	root = get_root_inode(sb, d.rootmode);
+2 −6
Original line number Diff line number Diff line
@@ -108,12 +108,8 @@ enum fuse_opcode {
	FUSE_CREATE        = 35
};

/* Conservative buffer size for the client */
#define FUSE_MAX_IN 8192

#define FUSE_NAME_MAX 1024
#define FUSE_SYMLINK_MAX 4096
#define FUSE_XATTR_SIZE_MAX 4096
/* The read buffer is required to be at least 8k, but may be much larger */
#define FUSE_MIN_READ_BUFFER 8192

struct fuse_entry_out {
	__u64	nodeid;		/* Inode ID */