Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull vfs fixes from Al Viro:
 "Overlayfs fixes from Miklos, assorted fixes from me.

  Stable fodder of varying severity, all sat in -next for a while"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  ovl: ignore permissions on underlying lookup
  vfs: add lookup_hash() helper
  vfs: rename: check backing inode being equal
  vfs: add vfs_select_inode() helper
  get_rock_ridge_filename(): handle malformed NM entries
  ecryptfs: fix handling of directory opening
  atomic_open(): fix the handling of create_error
  fix the copy vs. map logics in blk_rq_map_user_iov()
  do_splice_to(): cap the size before passing to ->splice_read()
This commit is contained in:
Linus Torvalds 2016-05-14 11:59:43 -07:00
commit 6ba5b85fd4
11 changed files with 152 additions and 91 deletions

View File

@ -9,24 +9,6 @@
#include "blk.h" #include "blk.h"
static bool iovec_gap_to_prv(struct request_queue *q,
struct iovec *prv, struct iovec *cur)
{
unsigned long prev_end;
if (!queue_virt_boundary(q))
return false;
if (prv->iov_base == NULL && prv->iov_len == 0)
/* prv is not set - don't check */
return false;
prev_end = (unsigned long)(prv->iov_base + prv->iov_len);
return (((unsigned long)cur->iov_base & queue_virt_boundary(q)) ||
prev_end & queue_virt_boundary(q));
}
int blk_rq_append_bio(struct request_queue *q, struct request *rq, int blk_rq_append_bio(struct request_queue *q, struct request *rq,
struct bio *bio) struct bio *bio)
{ {
@ -125,31 +107,18 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
struct rq_map_data *map_data, struct rq_map_data *map_data,
const struct iov_iter *iter, gfp_t gfp_mask) const struct iov_iter *iter, gfp_t gfp_mask)
{ {
struct iovec iov, prv = {.iov_base = NULL, .iov_len = 0}; bool copy = false;
bool copy = (q->dma_pad_mask & iter->count) || map_data; unsigned long align = q->dma_pad_mask | queue_dma_alignment(q);
struct bio *bio = NULL; struct bio *bio = NULL;
struct iov_iter i; struct iov_iter i;
int ret; int ret;
if (!iter || !iter->count) if (map_data)
return -EINVAL;
iov_for_each(iov, i, *iter) {
unsigned long uaddr = (unsigned long) iov.iov_base;
if (!iov.iov_len)
return -EINVAL;
/*
* Keep going so we check length of all segments
*/
if ((uaddr & queue_dma_alignment(q)) ||
iovec_gap_to_prv(q, &prv, &iov))
copy = true; copy = true;
else if (iov_iter_alignment(iter) & align)
prv.iov_base = iov.iov_base; copy = true;
prv.iov_len = iov.iov_len; else if (queue_virt_boundary(q))
} copy = queue_virt_boundary(q) & iov_iter_gap_alignment(iter);
i = *iter; i = *iter;
do { do {

View File

@ -112,7 +112,6 @@ static int ecryptfs_readdir(struct file *file, struct dir_context *ctx)
.sb = inode->i_sb, .sb = inode->i_sb,
}; };
lower_file = ecryptfs_file_to_lower(file); lower_file = ecryptfs_file_to_lower(file);
lower_file->f_pos = ctx->pos;
rc = iterate_dir(lower_file, &buf.ctx); rc = iterate_dir(lower_file, &buf.ctx);
ctx->pos = buf.ctx.pos; ctx->pos = buf.ctx.pos;
if (rc < 0) if (rc < 0)
@ -223,14 +222,6 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
} }
ecryptfs_set_file_lower( ecryptfs_set_file_lower(
file, ecryptfs_inode_to_private(inode)->lower_file); file, ecryptfs_inode_to_private(inode)->lower_file);
if (d_is_dir(ecryptfs_dentry)) {
ecryptfs_printk(KERN_DEBUG, "This is a directory\n");
mutex_lock(&crypt_stat->cs_mutex);
crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
mutex_unlock(&crypt_stat->cs_mutex);
rc = 0;
goto out;
}
rc = read_or_initialize_metadata(ecryptfs_dentry); rc = read_or_initialize_metadata(ecryptfs_dentry);
if (rc) if (rc)
goto out_put; goto out_put;
@ -247,6 +238,45 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
return rc; return rc;
} }
/**
* ecryptfs_dir_open
* @inode: inode speciying file to open
* @file: Structure to return filled in
*
* Opens the file specified by inode.
*
* Returns zero on success; non-zero otherwise
*/
static int ecryptfs_dir_open(struct inode *inode, struct file *file)
{
struct dentry *ecryptfs_dentry = file->f_path.dentry;
/* Private value of ecryptfs_dentry allocated in
* ecryptfs_lookup() */
struct ecryptfs_file_info *file_info;
struct file *lower_file;
/* Released in ecryptfs_release or end of function if failure */
file_info = kmem_cache_zalloc(ecryptfs_file_info_cache, GFP_KERNEL);
ecryptfs_set_file_private(file, file_info);
if (unlikely(!file_info)) {
ecryptfs_printk(KERN_ERR,
"Error attempting to allocate memory\n");
return -ENOMEM;
}
lower_file = dentry_open(ecryptfs_dentry_to_lower_path(ecryptfs_dentry),
file->f_flags, current_cred());
if (IS_ERR(lower_file)) {
printk(KERN_ERR "%s: Error attempting to initialize "
"the lower file for the dentry with name "
"[%pd]; rc = [%ld]\n", __func__,
ecryptfs_dentry, PTR_ERR(lower_file));
kmem_cache_free(ecryptfs_file_info_cache, file_info);
return PTR_ERR(lower_file);
}
ecryptfs_set_file_lower(file, lower_file);
return 0;
}
static int ecryptfs_flush(struct file *file, fl_owner_t td) static int ecryptfs_flush(struct file *file, fl_owner_t td)
{ {
struct file *lower_file = ecryptfs_file_to_lower(file); struct file *lower_file = ecryptfs_file_to_lower(file);
@ -267,6 +297,19 @@ static int ecryptfs_release(struct inode *inode, struct file *file)
return 0; return 0;
} }
static int ecryptfs_dir_release(struct inode *inode, struct file *file)
{
fput(ecryptfs_file_to_lower(file));
kmem_cache_free(ecryptfs_file_info_cache,
ecryptfs_file_to_private(file));
return 0;
}
static loff_t ecryptfs_dir_llseek(struct file *file, loff_t offset, int whence)
{
return vfs_llseek(ecryptfs_file_to_lower(file), offset, whence);
}
static int static int
ecryptfs_fsync(struct file *file, loff_t start, loff_t end, int datasync) ecryptfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
{ {
@ -346,20 +389,16 @@ const struct file_operations ecryptfs_dir_fops = {
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
.compat_ioctl = ecryptfs_compat_ioctl, .compat_ioctl = ecryptfs_compat_ioctl,
#endif #endif
.open = ecryptfs_open, .open = ecryptfs_dir_open,
.flush = ecryptfs_flush, .release = ecryptfs_dir_release,
.release = ecryptfs_release,
.fsync = ecryptfs_fsync, .fsync = ecryptfs_fsync,
.fasync = ecryptfs_fasync, .llseek = ecryptfs_dir_llseek,
.splice_read = generic_file_splice_read,
.llseek = default_llseek,
}; };
const struct file_operations ecryptfs_main_fops = { const struct file_operations ecryptfs_main_fops = {
.llseek = generic_file_llseek, .llseek = generic_file_llseek,
.read_iter = ecryptfs_read_update_atime, .read_iter = ecryptfs_read_update_atime,
.write_iter = generic_file_write_iter, .write_iter = generic_file_write_iter,
.iterate = ecryptfs_readdir,
.unlocked_ioctl = ecryptfs_unlocked_ioctl, .unlocked_ioctl = ecryptfs_unlocked_ioctl,
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
.compat_ioctl = ecryptfs_compat_ioctl, .compat_ioctl = ecryptfs_compat_ioctl,

View File

@ -203,6 +203,8 @@ int get_rock_ridge_filename(struct iso_directory_record *de,
int retnamlen = 0; int retnamlen = 0;
int truncate = 0; int truncate = 0;
int ret = 0; int ret = 0;
char *p;
int len;
if (!ISOFS_SB(inode->i_sb)->s_rock) if (!ISOFS_SB(inode->i_sb)->s_rock)
return 0; return 0;
@ -267,12 +269,17 @@ int get_rock_ridge_filename(struct iso_directory_record *de,
rr->u.NM.flags); rr->u.NM.flags);
break; break;
} }
if ((strlen(retname) + rr->len - 5) >= 254) { len = rr->len - 5;
if (retnamlen + len >= 254) {
truncate = 1; truncate = 1;
break; break;
} }
strncat(retname, rr->u.NM.name, rr->len - 5); p = memchr(rr->u.NM.name, '\0', len);
retnamlen += rr->len - 5; if (unlikely(p))
len = p - rr->u.NM.name;
memcpy(retname + retnamlen, rr->u.NM.name, len);
retnamlen += len;
retname[retnamlen] = '\0';
break; break;
case SIG('R', 'E'): case SIG('R', 'E'):
kfree(rs.buffer); kfree(rs.buffer);

View File

@ -2266,6 +2266,33 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
} }
EXPORT_SYMBOL(vfs_path_lookup); EXPORT_SYMBOL(vfs_path_lookup);
/**
* lookup_hash - lookup single pathname component on already hashed name
* @name: name and hash to lookup
* @base: base directory to lookup from
*
* The name must have been verified and hashed (see lookup_one_len()). Using
* this after just full_name_hash() is unsafe.
*
* This function also doesn't check for search permission on base directory.
*
* Use lookup_one_len_unlocked() instead, unless you really know what you are
* doing.
*
* Do not hold i_mutex; this helper takes i_mutex if necessary.
*/
struct dentry *lookup_hash(const struct qstr *name, struct dentry *base)
{
struct dentry *ret;
ret = lookup_dcache(name, base, 0);
if (!ret)
ret = lookup_slow(name, base, 0);
return ret;
}
EXPORT_SYMBOL(lookup_hash);
/** /**
* lookup_one_len - filesystem helper to lookup single pathname component * lookup_one_len - filesystem helper to lookup single pathname component
* @name: pathname component to lookup * @name: pathname component to lookup
@ -2337,7 +2364,6 @@ struct dentry *lookup_one_len_unlocked(const char *name,
struct qstr this; struct qstr this;
unsigned int c; unsigned int c;
int err; int err;
struct dentry *ret;
this.name = name; this.name = name;
this.len = len; this.len = len;
@ -2369,10 +2395,7 @@ struct dentry *lookup_one_len_unlocked(const char *name,
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);
ret = lookup_dcache(&this, base, 0); return lookup_hash(&this, base);
if (!ret)
ret = lookup_slow(&this, base, 0);
return ret;
} }
EXPORT_SYMBOL(lookup_one_len_unlocked); EXPORT_SYMBOL(lookup_one_len_unlocked);
@ -2942,22 +2965,10 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
dentry = lookup_real(dir, dentry, nd->flags); dentry = lookup_real(dir, dentry, nd->flags);
if (IS_ERR(dentry)) if (IS_ERR(dentry))
return PTR_ERR(dentry); return PTR_ERR(dentry);
}
if (create_error) { if (create_error && !dentry->d_inode) {
int open_flag = op->open_flag;
error = create_error; error = create_error;
if ((open_flag & O_EXCL)) {
if (!dentry->d_inode)
goto out; goto out;
} else if (!dentry->d_inode) {
goto out;
} else if ((open_flag & O_TRUNC) &&
d_is_reg(dentry)) {
goto out;
}
/* will fail later, go on to get the right error */
}
} }
looked_up: looked_up:
path->dentry = dentry; path->dentry = dentry;
@ -4213,7 +4224,11 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
bool new_is_dir = false; bool new_is_dir = false;
unsigned max_links = new_dir->i_sb->s_max_links; unsigned max_links = new_dir->i_sb->s_max_links;
if (source == target) /*
* Check source == target.
* On overlayfs need to look at underlying inodes.
*/
if (vfs_select_inode(old_dentry, 0) == vfs_select_inode(new_dentry, 0))
return 0; return 0;
error = may_delete(old_dir, old_dentry, is_dir); error = may_delete(old_dir, old_dentry, is_dir);

View File

@ -840,16 +840,12 @@ EXPORT_SYMBOL(file_path);
int vfs_open(const struct path *path, struct file *file, int vfs_open(const struct path *path, struct file *file,
const struct cred *cred) const struct cred *cred)
{ {
struct dentry *dentry = path->dentry; struct inode *inode = vfs_select_inode(path->dentry, file->f_flags);
struct inode *inode = dentry->d_inode;
file->f_path = *path;
if (dentry->d_flags & DCACHE_OP_SELECT_INODE) {
inode = dentry->d_op->d_select_inode(dentry, file->f_flags);
if (IS_ERR(inode)) if (IS_ERR(inode))
return PTR_ERR(inode); return PTR_ERR(inode);
}
file->f_path = *path;
return do_dentry_open(file, inode, NULL, cred); return do_dentry_open(file, inode, NULL, cred);
} }

View File

@ -411,9 +411,7 @@ static inline struct dentry *ovl_lookup_real(struct dentry *dir,
{ {
struct dentry *dentry; struct dentry *dentry;
inode_lock(dir->d_inode); dentry = lookup_hash(name, dir);
dentry = lookup_one_len(name->name, dir, name->len);
inode_unlock(dir->d_inode);
if (IS_ERR(dentry)) { if (IS_ERR(dentry)) {
if (PTR_ERR(dentry) == -ENOENT) if (PTR_ERR(dentry) == -ENOENT)

View File

@ -1143,6 +1143,9 @@ static long do_splice_to(struct file *in, loff_t *ppos,
if (unlikely(ret < 0)) if (unlikely(ret < 0))
return ret; return ret;
if (unlikely(len > MAX_RW_COUNT))
len = MAX_RW_COUNT;
if (in->f_op->splice_read) if (in->f_op->splice_read)
splice_read = in->f_op->splice_read; splice_read = in->f_op->splice_read;
else else

View File

@ -565,4 +565,16 @@ static inline struct dentry *d_real(struct dentry *dentry)
return dentry; return dentry;
} }
static inline struct inode *vfs_select_inode(struct dentry *dentry,
unsigned open_flags)
{
struct inode *inode = d_inode(dentry);
if (inode && unlikely(dentry->d_flags & DCACHE_OP_SELECT_INODE))
inode = dentry->d_op->d_select_inode(dentry, open_flags);
return inode;
}
#endif /* __LINUX_DCACHE_H */ #endif /* __LINUX_DCACHE_H */

View File

@ -79,6 +79,8 @@ extern int kern_path_mountpoint(int, const char *, struct path *, unsigned int);
extern struct dentry *lookup_one_len(const char *, struct dentry *, int); extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
extern struct dentry *lookup_one_len_unlocked(const char *, struct dentry *, int); extern struct dentry *lookup_one_len_unlocked(const char *, struct dentry *, int);
struct qstr;
extern struct dentry *lookup_hash(const struct qstr *, struct dentry *);
extern int follow_down_one(struct path *); extern int follow_down_one(struct path *);
extern int follow_down(struct path *); extern int follow_down(struct path *);

View File

@ -87,6 +87,7 @@ size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i);
size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i); size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i);
size_t iov_iter_zero(size_t bytes, struct iov_iter *); size_t iov_iter_zero(size_t bytes, struct iov_iter *);
unsigned long iov_iter_alignment(const struct iov_iter *i); unsigned long iov_iter_alignment(const struct iov_iter *i);
unsigned long iov_iter_gap_alignment(const struct iov_iter *i);
void iov_iter_init(struct iov_iter *i, int direction, const struct iovec *iov, void iov_iter_init(struct iov_iter *i, int direction, const struct iovec *iov,
unsigned long nr_segs, size_t count); unsigned long nr_segs, size_t count);
void iov_iter_kvec(struct iov_iter *i, int direction, const struct kvec *kvec, void iov_iter_kvec(struct iov_iter *i, int direction, const struct kvec *kvec,

View File

@ -569,6 +569,25 @@ unsigned long iov_iter_alignment(const struct iov_iter *i)
} }
EXPORT_SYMBOL(iov_iter_alignment); EXPORT_SYMBOL(iov_iter_alignment);
unsigned long iov_iter_gap_alignment(const struct iov_iter *i)
{
unsigned long res = 0;
size_t size = i->count;
if (!size)
return 0;
iterate_all_kinds(i, size, v,
(res |= (!res ? 0 : (unsigned long)v.iov_base) |
(size != v.iov_len ? size : 0), 0),
(res |= (!res ? 0 : (unsigned long)v.bv_offset) |
(size != v.bv_len ? size : 0)),
(res |= (!res ? 0 : (unsigned long)v.iov_base) |
(size != v.iov_len ? size : 0))
);
return res;
}
EXPORT_SYMBOL(iov_iter_gap_alignment);
ssize_t iov_iter_get_pages(struct iov_iter *i, ssize_t iov_iter_get_pages(struct iov_iter *i,
struct page **pages, size_t maxsize, unsigned maxpages, struct page **pages, size_t maxsize, unsigned maxpages,
size_t *start) size_t *start)