diff options
-rw-r--r-- | fs/ntfs/file.c | 21 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_lrw.c | 22 | ||||
-rw-r--r-- | include/linux/fs.h | 2 | ||||
-rw-r--r-- | mm/filemap.c | 82 |
4 files changed, 53 insertions, 74 deletions
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index dbbac5593106..621de369e6f8 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c | |||
@@ -2129,28 +2129,13 @@ static ssize_t ntfs_file_aio_write_nolock(struct kiocb *iocb, | |||
2129 | struct address_space *mapping = file->f_mapping; | 2129 | struct address_space *mapping = file->f_mapping; |
2130 | struct inode *inode = mapping->host; | 2130 | struct inode *inode = mapping->host; |
2131 | loff_t pos; | 2131 | loff_t pos; |
2132 | unsigned long seg; | ||
2133 | size_t count; /* after file limit checks */ | 2132 | size_t count; /* after file limit checks */ |
2134 | ssize_t written, err; | 2133 | ssize_t written, err; |
2135 | 2134 | ||
2136 | count = 0; | 2135 | count = 0; |
2137 | for (seg = 0; seg < nr_segs; seg++) { | 2136 | err = generic_segment_checks(iov, &nr_segs, &count, VERIFY_READ); |
2138 | const struct iovec *iv = &iov[seg]; | 2137 | if (err) |
2139 | /* | 2138 | return err; |
2140 | * If any segment has a negative length, or the cumulative | ||
2141 | * length ever wraps negative then return -EINVAL. | ||
2142 | */ | ||
2143 | count += iv->iov_len; | ||
2144 | if (unlikely((ssize_t)(count|iv->iov_len) < 0)) | ||
2145 | return -EINVAL; | ||
2146 | if (access_ok(VERIFY_READ, iv->iov_base, iv->iov_len)) | ||
2147 | continue; | ||
2148 | if (!seg) | ||
2149 | return -EFAULT; | ||
2150 | nr_segs = seg; | ||
2151 | count -= iv->iov_len; /* This segment is no good */ | ||
2152 | break; | ||
2153 | } | ||
2154 | pos = *ppos; | 2139 | pos = *ppos; |
2155 | vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE); | 2140 | vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE); |
2156 | /* We can write back this queue in page reclaim. */ | 2141 | /* We can write back this queue in page reclaim. */ |
diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c index ff8d64eba9f8..558076dd0752 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.c +++ b/fs/xfs/linux-2.6/xfs_lrw.c | |||
@@ -639,7 +639,6 @@ xfs_write( | |||
639 | xfs_fsize_t isize, new_size; | 639 | xfs_fsize_t isize, new_size; |
640 | xfs_iocore_t *io; | 640 | xfs_iocore_t *io; |
641 | bhv_vnode_t *vp; | 641 | bhv_vnode_t *vp; |
642 | unsigned long seg; | ||
643 | int iolock; | 642 | int iolock; |
644 | int eventsent = 0; | 643 | int eventsent = 0; |
645 | bhv_vrwlock_t locktype; | 644 | bhv_vrwlock_t locktype; |
@@ -652,24 +651,9 @@ xfs_write( | |||
652 | vp = BHV_TO_VNODE(bdp); | 651 | vp = BHV_TO_VNODE(bdp); |
653 | xip = XFS_BHVTOI(bdp); | 652 | xip = XFS_BHVTOI(bdp); |
654 | 653 | ||
655 | for (seg = 0; seg < segs; seg++) { | 654 | error = generic_segment_checks(iovp, &segs, &ocount, VERIFY_READ); |
656 | const struct iovec *iv = &iovp[seg]; | 655 | if (error) |
657 | 656 | return error; | |
658 | /* | ||
659 | * If any segment has a negative length, or the cumulative | ||
660 | * length ever wraps negative then return -EINVAL. | ||
661 | */ | ||
662 | ocount += iv->iov_len; | ||
663 | if (unlikely((ssize_t)(ocount|iv->iov_len) < 0)) | ||
664 | return -EINVAL; | ||
665 | if (access_ok(VERIFY_READ, iv->iov_base, iv->iov_len)) | ||
666 | continue; | ||
667 | if (seg == 0) | ||
668 | return -EFAULT; | ||
669 | segs = seg; | ||
670 | ocount -= iv->iov_len; /* This segment is no good */ | ||
671 | break; | ||
672 | } | ||
673 | 657 | ||
674 | count = ocount; | 658 | count = ocount; |
675 | pos = *offset; | 659 | pos = *offset; |
diff --git a/include/linux/fs.h b/include/linux/fs.h index bc6d27cecaac..020a8426e10a 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1735,6 +1735,8 @@ extern ssize_t generic_file_sendfile(struct file *, loff_t *, size_t, read_actor | |||
1735 | extern void do_generic_mapping_read(struct address_space *mapping, | 1735 | extern void do_generic_mapping_read(struct address_space *mapping, |
1736 | struct file_ra_state *, struct file *, | 1736 | struct file_ra_state *, struct file *, |
1737 | loff_t *, read_descriptor_t *, read_actor_t); | 1737 | loff_t *, read_descriptor_t *, read_actor_t); |
1738 | extern int generic_segment_checks(const struct iovec *iov, | ||
1739 | unsigned long *nr_segs, size_t *count, int access_flags); | ||
1738 | 1740 | ||
1739 | /* fs/splice.c */ | 1741 | /* fs/splice.c */ |
1740 | extern ssize_t generic_file_splice_read(struct file *, loff_t *, | 1742 | extern ssize_t generic_file_splice_read(struct file *, loff_t *, |
diff --git a/mm/filemap.c b/mm/filemap.c index 5631d6b2a62d..3e49fe13d6ac 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -1110,6 +1110,45 @@ success: | |||
1110 | return size; | 1110 | return size; |
1111 | } | 1111 | } |
1112 | 1112 | ||
1113 | /* | ||
1114 | * Performs necessary checks before doing a write | ||
1115 | * @iov: io vector request | ||
1116 | * @nr_segs: number of segments in the iovec | ||
1117 | * @count: number of bytes to write | ||
1118 | * @access_flags: type of access: %VERIFY_READ or %VERIFY_WRITE | ||
1119 | * | ||
1120 | * Adjust number of segments and amount of bytes to write (nr_segs should be | ||
1121 | * properly initialized first). Returns appropriate error code that caller | ||
1122 | * should return or zero in case that write should be allowed. | ||
1123 | */ | ||
1124 | int generic_segment_checks(const struct iovec *iov, | ||
1125 | unsigned long *nr_segs, size_t *count, int access_flags) | ||
1126 | { | ||
1127 | unsigned long seg; | ||
1128 | size_t cnt = 0; | ||
1129 | for (seg = 0; seg < *nr_segs; seg++) { | ||
1130 | const struct iovec *iv = &iov[seg]; | ||
1131 | |||
1132 | /* | ||
1133 | * If any segment has a negative length, or the cumulative | ||
1134 | * length ever wraps negative then return -EINVAL. | ||
1135 | */ | ||
1136 | cnt += iv->iov_len; | ||
1137 | if (unlikely((ssize_t)(cnt|iv->iov_len) < 0)) | ||
1138 | return -EINVAL; | ||
1139 | if (access_ok(access_flags, iv->iov_base, iv->iov_len)) | ||
1140 | continue; | ||
1141 | if (seg == 0) | ||
1142 | return -EFAULT; | ||
1143 | *nr_segs = seg; | ||
1144 | cnt -= iv->iov_len; /* This segment is no good */ | ||
1145 | break; | ||
1146 | } | ||
1147 | *count = cnt; | ||
1148 | return 0; | ||
1149 | } | ||
1150 | EXPORT_SYMBOL(generic_segment_checks); | ||
1151 | |||
1113 | /** | 1152 | /** |
1114 | * generic_file_aio_read - generic filesystem read routine | 1153 | * generic_file_aio_read - generic filesystem read routine |
1115 | * @iocb: kernel I/O control block | 1154 | * @iocb: kernel I/O control block |
@@ -1131,24 +1170,9 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, | |||
1131 | loff_t *ppos = &iocb->ki_pos; | 1170 | loff_t *ppos = &iocb->ki_pos; |
1132 | 1171 | ||
1133 | count = 0; | 1172 | count = 0; |
1134 | for (seg = 0; seg < nr_segs; seg++) { | 1173 | retval = generic_segment_checks(iov, &nr_segs, &count, VERIFY_WRITE); |
1135 | const struct iovec *iv = &iov[seg]; | 1174 | if (retval) |
1136 | 1175 | return retval; | |
1137 | /* | ||
1138 | * If any segment has a negative length, or the cumulative | ||
1139 | * length ever wraps negative then return -EINVAL. | ||
1140 | */ | ||
1141 | count += iv->iov_len; | ||
1142 | if (unlikely((ssize_t)(count|iv->iov_len) < 0)) | ||
1143 | return -EINVAL; | ||
1144 | if (access_ok(VERIFY_WRITE, iv->iov_base, iv->iov_len)) | ||
1145 | continue; | ||
1146 | if (seg == 0) | ||
1147 | return -EFAULT; | ||
1148 | nr_segs = seg; | ||
1149 | count -= iv->iov_len; /* This segment is no good */ | ||
1150 | break; | ||
1151 | } | ||
1152 | 1176 | ||
1153 | /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */ | 1177 | /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */ |
1154 | if (filp->f_flags & O_DIRECT) { | 1178 | if (filp->f_flags & O_DIRECT) { |
@@ -2218,30 +2242,14 @@ __generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov, | |||
2218 | size_t ocount; /* original count */ | 2242 | size_t ocount; /* original count */ |
2219 | size_t count; /* after file limit checks */ | 2243 | size_t count; /* after file limit checks */ |
2220 | struct inode *inode = mapping->host; | 2244 | struct inode *inode = mapping->host; |
2221 | unsigned long seg; | ||
2222 | loff_t pos; | 2245 | loff_t pos; |
2223 | ssize_t written; | 2246 | ssize_t written; |
2224 | ssize_t err; | 2247 | ssize_t err; |
2225 | 2248 | ||
2226 | ocount = 0; | 2249 | ocount = 0; |
2227 | for (seg = 0; seg < nr_segs; seg++) { | 2250 | err = generic_segment_checks(iov, &nr_segs, &ocount, VERIFY_READ); |
2228 | const struct iovec *iv = &iov[seg]; | 2251 | if (err) |
2229 | 2252 | return err; | |
2230 | /* | ||
2231 | * If any segment has a negative length, or the cumulative | ||
2232 | * length ever wraps negative then return -EINVAL. | ||
2233 | */ | ||
2234 | ocount += iv->iov_len; | ||
2235 | if (unlikely((ssize_t)(ocount|iv->iov_len) < 0)) | ||
2236 | return -EINVAL; | ||
2237 | if (access_ok(VERIFY_READ, iv->iov_base, iv->iov_len)) | ||
2238 | continue; | ||
2239 | if (seg == 0) | ||
2240 | return -EFAULT; | ||
2241 | nr_segs = seg; | ||
2242 | ocount -= iv->iov_len; /* This segment is no good */ | ||
2243 | break; | ||
2244 | } | ||
2245 | 2253 | ||
2246 | count = ocount; | 2254 | count = ocount; |
2247 | pos = *ppos; | 2255 | pos = *ppos; |