diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/9p/trans_sock.c | 1 | ||||
-rw-r--r-- | fs/bio.c | 38 | ||||
-rw-r--r-- | fs/compat.c | 2 | ||||
-rw-r--r-- | fs/nfs/callback.c | 3 | ||||
-rw-r--r-- | fs/read_write.c | 34 |
5 files changed, 60 insertions, 18 deletions
diff --git a/fs/9p/trans_sock.c b/fs/9p/trans_sock.c index a93c2bf94c33..6a9a75d40f73 100644 --- a/fs/9p/trans_sock.c +++ b/fs/9p/trans_sock.c | |||
@@ -26,6 +26,7 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | #include <linux/config.h> | 28 | #include <linux/config.h> |
29 | #include <linux/in.h> | ||
29 | #include <linux/module.h> | 30 | #include <linux/module.h> |
30 | #include <linux/net.h> | 31 | #include <linux/net.h> |
31 | #include <linux/ipv6.h> | 32 | #include <linux/ipv6.h> |
@@ -313,7 +313,8 @@ int bio_get_nr_vecs(struct block_device *bdev) | |||
313 | } | 313 | } |
314 | 314 | ||
315 | static int __bio_add_page(request_queue_t *q, struct bio *bio, struct page | 315 | static int __bio_add_page(request_queue_t *q, struct bio *bio, struct page |
316 | *page, unsigned int len, unsigned int offset) | 316 | *page, unsigned int len, unsigned int offset, |
317 | unsigned short max_sectors) | ||
317 | { | 318 | { |
318 | int retried_segments = 0; | 319 | int retried_segments = 0; |
319 | struct bio_vec *bvec; | 320 | struct bio_vec *bvec; |
@@ -327,7 +328,7 @@ static int __bio_add_page(request_queue_t *q, struct bio *bio, struct page | |||
327 | if (bio->bi_vcnt >= bio->bi_max_vecs) | 328 | if (bio->bi_vcnt >= bio->bi_max_vecs) |
328 | return 0; | 329 | return 0; |
329 | 330 | ||
330 | if (((bio->bi_size + len) >> 9) > q->max_sectors) | 331 | if (((bio->bi_size + len) >> 9) > max_sectors) |
331 | return 0; | 332 | return 0; |
332 | 333 | ||
333 | /* | 334 | /* |
@@ -386,6 +387,25 @@ static int __bio_add_page(request_queue_t *q, struct bio *bio, struct page | |||
386 | } | 387 | } |
387 | 388 | ||
388 | /** | 389 | /** |
390 | * bio_add_pc_page - attempt to add page to bio | ||
391 | * @bio: destination bio | ||
392 | * @page: page to add | ||
393 | * @len: vec entry length | ||
394 | * @offset: vec entry offset | ||
395 | * | ||
396 | * Attempt to add a page to the bio_vec maplist. This can fail for a | ||
397 | * number of reasons, such as the bio being full or target block | ||
398 | * device limitations. The target block device must allow bio's | ||
399 | * smaller than PAGE_SIZE, so it is always possible to add a single | ||
400 | * page to an empty bio. This should only be used by REQ_PC bios. | ||
401 | */ | ||
402 | int bio_add_pc_page(request_queue_t *q, struct bio *bio, struct page *page, | ||
403 | unsigned int len, unsigned int offset) | ||
404 | { | ||
405 | return __bio_add_page(q, bio, page, len, offset, q->max_hw_sectors); | ||
406 | } | ||
407 | |||
408 | /** | ||
389 | * bio_add_page - attempt to add page to bio | 409 | * bio_add_page - attempt to add page to bio |
390 | * @bio: destination bio | 410 | * @bio: destination bio |
391 | * @page: page to add | 411 | * @page: page to add |
@@ -401,8 +421,8 @@ static int __bio_add_page(request_queue_t *q, struct bio *bio, struct page | |||
401 | int bio_add_page(struct bio *bio, struct page *page, unsigned int len, | 421 | int bio_add_page(struct bio *bio, struct page *page, unsigned int len, |
402 | unsigned int offset) | 422 | unsigned int offset) |
403 | { | 423 | { |
404 | return __bio_add_page(bdev_get_queue(bio->bi_bdev), bio, page, | 424 | struct request_queue *q = bdev_get_queue(bio->bi_bdev); |
405 | len, offset); | 425 | return __bio_add_page(q, bio, page, len, offset, q->max_sectors); |
406 | } | 426 | } |
407 | 427 | ||
408 | struct bio_map_data { | 428 | struct bio_map_data { |
@@ -514,7 +534,7 @@ struct bio *bio_copy_user(request_queue_t *q, unsigned long uaddr, | |||
514 | break; | 534 | break; |
515 | } | 535 | } |
516 | 536 | ||
517 | if (__bio_add_page(q, bio, page, bytes, 0) < bytes) { | 537 | if (bio_add_pc_page(q, bio, page, bytes, 0) < bytes) { |
518 | ret = -EINVAL; | 538 | ret = -EINVAL; |
519 | break; | 539 | break; |
520 | } | 540 | } |
@@ -628,7 +648,8 @@ static struct bio *__bio_map_user_iov(request_queue_t *q, | |||
628 | /* | 648 | /* |
629 | * sorry... | 649 | * sorry... |
630 | */ | 650 | */ |
631 | if (__bio_add_page(q, bio, pages[j], bytes, offset) < bytes) | 651 | if (bio_add_pc_page(q, bio, pages[j], bytes, offset) < |
652 | bytes) | ||
632 | break; | 653 | break; |
633 | 654 | ||
634 | len -= bytes; | 655 | len -= bytes; |
@@ -801,8 +822,8 @@ static struct bio *__bio_map_kern(request_queue_t *q, void *data, | |||
801 | if (bytes > len) | 822 | if (bytes > len) |
802 | bytes = len; | 823 | bytes = len; |
803 | 824 | ||
804 | if (__bio_add_page(q, bio, virt_to_page(data), bytes, | 825 | if (bio_add_pc_page(q, bio, virt_to_page(data), bytes, |
805 | offset) < bytes) | 826 | offset) < bytes) |
806 | break; | 827 | break; |
807 | 828 | ||
808 | data += bytes; | 829 | data += bytes; |
@@ -1228,6 +1249,7 @@ EXPORT_SYMBOL(bio_clone); | |||
1228 | EXPORT_SYMBOL(bio_phys_segments); | 1249 | EXPORT_SYMBOL(bio_phys_segments); |
1229 | EXPORT_SYMBOL(bio_hw_segments); | 1250 | EXPORT_SYMBOL(bio_hw_segments); |
1230 | EXPORT_SYMBOL(bio_add_page); | 1251 | EXPORT_SYMBOL(bio_add_page); |
1252 | EXPORT_SYMBOL(bio_add_pc_page); | ||
1231 | EXPORT_SYMBOL(bio_get_nr_vecs); | 1253 | EXPORT_SYMBOL(bio_get_nr_vecs); |
1232 | EXPORT_SYMBOL(bio_map_user); | 1254 | EXPORT_SYMBOL(bio_map_user); |
1233 | EXPORT_SYMBOL(bio_unmap_user); | 1255 | EXPORT_SYMBOL(bio_unmap_user); |
diff --git a/fs/compat.c b/fs/compat.c index 818634120b69..55ac0324aaf1 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
@@ -1170,7 +1170,7 @@ static ssize_t compat_do_readv_writev(int type, struct file *file, | |||
1170 | } | 1170 | } |
1171 | 1171 | ||
1172 | ret = rw_verify_area(type, file, pos, tot_len); | 1172 | ret = rw_verify_area(type, file, pos, tot_len); |
1173 | if (ret) | 1173 | if (ret < 0) |
1174 | goto out; | 1174 | goto out; |
1175 | 1175 | ||
1176 | fnv = NULL; | 1176 | fnv = NULL; |
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index f2ca782aba33..30cae3602867 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -14,6 +14,9 @@ | |||
14 | #include <linux/sunrpc/svc.h> | 14 | #include <linux/sunrpc/svc.h> |
15 | #include <linux/sunrpc/svcsock.h> | 15 | #include <linux/sunrpc/svcsock.h> |
16 | #include <linux/nfs_fs.h> | 16 | #include <linux/nfs_fs.h> |
17 | |||
18 | #include <net/inet_sock.h> | ||
19 | |||
17 | #include "nfs4_fs.h" | 20 | #include "nfs4_fs.h" |
18 | #include "callback.h" | 21 | #include "callback.h" |
19 | 22 | ||
diff --git a/fs/read_write.c b/fs/read_write.c index a091ee4f430d..df3468a22fea 100644 --- a/fs/read_write.c +++ b/fs/read_write.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/security.h> | 14 | #include <linux/security.h> |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/syscalls.h> | 16 | #include <linux/syscalls.h> |
17 | #include <linux/pagemap.h> | ||
17 | 18 | ||
18 | #include <asm/uaccess.h> | 19 | #include <asm/uaccess.h> |
19 | #include <asm/unistd.h> | 20 | #include <asm/unistd.h> |
@@ -182,22 +183,33 @@ bad: | |||
182 | } | 183 | } |
183 | #endif | 184 | #endif |
184 | 185 | ||
186 | /* | ||
187 | * rw_verify_area doesn't like huge counts. We limit | ||
188 | * them to something that fits in "int" so that others | ||
189 | * won't have to do range checks all the time. | ||
190 | */ | ||
191 | #define MAX_RW_COUNT (INT_MAX & PAGE_CACHE_MASK) | ||
185 | 192 | ||
186 | int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count) | 193 | int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count) |
187 | { | 194 | { |
188 | struct inode *inode; | 195 | struct inode *inode; |
189 | loff_t pos; | 196 | loff_t pos; |
190 | 197 | ||
191 | if (unlikely(count > INT_MAX)) | 198 | if (unlikely((ssize_t) count < 0)) |
192 | goto Einval; | 199 | goto Einval; |
193 | pos = *ppos; | 200 | pos = *ppos; |
194 | if (unlikely((pos < 0) || (loff_t) (pos + count) < 0)) | 201 | if (unlikely((pos < 0) || (loff_t) (pos + count) < 0)) |
195 | goto Einval; | 202 | goto Einval; |
196 | 203 | ||
197 | inode = file->f_dentry->d_inode; | 204 | inode = file->f_dentry->d_inode; |
198 | if (inode->i_flock && MANDATORY_LOCK(inode)) | 205 | if (inode->i_flock && MANDATORY_LOCK(inode)) { |
199 | return locks_mandatory_area(read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE, inode, file, pos, count); | 206 | int retval = locks_mandatory_area( |
200 | return 0; | 207 | read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE, |
208 | inode, file, pos, count); | ||
209 | if (retval < 0) | ||
210 | return retval; | ||
211 | } | ||
212 | return count > MAX_RW_COUNT ? MAX_RW_COUNT : count; | ||
201 | 213 | ||
202 | Einval: | 214 | Einval: |
203 | return -EINVAL; | 215 | return -EINVAL; |
@@ -244,7 +256,8 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) | |||
244 | return -EFAULT; | 256 | return -EFAULT; |
245 | 257 | ||
246 | ret = rw_verify_area(READ, file, pos, count); | 258 | ret = rw_verify_area(READ, file, pos, count); |
247 | if (!ret) { | 259 | if (ret >= 0) { |
260 | count = ret; | ||
248 | ret = security_file_permission (file, MAY_READ); | 261 | ret = security_file_permission (file, MAY_READ); |
249 | if (!ret) { | 262 | if (!ret) { |
250 | if (file->f_op->read) | 263 | if (file->f_op->read) |
@@ -295,7 +308,8 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_ | |||
295 | return -EFAULT; | 308 | return -EFAULT; |
296 | 309 | ||
297 | ret = rw_verify_area(WRITE, file, pos, count); | 310 | ret = rw_verify_area(WRITE, file, pos, count); |
298 | if (!ret) { | 311 | if (ret >= 0) { |
312 | count = ret; | ||
299 | ret = security_file_permission (file, MAY_WRITE); | 313 | ret = security_file_permission (file, MAY_WRITE); |
300 | if (!ret) { | 314 | if (!ret) { |
301 | if (file->f_op->write) | 315 | if (file->f_op->write) |
@@ -497,7 +511,7 @@ static ssize_t do_readv_writev(int type, struct file *file, | |||
497 | } | 511 | } |
498 | 512 | ||
499 | ret = rw_verify_area(type, file, pos, tot_len); | 513 | ret = rw_verify_area(type, file, pos, tot_len); |
500 | if (ret) | 514 | if (ret < 0) |
501 | goto out; | 515 | goto out; |
502 | ret = security_file_permission(file, type == READ ? MAY_READ : MAY_WRITE); | 516 | ret = security_file_permission(file, type == READ ? MAY_READ : MAY_WRITE); |
503 | if (ret) | 517 | if (ret) |
@@ -653,8 +667,9 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, | |||
653 | if (!(in_file->f_mode & FMODE_PREAD)) | 667 | if (!(in_file->f_mode & FMODE_PREAD)) |
654 | goto fput_in; | 668 | goto fput_in; |
655 | retval = rw_verify_area(READ, in_file, ppos, count); | 669 | retval = rw_verify_area(READ, in_file, ppos, count); |
656 | if (retval) | 670 | if (retval < 0) |
657 | goto fput_in; | 671 | goto fput_in; |
672 | count = retval; | ||
658 | 673 | ||
659 | retval = security_file_permission (in_file, MAY_READ); | 674 | retval = security_file_permission (in_file, MAY_READ); |
660 | if (retval) | 675 | if (retval) |
@@ -674,8 +689,9 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, | |||
674 | goto fput_out; | 689 | goto fput_out; |
675 | out_inode = out_file->f_dentry->d_inode; | 690 | out_inode = out_file->f_dentry->d_inode; |
676 | retval = rw_verify_area(WRITE, out_file, &out_file->f_pos, count); | 691 | retval = rw_verify_area(WRITE, out_file, &out_file->f_pos, count); |
677 | if (retval) | 692 | if (retval < 0) |
678 | goto fput_out; | 693 | goto fput_out; |
694 | count = retval; | ||
679 | 695 | ||
680 | retval = security_file_permission (out_file, MAY_WRITE); | 696 | retval = security_file_permission (out_file, MAY_WRITE); |
681 | if (retval) | 697 | if (retval) |