Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs fixes from Al Viro: "Several fixes for bugs caught while looking through f_pos (ab)users" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: aout32 coredump compat fix splice: don't pass the address of ->f_pos to methods mconsole: we'd better initialize pos before passing it to vfs_read()...
This commit is contained in:
commit
b8ff768b5a
|
@ -147,7 +147,7 @@ void mconsole_proc(struct mc_request *req)
|
|||
}
|
||||
|
||||
do {
|
||||
loff_t pos;
|
||||
loff_t pos = file->f_pos;
|
||||
mm_segment_t old_fs = get_fs();
|
||||
set_fs(KERNEL_DS);
|
||||
len = vfs_read(file, buf, PAGE_SIZE - 1, &pos);
|
||||
|
|
|
@ -192,7 +192,7 @@ static int aout_core_dump(long signr, struct pt_regs *regs, struct file *file,
|
|||
/* struct user */
|
||||
DUMP_WRITE(&dump, sizeof(dump));
|
||||
/* Now dump all of the user data. Include malloced stuff as well */
|
||||
DUMP_SEEK(PAGE_SIZE);
|
||||
DUMP_SEEK(PAGE_SIZE - sizeof(dump));
|
||||
/* now we start writing out the user space info */
|
||||
set_fs(USER_DS);
|
||||
/* Dump the data area */
|
||||
|
|
|
@ -131,6 +131,12 @@ extern struct dentry *__d_alloc(struct super_block *, const struct qstr *);
|
|||
*/
|
||||
extern ssize_t __kernel_write(struct file *, const char *, size_t, loff_t *);
|
||||
|
||||
/*
|
||||
* splice.c
|
||||
*/
|
||||
extern long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
|
||||
loff_t *opos, size_t len, unsigned int flags);
|
||||
|
||||
/*
|
||||
* pipe.c
|
||||
*/
|
||||
|
|
|
@ -1064,6 +1064,7 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
|
|||
struct fd in, out;
|
||||
struct inode *in_inode, *out_inode;
|
||||
loff_t pos;
|
||||
loff_t out_pos;
|
||||
ssize_t retval;
|
||||
int fl;
|
||||
|
||||
|
@ -1077,12 +1078,14 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
|
|||
if (!(in.file->f_mode & FMODE_READ))
|
||||
goto fput_in;
|
||||
retval = -ESPIPE;
|
||||
if (!ppos)
|
||||
ppos = &in.file->f_pos;
|
||||
else
|
||||
if (!ppos) {
|
||||
pos = in.file->f_pos;
|
||||
} else {
|
||||
pos = *ppos;
|
||||
if (!(in.file->f_mode & FMODE_PREAD))
|
||||
goto fput_in;
|
||||
retval = rw_verify_area(READ, in.file, ppos, count);
|
||||
}
|
||||
retval = rw_verify_area(READ, in.file, &pos, count);
|
||||
if (retval < 0)
|
||||
goto fput_in;
|
||||
count = retval;
|
||||
|
@ -1099,7 +1102,8 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
|
|||
retval = -EINVAL;
|
||||
in_inode = file_inode(in.file);
|
||||
out_inode = file_inode(out.file);
|
||||
retval = rw_verify_area(WRITE, out.file, &out.file->f_pos, count);
|
||||
out_pos = out.file->f_pos;
|
||||
retval = rw_verify_area(WRITE, out.file, &out_pos, count);
|
||||
if (retval < 0)
|
||||
goto fput_out;
|
||||
count = retval;
|
||||
|
@ -1107,7 +1111,6 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
|
|||
if (!max)
|
||||
max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes);
|
||||
|
||||
pos = *ppos;
|
||||
if (unlikely(pos + count > max)) {
|
||||
retval = -EOVERFLOW;
|
||||
if (pos >= max)
|
||||
|
@ -1126,18 +1129,23 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
|
|||
if (in.file->f_flags & O_NONBLOCK)
|
||||
fl = SPLICE_F_NONBLOCK;
|
||||
#endif
|
||||
retval = do_splice_direct(in.file, ppos, out.file, count, fl);
|
||||
retval = do_splice_direct(in.file, &pos, out.file, &out_pos, count, fl);
|
||||
|
||||
if (retval > 0) {
|
||||
add_rchar(current, retval);
|
||||
add_wchar(current, retval);
|
||||
fsnotify_access(in.file);
|
||||
fsnotify_modify(out.file);
|
||||
out.file->f_pos = out_pos;
|
||||
if (ppos)
|
||||
*ppos = pos;
|
||||
else
|
||||
in.file->f_pos = pos;
|
||||
}
|
||||
|
||||
inc_syscr(current);
|
||||
inc_syscw(current);
|
||||
if (*ppos > max)
|
||||
if (pos > max)
|
||||
retval = -EOVERFLOW;
|
||||
|
||||
fput_out:
|
||||
|
|
31
fs/splice.c
31
fs/splice.c
|
@ -1274,7 +1274,7 @@ static int direct_splice_actor(struct pipe_inode_info *pipe,
|
|||
{
|
||||
struct file *file = sd->u.file;
|
||||
|
||||
return do_splice_from(pipe, file, &file->f_pos, sd->total_len,
|
||||
return do_splice_from(pipe, file, sd->opos, sd->total_len,
|
||||
sd->flags);
|
||||
}
|
||||
|
||||
|
@ -1294,7 +1294,7 @@ static int direct_splice_actor(struct pipe_inode_info *pipe,
|
|||
*
|
||||
*/
|
||||
long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
|
||||
size_t len, unsigned int flags)
|
||||
loff_t *opos, size_t len, unsigned int flags)
|
||||
{
|
||||
struct splice_desc sd = {
|
||||
.len = len,
|
||||
|
@ -1302,6 +1302,7 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
|
|||
.flags = flags,
|
||||
.pos = *ppos,
|
||||
.u.file = out,
|
||||
.opos = opos,
|
||||
};
|
||||
long ret;
|
||||
|
||||
|
@ -1325,7 +1326,7 @@ static long do_splice(struct file *in, loff_t __user *off_in,
|
|||
{
|
||||
struct pipe_inode_info *ipipe;
|
||||
struct pipe_inode_info *opipe;
|
||||
loff_t offset, *off;
|
||||
loff_t offset;
|
||||
long ret;
|
||||
|
||||
ipipe = get_pipe_info(in);
|
||||
|
@ -1356,13 +1357,15 @@ static long do_splice(struct file *in, loff_t __user *off_in,
|
|||
return -EINVAL;
|
||||
if (copy_from_user(&offset, off_out, sizeof(loff_t)))
|
||||
return -EFAULT;
|
||||
off = &offset;
|
||||
} else
|
||||
off = &out->f_pos;
|
||||
} else {
|
||||
offset = out->f_pos;
|
||||
}
|
||||
|
||||
ret = do_splice_from(ipipe, out, off, len, flags);
|
||||
ret = do_splice_from(ipipe, out, &offset, len, flags);
|
||||
|
||||
if (off_out && copy_to_user(off_out, off, sizeof(loff_t)))
|
||||
if (!off_out)
|
||||
out->f_pos = offset;
|
||||
else if (copy_to_user(off_out, &offset, sizeof(loff_t)))
|
||||
ret = -EFAULT;
|
||||
|
||||
return ret;
|
||||
|
@ -1376,13 +1379,15 @@ static long do_splice(struct file *in, loff_t __user *off_in,
|
|||
return -EINVAL;
|
||||
if (copy_from_user(&offset, off_in, sizeof(loff_t)))
|
||||
return -EFAULT;
|
||||
off = &offset;
|
||||
} else
|
||||
off = &in->f_pos;
|
||||
} else {
|
||||
offset = in->f_pos;
|
||||
}
|
||||
|
||||
ret = do_splice_to(in, off, opipe, len, flags);
|
||||
ret = do_splice_to(in, &offset, opipe, len, flags);
|
||||
|
||||
if (off_in && copy_to_user(off_in, off, sizeof(loff_t)))
|
||||
if (!off_in)
|
||||
in->f_pos = offset;
|
||||
else if (copy_to_user(off_in, &offset, sizeof(loff_t)))
|
||||
ret = -EFAULT;
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -2414,8 +2414,6 @@ extern ssize_t generic_file_splice_write(struct pipe_inode_info *,
|
|||
struct file *, loff_t *, size_t, unsigned int);
|
||||
extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe,
|
||||
struct file *out, loff_t *, size_t len, unsigned int flags);
|
||||
extern long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
|
||||
size_t len, unsigned int flags);
|
||||
|
||||
extern void
|
||||
file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping);
|
||||
|
|
|
@ -35,6 +35,7 @@ struct splice_desc {
|
|||
void *data; /* cookie */
|
||||
} u;
|
||||
loff_t pos; /* file position */
|
||||
loff_t *opos; /* sendfile: output position */
|
||||
size_t num_spliced; /* number of bytes already spliced */
|
||||
bool need_wakeup; /* need to wake up writer */
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue