diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-06-22 14:42:20 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-06-22 14:42:20 -0400 |
commit | b8ff768b5ab9d17204c1a8b3647ee6db608f63ab (patch) | |
tree | 7be3d5a4ac5a8e3d68ab9259d69add29c2998a07 | |
parent | f71194a7d47c1da787555d27aac63973ca72323b (diff) | |
parent | 945fb136dfcb5291b4fb2abd4fd1edf790de44ff (diff) |
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()...
-rw-r--r-- | arch/um/drivers/mconsole_kern.c | 2 | ||||
-rw-r--r-- | arch/x86/ia32/ia32_aout.c | 2 | ||||
-rw-r--r-- | fs/internal.h | 6 | ||||
-rw-r--r-- | fs/read_write.c | 24 | ||||
-rw-r--r-- | fs/splice.c | 31 | ||||
-rw-r--r-- | include/linux/fs.h | 2 | ||||
-rw-r--r-- | include/linux/splice.h | 1 |
7 files changed, 43 insertions, 25 deletions
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index d7d21851e60c..3df3bd544492 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c | |||
@@ -147,7 +147,7 @@ void mconsole_proc(struct mc_request *req) | |||
147 | } | 147 | } |
148 | 148 | ||
149 | do { | 149 | do { |
150 | loff_t pos; | 150 | loff_t pos = file->f_pos; |
151 | mm_segment_t old_fs = get_fs(); | 151 | mm_segment_t old_fs = get_fs(); |
152 | set_fs(KERNEL_DS); | 152 | set_fs(KERNEL_DS); |
153 | len = vfs_read(file, buf, PAGE_SIZE - 1, &pos); | 153 | len = vfs_read(file, buf, PAGE_SIZE - 1, &pos); |
diff --git a/arch/x86/ia32/ia32_aout.c b/arch/x86/ia32/ia32_aout.c index 805078e08013..52ff81cce008 100644 --- a/arch/x86/ia32/ia32_aout.c +++ b/arch/x86/ia32/ia32_aout.c | |||
@@ -192,7 +192,7 @@ static int aout_core_dump(long signr, struct pt_regs *regs, struct file *file, | |||
192 | /* struct user */ | 192 | /* struct user */ |
193 | DUMP_WRITE(&dump, sizeof(dump)); | 193 | DUMP_WRITE(&dump, sizeof(dump)); |
194 | /* Now dump all of the user data. Include malloced stuff as well */ | 194 | /* Now dump all of the user data. Include malloced stuff as well */ |
195 | DUMP_SEEK(PAGE_SIZE); | 195 | DUMP_SEEK(PAGE_SIZE - sizeof(dump)); |
196 | /* now we start writing out the user space info */ | 196 | /* now we start writing out the user space info */ |
197 | set_fs(USER_DS); | 197 | set_fs(USER_DS); |
198 | /* Dump the data area */ | 198 | /* Dump the data area */ |
diff --git a/fs/internal.h b/fs/internal.h index eaa75f75b625..68121584ae37 100644 --- a/fs/internal.h +++ b/fs/internal.h | |||
@@ -132,6 +132,12 @@ extern struct dentry *__d_alloc(struct super_block *, const struct qstr *); | |||
132 | extern ssize_t __kernel_write(struct file *, const char *, size_t, loff_t *); | 132 | extern ssize_t __kernel_write(struct file *, const char *, size_t, loff_t *); |
133 | 133 | ||
134 | /* | 134 | /* |
135 | * splice.c | ||
136 | */ | ||
137 | extern long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, | ||
138 | loff_t *opos, size_t len, unsigned int flags); | ||
139 | |||
140 | /* | ||
135 | * pipe.c | 141 | * pipe.c |
136 | */ | 142 | */ |
137 | extern const struct file_operations pipefifo_fops; | 143 | extern const struct file_operations pipefifo_fops; |
diff --git a/fs/read_write.c b/fs/read_write.c index 03430008704e..2cefa417be34 100644 --- a/fs/read_write.c +++ b/fs/read_write.c | |||
@@ -1064,6 +1064,7 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, | |||
1064 | struct fd in, out; | 1064 | struct fd in, out; |
1065 | struct inode *in_inode, *out_inode; | 1065 | struct inode *in_inode, *out_inode; |
1066 | loff_t pos; | 1066 | loff_t pos; |
1067 | loff_t out_pos; | ||
1067 | ssize_t retval; | 1068 | ssize_t retval; |
1068 | int fl; | 1069 | int fl; |
1069 | 1070 | ||
@@ -1077,12 +1078,14 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, | |||
1077 | if (!(in.file->f_mode & FMODE_READ)) | 1078 | if (!(in.file->f_mode & FMODE_READ)) |
1078 | goto fput_in; | 1079 | goto fput_in; |
1079 | retval = -ESPIPE; | 1080 | retval = -ESPIPE; |
1080 | if (!ppos) | 1081 | if (!ppos) { |
1081 | ppos = &in.file->f_pos; | 1082 | pos = in.file->f_pos; |
1082 | else | 1083 | } else { |
1084 | pos = *ppos; | ||
1083 | if (!(in.file->f_mode & FMODE_PREAD)) | 1085 | if (!(in.file->f_mode & FMODE_PREAD)) |
1084 | goto fput_in; | 1086 | goto fput_in; |
1085 | retval = rw_verify_area(READ, in.file, ppos, count); | 1087 | } |
1088 | retval = rw_verify_area(READ, in.file, &pos, count); | ||
1086 | if (retval < 0) | 1089 | if (retval < 0) |
1087 | goto fput_in; | 1090 | goto fput_in; |
1088 | count = retval; | 1091 | count = retval; |
@@ -1099,7 +1102,8 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, | |||
1099 | retval = -EINVAL; | 1102 | retval = -EINVAL; |
1100 | in_inode = file_inode(in.file); | 1103 | in_inode = file_inode(in.file); |
1101 | out_inode = file_inode(out.file); | 1104 | out_inode = file_inode(out.file); |
1102 | retval = rw_verify_area(WRITE, out.file, &out.file->f_pos, count); | 1105 | out_pos = out.file->f_pos; |
1106 | retval = rw_verify_area(WRITE, out.file, &out_pos, count); | ||
1103 | if (retval < 0) | 1107 | if (retval < 0) |
1104 | goto fput_out; | 1108 | goto fput_out; |
1105 | count = retval; | 1109 | count = retval; |
@@ -1107,7 +1111,6 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, | |||
1107 | if (!max) | 1111 | if (!max) |
1108 | max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes); | 1112 | max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes); |
1109 | 1113 | ||
1110 | pos = *ppos; | ||
1111 | if (unlikely(pos + count > max)) { | 1114 | if (unlikely(pos + count > max)) { |
1112 | retval = -EOVERFLOW; | 1115 | retval = -EOVERFLOW; |
1113 | if (pos >= max) | 1116 | if (pos >= max) |
@@ -1126,18 +1129,23 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, | |||
1126 | if (in.file->f_flags & O_NONBLOCK) | 1129 | if (in.file->f_flags & O_NONBLOCK) |
1127 | fl = SPLICE_F_NONBLOCK; | 1130 | fl = SPLICE_F_NONBLOCK; |
1128 | #endif | 1131 | #endif |
1129 | retval = do_splice_direct(in.file, ppos, out.file, count, fl); | 1132 | retval = do_splice_direct(in.file, &pos, out.file, &out_pos, count, fl); |
1130 | 1133 | ||
1131 | if (retval > 0) { | 1134 | if (retval > 0) { |
1132 | add_rchar(current, retval); | 1135 | add_rchar(current, retval); |
1133 | add_wchar(current, retval); | 1136 | add_wchar(current, retval); |
1134 | fsnotify_access(in.file); | 1137 | fsnotify_access(in.file); |
1135 | fsnotify_modify(out.file); | 1138 | fsnotify_modify(out.file); |
1139 | out.file->f_pos = out_pos; | ||
1140 | if (ppos) | ||
1141 | *ppos = pos; | ||
1142 | else | ||
1143 | in.file->f_pos = pos; | ||
1136 | } | 1144 | } |
1137 | 1145 | ||
1138 | inc_syscr(current); | 1146 | inc_syscr(current); |
1139 | inc_syscw(current); | 1147 | inc_syscw(current); |
1140 | if (*ppos > max) | 1148 | if (pos > max) |
1141 | retval = -EOVERFLOW; | 1149 | retval = -EOVERFLOW; |
1142 | 1150 | ||
1143 | fput_out: | 1151 | fput_out: |
diff --git a/fs/splice.c b/fs/splice.c index e6b25598c8c4..9eca476227d5 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
@@ -1274,7 +1274,7 @@ static int direct_splice_actor(struct pipe_inode_info *pipe, | |||
1274 | { | 1274 | { |
1275 | struct file *file = sd->u.file; | 1275 | struct file *file = sd->u.file; |
1276 | 1276 | ||
1277 | return do_splice_from(pipe, file, &file->f_pos, sd->total_len, | 1277 | return do_splice_from(pipe, file, sd->opos, sd->total_len, |
1278 | sd->flags); | 1278 | sd->flags); |
1279 | } | 1279 | } |
1280 | 1280 | ||
@@ -1294,7 +1294,7 @@ static int direct_splice_actor(struct pipe_inode_info *pipe, | |||
1294 | * | 1294 | * |
1295 | */ | 1295 | */ |
1296 | long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, | 1296 | long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, |
1297 | size_t len, unsigned int flags) | 1297 | loff_t *opos, size_t len, unsigned int flags) |
1298 | { | 1298 | { |
1299 | struct splice_desc sd = { | 1299 | struct splice_desc sd = { |
1300 | .len = len, | 1300 | .len = len, |
@@ -1302,6 +1302,7 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, | |||
1302 | .flags = flags, | 1302 | .flags = flags, |
1303 | .pos = *ppos, | 1303 | .pos = *ppos, |
1304 | .u.file = out, | 1304 | .u.file = out, |
1305 | .opos = opos, | ||
1305 | }; | 1306 | }; |
1306 | long ret; | 1307 | long ret; |
1307 | 1308 | ||
@@ -1325,7 +1326,7 @@ static long do_splice(struct file *in, loff_t __user *off_in, | |||
1325 | { | 1326 | { |
1326 | struct pipe_inode_info *ipipe; | 1327 | struct pipe_inode_info *ipipe; |
1327 | struct pipe_inode_info *opipe; | 1328 | struct pipe_inode_info *opipe; |
1328 | loff_t offset, *off; | 1329 | loff_t offset; |
1329 | long ret; | 1330 | long ret; |
1330 | 1331 | ||
1331 | ipipe = get_pipe_info(in); | 1332 | ipipe = get_pipe_info(in); |
@@ -1356,13 +1357,15 @@ static long do_splice(struct file *in, loff_t __user *off_in, | |||
1356 | return -EINVAL; | 1357 | return -EINVAL; |
1357 | if (copy_from_user(&offset, off_out, sizeof(loff_t))) | 1358 | if (copy_from_user(&offset, off_out, sizeof(loff_t))) |
1358 | return -EFAULT; | 1359 | return -EFAULT; |
1359 | off = &offset; | 1360 | } else { |
1360 | } else | 1361 | offset = out->f_pos; |
1361 | off = &out->f_pos; | 1362 | } |
1362 | 1363 | ||
1363 | ret = do_splice_from(ipipe, out, off, len, flags); | 1364 | ret = do_splice_from(ipipe, out, &offset, len, flags); |
1364 | 1365 | ||
1365 | if (off_out && copy_to_user(off_out, off, sizeof(loff_t))) | 1366 | if (!off_out) |
1367 | out->f_pos = offset; | ||
1368 | else if (copy_to_user(off_out, &offset, sizeof(loff_t))) | ||
1366 | ret = -EFAULT; | 1369 | ret = -EFAULT; |
1367 | 1370 | ||
1368 | return ret; | 1371 | return ret; |
@@ -1376,13 +1379,15 @@ static long do_splice(struct file *in, loff_t __user *off_in, | |||
1376 | return -EINVAL; | 1379 | return -EINVAL; |
1377 | if (copy_from_user(&offset, off_in, sizeof(loff_t))) | 1380 | if (copy_from_user(&offset, off_in, sizeof(loff_t))) |
1378 | return -EFAULT; | 1381 | return -EFAULT; |
1379 | off = &offset; | 1382 | } else { |
1380 | } else | 1383 | offset = in->f_pos; |
1381 | off = &in->f_pos; | 1384 | } |
1382 | 1385 | ||
1383 | ret = do_splice_to(in, off, opipe, len, flags); | 1386 | ret = do_splice_to(in, &offset, opipe, len, flags); |
1384 | 1387 | ||
1385 | if (off_in && copy_to_user(off_in, off, sizeof(loff_t))) | 1388 | if (!off_in) |
1389 | in->f_pos = offset; | ||
1390 | else if (copy_to_user(off_in, &offset, sizeof(loff_t))) | ||
1386 | ret = -EFAULT; | 1391 | ret = -EFAULT; |
1387 | 1392 | ||
1388 | return ret; | 1393 | return ret; |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 43db02e9c9fa..65c2be22b601 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -2414,8 +2414,6 @@ extern ssize_t generic_file_splice_write(struct pipe_inode_info *, | |||
2414 | struct file *, loff_t *, size_t, unsigned int); | 2414 | struct file *, loff_t *, size_t, unsigned int); |
2415 | extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, | 2415 | extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, |
2416 | struct file *out, loff_t *, size_t len, unsigned int flags); | 2416 | struct file *out, loff_t *, size_t len, unsigned int flags); |
2417 | extern long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, | ||
2418 | size_t len, unsigned int flags); | ||
2419 | 2417 | ||
2420 | extern void | 2418 | extern void |
2421 | file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping); | 2419 | file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping); |
diff --git a/include/linux/splice.h b/include/linux/splice.h index 09a545a7dfa3..74575cbf2d6f 100644 --- a/include/linux/splice.h +++ b/include/linux/splice.h | |||
@@ -35,6 +35,7 @@ struct splice_desc { | |||
35 | void *data; /* cookie */ | 35 | void *data; /* cookie */ |
36 | } u; | 36 | } u; |
37 | loff_t pos; /* file position */ | 37 | loff_t pos; /* file position */ |
38 | loff_t *opos; /* sendfile: output position */ | ||
38 | size_t num_spliced; /* number of bytes already spliced */ | 39 | size_t num_spliced; /* number of bytes already spliced */ |
39 | bool need_wakeup; /* need to wake up writer */ | 40 | bool need_wakeup; /* need to wake up writer */ |
40 | }; | 41 | }; |