History

fs: move fiemap range validation into the file systems instances

Replace fiemap_check_flags with a fiemap_prep helper that also takes the inode and mapped range, and performs the sanity check and truncation previously done in fiemap_check_range. This way the validation is inside the file system itself and thus properly works for the stacked overlayfs case as well.

Christoph Hellwig committed 6 years ago

Commit cddf8a21 parent 273288110 files · +47 −54Browse files

Unified · Split

10 files
  1. Documentation/filesystems/fiemap.txt +7 −5
  2. fs/btrfs/inode.c +1 −1
  3. fs/cifs/smb2ops.c +4 −2
  4. fs/ext4/extents.c +3 −2
  5. fs/f2fs/data.c +2 −1
  6. fs/ioctl.c +24 −39
  7. fs/iomap/fiemap.c +1 −1
  8. fs/nilfs2/inode.c +1 −1
  9. fs/ocfs2/extent_map.c +2 −1
  10. include/linux/fiemap.h +2 −1
Documentation/filesystems/fiemap.txt+7−5
@@ -203,16 +203,18 @@ EINTR once fatal signal received. · 202 unmodified lines
203 203
204 204
205Flag checking should be done at the beginning of the ->fiemap callback via the205Flag checking should be done at the beginning of the ->fiemap callback via the
206fiemap_check_flags() helper:206fiemap_prep() helper:
207 207
208int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags);208int fiemap_prep(struct inode *inode, struct fiemap_extent_info *fieinfo,
209 u64 start, u64 *len, u32 supported_flags);
209 210
210The struct fieinfo should be passed in as received from ioctl_fiemap(). The211The struct fieinfo should be passed in as received from ioctl_fiemap(). The
211set of fiemap flags which the fs understands should be passed via fs_flags. If212set of fiemap flags which the fs understands should be passed via fs_flags. If
212fiemap_check_flags finds invalid user flags, it will place the bad values in213fiemap_prep finds invalid user flags, it will place the bad values in
213fieinfo->fi_flags and return -EBADR. If the file system gets -EBADR, from214fieinfo->fi_flags and return -EBADR. If the file system gets -EBADR, from
214fiemap_check_flags(), it should immediately exit, returning that error back to215fiemap_prep(), it should immediately exit, returning that error back to
215ioctl_fiemap().216ioctl_fiemap(). Additionally the range is validate against the supported
217maximum file size.
216 218
217 219
218For each extent in the request range, the file system should call220For each extent in the request range, the file system should call
fs/btrfs/inode.c+1−1
@@ -8250,7 +8250,7 @@ static int btrfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, · 8249 unmodified lines
8250{8250{
8251 int ret;8251 int ret;
8252 8252
8253 ret = fiemap_check_flags(fieinfo, BTRFS_FIEMAP_FLAGS);8253 ret = fiemap_prep(inode, fieinfo, start, &len, BTRFS_FIEMAP_FLAGS);
8254 if (ret)8254 if (ret)
8255 return ret;8255 return ret;
8256 8256
fs/cifs/smb2ops.c+4−2
@@ -3408,8 +3408,10 @@ static int smb3_fiemap(struct cifs_tcon *tcon, · 3407 unmodified lines
3408 int i, num, rc, flags, last_blob;3408 int i, num, rc, flags, last_blob;
3409 u64 next;3409 u64 next;
3410 3410
3411 if (fiemap_check_flags(fei, FIEMAP_FLAG_SYNC))3411 rc = fiemap_prep(d_inode(cfile->dentry), fei, start, &len,
3412 return -EBADR;3412 FIEMAP_FLAG_SYNC);
3413 if (rc)
3414 return rc;
3413 3415
3414 xid = get_xid();3416 xid = get_xid();
3415 again:3417 again:
fs/ext4/extents.c+3−2
@@ -4938,8 +4938,9 @@ int ext4_get_es_cache(struct inode *inode, struct fiemap_extent_info *fieinfo, · 4937 unmodified lines
4938 fieinfo->fi_flags &= ~FIEMAP_FLAG_CACHE;4938 fieinfo->fi_flags &= ~FIEMAP_FLAG_CACHE;
4939 }4939 }
4940 4940
4941 if (fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC))4941 error = fiemap_prep(inode, fieinfo, start, &len, FIEMAP_FLAG_SYNC);
4942 return -EBADR;4942 if (error)
4943 return error;
4943 4944
4944 error = ext4_fiemap_check_ranges(inode, start, &len);4945 error = ext4_fiemap_check_ranges(inode, start, &len);
4945 if (error)4946 if (error)
fs/f2fs/data.c+2−1
@@ -1825,7 +1825,8 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, · 1824 unmodified lines
1825 return ret;1825 return ret;
1826 }1826 }
1827 1827
1828 ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC | FIEMAP_FLAG_XATTR);1828 ret = fiemap_prep(inode, fieinfo, start, &len,
1829 FIEMAP_FLAG_SYNC | FIEMAP_FLAG_XATTR);
1829 if (ret)1830 if (ret)
1830 return ret;1831 return ret;
1831 1832
fs/ioctl.c+24−39
@@ -149,61 +149,50 @@ int fiemap_fill_next_extent(struct fiemap_extent_info *fieinfo, u64 logical, · 148 unmodified lines
149EXPORT_SYMBOL(fiemap_fill_next_extent);149EXPORT_SYMBOL(fiemap_fill_next_extent);
150 150
151/**151/**
152 * fiemap_check_flags - check validity of requested flags for fiemap152 * fiemap_prep - check validity of requested flags for fiemap
153 * @inode: Inode to operate on
153 * @fieinfo: Fiemap context passed into ->fiemap154 * @fieinfo: Fiemap context passed into ->fiemap
154 * @fs_flags: Set of fiemap flags that the file system understands155 * @start: Start of the mapped range
156 * @len: Length of the mapped range, can be truncated by this function.
157 * @supported_flags: Set of fiemap flags that the file system understands
155 *158 *
156 * Called from file system ->fiemap callback. This will compute the159 * This function must be called from each ->fiemap instance to validate the
157 * intersection of valid fiemap flags and those that the fs supports. That160 * fiemap request against the file system parameters.
158 * value is then compared against the user supplied flags. In case of bad user
159 * flags, the invalid values will be written into the fieinfo structure, and
160 * -EBADR is returned, which tells ioctl_fiemap() to return those values to
161 * userspace. For this reason, a return code of -EBADR should be preserved.
162 *161 *
163 * Returns 0 on success, -EBADR on bad flags.162 * Returns 0 on success, or a negative error on failure.
164 */163 */
165int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags)164int fiemap_prep(struct inode *inode, struct fiemap_extent_info *fieinfo,
165 u64 start, u64 *len, u32 supported_flags)
166{166{
167 u64 maxbytes = inode->i_sb->s_maxbytes;
167 u32 incompat_flags;168 u32 incompat_flags;
168 169
169 incompat_flags = fieinfo->fi_flags & ~(FIEMAP_FLAGS_COMPAT & fs_flags);170 if (*len == 0)
170 if (incompat_flags) {
171 fieinfo->fi_flags = incompat_flags;
172 return -EBADR;
173 }
174 return 0;
175}
176EXPORT_SYMBOL(fiemap_check_flags);
177
178static int fiemap_check_ranges(struct super_block *sb,
179 u64 start, u64 len, u64 *new_len)
180{
181 u64 maxbytes = (u64) sb->s_maxbytes;
182
183 *new_len = len;
184
185 if (len == 0)
186 return -EINVAL;171 return -EINVAL;
187
188 if (start > maxbytes)172 if (start > maxbytes)
189 return -EFBIG;173 return -EFBIG;
190 174
191 /*175 /*
192 * Shrink request scope to what the fs can actually handle.176 * Shrink request scope to what the fs can actually handle.
193 */177 */
194 if (len > maxbytes || (maxbytes - len) < start)178 if (*len > maxbytes || (maxbytes - *len) < start)
195 *new_len = maxbytes - start;179 *len = maxbytes - start;
196 180
181 supported_flags &= FIEMAP_FLAGS_COMPAT;
182 incompat_flags = fieinfo->fi_flags & ~supported_flags;
183 if (incompat_flags) {
184 fieinfo->fi_flags = incompat_flags;
185 return -EBADR;
186 }
197 return 0;187 return 0;
198}188}
189EXPORT_SYMBOL(fiemap_prep);
199 190
200static int ioctl_fiemap(struct file *filp, struct fiemap __user *ufiemap)191static int ioctl_fiemap(struct file *filp, struct fiemap __user *ufiemap)
201{192{
202 struct fiemap fiemap;193 struct fiemap fiemap;
203 struct fiemap_extent_info fieinfo = { 0, };194 struct fiemap_extent_info fieinfo = { 0, };
204 struct inode *inode = file_inode(filp);195 struct inode *inode = file_inode(filp);
205 struct super_block *sb = inode->i_sb;
206 u64 len;
207 int error;196 int error;
208 197
209 if (!inode->i_op->fiemap)198 if (!inode->i_op->fiemap)
@@ -215,11 +204,6 @@ static int ioctl_fiemap(struct file *filp, struct fiemap __user *ufiemap) · 5 unmodified lines
215 if (fiemap.fm_extent_count > FIEMAP_MAX_EXTENTS)204 if (fiemap.fm_extent_count > FIEMAP_MAX_EXTENTS)
216 return -EINVAL;205 return -EINVAL;
217 206
218 error = fiemap_check_ranges(sb, fiemap.fm_start, fiemap.fm_length,
219 &len);
220 if (error)
221 return error;
222
223 fieinfo.fi_flags = fiemap.fm_flags;207 fieinfo.fi_flags = fiemap.fm_flags;
224 fieinfo.fi_extents_max = fiemap.fm_extent_count;208 fieinfo.fi_extents_max = fiemap.fm_extent_count;
225 fieinfo.fi_extents_start = ufiemap->fm_extents;209 fieinfo.fi_extents_start = ufiemap->fm_extents;
@@ -232,7 +216,8 @@ static int ioctl_fiemap(struct file *filp, struct fiemap __user *ufiemap) · 6 unmodified lines
232 if (fieinfo.fi_flags & FIEMAP_FLAG_SYNC)216 if (fieinfo.fi_flags & FIEMAP_FLAG_SYNC)
233 filemap_write_and_wait(inode->i_mapping);217 filemap_write_and_wait(inode->i_mapping);
234 218
235 error = inode->i_op->fiemap(inode, &fieinfo, fiemap.fm_start, len);219 error = inode->i_op->fiemap(inode, &fieinfo, fiemap.fm_start,
220 fiemap.fm_length);
236 fiemap.fm_flags = fieinfo.fi_flags;221 fiemap.fm_flags = fieinfo.fi_flags;
237 fiemap.fm_mapped_extents = fieinfo.fi_extents_mapped;222 fiemap.fm_mapped_extents = fieinfo.fi_extents_mapped;
238 if (copy_to_user(ufiemap, &fiemap, sizeof(fiemap)))223 if (copy_to_user(ufiemap, &fiemap, sizeof(fiemap)))
@@ -320,7 +305,7 @@ static int __generic_block_fiemap(struct inode *inode, · 81 unmodified lines
320 bool past_eof = false, whole_file = false;305 bool past_eof = false, whole_file = false;
321 int ret = 0;306 int ret = 0;
322 307
323 ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC);308 ret = fiemap_prep(inode, fieinfo, start, &len, FIEMAP_FLAG_SYNC);
324 if (ret)309 if (ret)
325 return ret;310 return ret;
326 311
fs/iomap/fiemap.c+1−1
@@ -75,7 +75,7 @@ int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi, · 74 unmodified lines
75 ctx.fi = fi;75 ctx.fi = fi;
76 ctx.prev.type = IOMAP_HOLE;76 ctx.prev.type = IOMAP_HOLE;
77 77
78 ret = fiemap_check_flags(fi, FIEMAP_FLAG_SYNC);78 ret = fiemap_prep(inode, fi, start, &len, FIEMAP_FLAG_SYNC);
79 if (ret)79 if (ret)
80 return ret;80 return ret;
81 81
fs/nilfs2/inode.c+1−1
@@ -1006,7 +1006,7 @@ int nilfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, · 1005 unmodified lines
1006 unsigned int blkbits = inode->i_blkbits;1006 unsigned int blkbits = inode->i_blkbits;
1007 int ret, n;1007 int ret, n;
1008 1008
1009 ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC);1009 ret = fiemap_prep(inode, fieinfo, start, &len, FIEMAP_FLAG_SYNC);
1010 if (ret)1010 if (ret)
1011 return ret;1011 return ret;
1012 1012
fs/ocfs2/extent_map.c+2−1
@@ -746,7 +746,8 @@ int ocfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, · 745 unmodified lines
746 struct buffer_head *di_bh = NULL;746 struct buffer_head *di_bh = NULL;
747 struct ocfs2_extent_rec rec;747 struct ocfs2_extent_rec rec;
748 748
749 ret = fiemap_check_flags(fieinfo, OCFS2_FIEMAP_FLAGS);749 ret = fiemap_prep(inode, fieinfo, map_start, &map_len,
750 OCFS2_FIEMAP_FLAGS);
750 if (ret)751 if (ret)
751 return ret;752 return ret;
752 753
include/linux/fiemap.h+2−1
@@ -13,9 +13,10 @@ struct fiemap_extent_info { · 12 unmodified lines
13 fiemap_extent array */13 fiemap_extent array */
14};14};
15 15
16int fiemap_prep(struct inode *inode, struct fiemap_extent_info *fieinfo,
17 u64 start, u64 *len, u32 supported_flags);
16int fiemap_fill_next_extent(struct fiemap_extent_info *info, u64 logical,18int fiemap_fill_next_extent(struct fiemap_extent_info *info, u64 logical,
17 u64 phys, u64 len, u32 flags);19 u64 phys, u64 len, u32 flags);
18int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags);
19 20
20int generic_block_fiemap(struct inode *inode,21int generic_block_fiemap(struct inode *inode,
21 struct fiemap_extent_info *fieinfo, u64 start, u64 len,22 struct fiemap_extent_info *fieinfo, u64 start, u64 len,

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t