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
203203
204204
205205 Flag checking should be done at the beginning of the ->fiemap callback via the
206−fiemap_check_flags() helper:
206+fiemap_prep() helper:
207207
208−int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags);
208+int fiemap_prep(struct inode *inode, struct fiemap_extent_info *fieinfo,
209+ u64 start, u64 *len, u32 supported_flags);
209210
210211 The struct fieinfo should be passed in as received from ioctl_fiemap(). The
211212 set of fiemap flags which the fs understands should be passed via fs_flags. If
212−fiemap_check_flags finds invalid user flags, it will place the bad values in
213+fiemap_prep finds invalid user flags, it will place the bad values in
213214 fieinfo->fi_flags and return -EBADR. If the file system gets -EBADR, from
214−fiemap_check_flags(), it should immediately exit, returning that error back to
215−ioctl_fiemap().
215+fiemap_prep(), it should immediately exit, returning that error back to
216+ioctl_fiemap(). Additionally the range is validate against the supported
217+maximum file size.
216218
217219
218220 For 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
82508250 {
82518251 int ret;
82528252
8253− ret = fiemap_check_flags(fieinfo, BTRFS_FIEMAP_FLAGS);
8253+ ret = fiemap_prep(inode, fieinfo, start, &len, BTRFS_FIEMAP_FLAGS);
82548254 if (ret)
82558255 return ret;
82568256
fs/cifs/smb2ops.c+4−2
@@ -3408,8 +3408,10 @@ static int smb3_fiemap(struct cifs_tcon *tcon, · 3407 unmodified lines
34083408 int i, num, rc, flags, last_blob;
34093409 u64 next;
34103410
3411− if (fiemap_check_flags(fei, FIEMAP_FLAG_SYNC))
3412− return -EBADR;
3411+ rc = fiemap_prep(d_inode(cfile->dentry), fei, start, &len,
3412+ FIEMAP_FLAG_SYNC);
3413+ if (rc)
3414+ return rc;
34133415
34143416 xid = get_xid();
34153417 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
49384938 fieinfo->fi_flags &= ~FIEMAP_FLAG_CACHE;
49394939 }
49404940
4941− if (fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC))
4942− return -EBADR;
4941+ error = fiemap_prep(inode, fieinfo, start, &len, FIEMAP_FLAG_SYNC);
4942+ if (error)
4943+ return error;
49434944
49444945 error = ext4_fiemap_check_ranges(inode, start, &len);
49454946 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
18251825 return ret;
18261826 }
18271827
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);
18291830 if (ret)
18301831 return ret;
18311832
fs/ioctl.c+24−39
@@ -149,61 +149,50 @@ int fiemap_fill_next_extent(struct fiemap_extent_info *fieinfo, u64 logical, · 148 unmodified lines
149149 EXPORT_SYMBOL(fiemap_fill_next_extent);
150150
151151 /**
152− * fiemap_check_flags - check validity of requested flags for fiemap
152+ * fiemap_prep - check validity of requested flags for fiemap
153+ * @inode: Inode to operate on
153154 * @fieinfo: Fiemap context passed into ->fiemap
154− * @fs_flags: Set of fiemap flags that the file system understands
155+ * @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
155158 *
156− * Called from file system ->fiemap callback. This will compute the
157− * intersection of valid fiemap flags and those that the fs supports. That
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.
159+ * This function must be called from each ->fiemap instance to validate the
160+ * fiemap request against the file system parameters.
162161 *
163− * Returns 0 on success, -EBADR on bad flags.
162+ * Returns 0 on success, or a negative error on failure.
164163 */
165−int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags)
164+int fiemap_prep(struct inode *inode, struct fiemap_extent_info *fieinfo,
165+ u64 start, u64 *len, u32 supported_flags)
166166 {
167+ u64 maxbytes = inode->i_sb->s_maxbytes;
167168 u32 incompat_flags;
168169
169− incompat_flags = fieinfo->fi_flags & ~(FIEMAP_FLAGS_COMPAT & fs_flags);
170− if (incompat_flags) {
171− fieinfo->fi_flags = incompat_flags;
172− return -EBADR;
173− }
174− return 0;
175−}
176−EXPORT_SYMBOL(fiemap_check_flags);
177−
178−static 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)
170+ if (*len == 0)
186171 return -EINVAL;
187−
188172 if (start > maxbytes)
189173 return -EFBIG;
190174
191175 /*
192176 * Shrink request scope to what the fs can actually handle.
193177 */
194− if (len > maxbytes || (maxbytes - len) < start)
195− *new_len = maxbytes - start;
178+ if (*len > maxbytes || (maxbytes - *len) < start)
179+ *len = maxbytes - start;
196180
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+ }
197187 return 0;
198188 }
189+EXPORT_SYMBOL(fiemap_prep);
199190
200191 static int ioctl_fiemap(struct file *filp, struct fiemap __user *ufiemap)
201192 {
202193 struct fiemap fiemap;
203194 struct fiemap_extent_info fieinfo = { 0, };
204195 struct inode *inode = file_inode(filp);
205− struct super_block *sb = inode->i_sb;
206− u64 len;
207196 int error;
208197
209198 if (!inode->i_op->fiemap)
@@ -215,11 +204,6 @@ static int ioctl_fiemap(struct file *filp, struct fiemap __user *ufiemap) · 5 unmodified lines
215204 if (fiemap.fm_extent_count > FIEMAP_MAX_EXTENTS)
216205 return -EINVAL;
217206
218− error = fiemap_check_ranges(sb, fiemap.fm_start, fiemap.fm_length,
219− &len);
220− if (error)
221− return error;
222−
223207 fieinfo.fi_flags = fiemap.fm_flags;
224208 fieinfo.fi_extents_max = fiemap.fm_extent_count;
225209 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
232216 if (fieinfo.fi_flags & FIEMAP_FLAG_SYNC)
233217 filemap_write_and_wait(inode->i_mapping);
234218
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);
236221 fiemap.fm_flags = fieinfo.fi_flags;
237222 fiemap.fm_mapped_extents = fieinfo.fi_extents_mapped;
238223 if (copy_to_user(ufiemap, &fiemap, sizeof(fiemap)))
@@ -320,7 +305,7 @@ static int __generic_block_fiemap(struct inode *inode, · 81 unmodified lines
320305 bool past_eof = false, whole_file = false;
321306 int ret = 0;
322307
323− ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC);
308+ ret = fiemap_prep(inode, fieinfo, start, &len, FIEMAP_FLAG_SYNC);
324309 if (ret)
325310 return ret;
326311
fs/iomap/fiemap.c+1−1
@@ -75,7 +75,7 @@ int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi, · 74 unmodified lines
7575 ctx.fi = fi;
7676 ctx.prev.type = IOMAP_HOLE;
7777
78− ret = fiemap_check_flags(fi, FIEMAP_FLAG_SYNC);
78+ ret = fiemap_prep(inode, fi, start, &len, FIEMAP_FLAG_SYNC);
7979 if (ret)
8080 return ret;
8181
fs/nilfs2/inode.c+1−1
@@ -1006,7 +1006,7 @@ int nilfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, · 1005 unmodified lines
10061006 unsigned int blkbits = inode->i_blkbits;
10071007 int ret, n;
10081008
1009− ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC);
1009+ ret = fiemap_prep(inode, fieinfo, start, &len, FIEMAP_FLAG_SYNC);
10101010 if (ret)
10111011 return ret;
10121012
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
746746 struct buffer_head *di_bh = NULL;
747747 struct ocfs2_extent_rec rec;
748748
749− ret = fiemap_check_flags(fieinfo, OCFS2_FIEMAP_FLAGS);
749+ ret = fiemap_prep(inode, fieinfo, map_start, &map_len,
750+ OCFS2_FIEMAP_FLAGS);
750751 if (ret)
751752 return ret;
752753
include/linux/fiemap.h+2−1
@@ -13,9 +13,10 @@ struct fiemap_extent_info { · 12 unmodified lines
1313 fiemap_extent array */
1414 };
1515
16+int fiemap_prep(struct inode *inode, struct fiemap_extent_info *fieinfo,
17+ u64 start, u64 *len, u32 supported_flags);
1618 int fiemap_fill_next_extent(struct fiemap_extent_info *info, u64 logical,
1719 u64 phys, u64 len, u32 flags);
18−int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags);
1920
2021 int generic_block_fiemap(struct inode *inode,
2122 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