diff options
author | Amir Goldstein <amir73il@gmail.com> | 2017-02-02 02:56:02 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-02-04 03:47:12 -0500 |
commit | 43ce5921773b827531ed123016625481d43c2bd9 (patch) | |
tree | ad7ad68957a3d7f8efdd6a2180d17c8eca8e02fd /fs | |
parent | b5f68e24cc7bc3492ebc5c70f3ef6babcbd4188b (diff) |
xfs: sanity check inode mode when creating new dentry
commit fab8eef86c814c3dd46bc5d760b6e4a53d5fc5a6 upstream.
The helper xfs_dentry_to_name() is used by 2 different
classes of callers: Callers that pass zero mode and don't care
about the returned name.type field and Callers that pass
non zero mode and do care about the name.type field.
Change xfs_dentry_to_name() to not take the mode argument and
change the call sites of the first class to not pass the mode
argument.
Create a new helper xfs_dentry_mode_to_name() which does pass
the mode argument and returns -EFSCORRUPTED if mode is invalid.
Callers that translate non zero mode to on-disk file type now
check the return value and will export the error to user instead
of staging an invalid file type to be written to directory entry.
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/xfs/xfs_iops.c | 48 |
1 files changed, 39 insertions, 9 deletions
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 1abe71918734..f5e0f608e245 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c | |||
@@ -98,12 +98,27 @@ xfs_init_security( | |||
98 | static void | 98 | static void |
99 | xfs_dentry_to_name( | 99 | xfs_dentry_to_name( |
100 | struct xfs_name *namep, | 100 | struct xfs_name *namep, |
101 | struct dentry *dentry) | ||
102 | { | ||
103 | namep->name = dentry->d_name.name; | ||
104 | namep->len = dentry->d_name.len; | ||
105 | namep->type = XFS_DIR3_FT_UNKNOWN; | ||
106 | } | ||
107 | |||
108 | static int | ||
109 | xfs_dentry_mode_to_name( | ||
110 | struct xfs_name *namep, | ||
101 | struct dentry *dentry, | 111 | struct dentry *dentry, |
102 | int mode) | 112 | int mode) |
103 | { | 113 | { |
104 | namep->name = dentry->d_name.name; | 114 | namep->name = dentry->d_name.name; |
105 | namep->len = dentry->d_name.len; | 115 | namep->len = dentry->d_name.len; |
106 | namep->type = xfs_mode_to_ftype(mode); | 116 | namep->type = xfs_mode_to_ftype(mode); |
117 | |||
118 | if (unlikely(namep->type == XFS_DIR3_FT_UNKNOWN)) | ||
119 | return -EFSCORRUPTED; | ||
120 | |||
121 | return 0; | ||
107 | } | 122 | } |
108 | 123 | ||
109 | STATIC void | 124 | STATIC void |
@@ -119,7 +134,7 @@ xfs_cleanup_inode( | |||
119 | * xfs_init_security we must back out. | 134 | * xfs_init_security we must back out. |
120 | * ENOSPC can hit here, among other things. | 135 | * ENOSPC can hit here, among other things. |
121 | */ | 136 | */ |
122 | xfs_dentry_to_name(&teardown, dentry, 0); | 137 | xfs_dentry_to_name(&teardown, dentry); |
123 | 138 | ||
124 | xfs_remove(XFS_I(dir), &teardown, XFS_I(inode)); | 139 | xfs_remove(XFS_I(dir), &teardown, XFS_I(inode)); |
125 | } | 140 | } |
@@ -154,8 +169,12 @@ xfs_generic_create( | |||
154 | if (error) | 169 | if (error) |
155 | return error; | 170 | return error; |
156 | 171 | ||
172 | /* Verify mode is valid also for tmpfile case */ | ||
173 | error = xfs_dentry_mode_to_name(&name, dentry, mode); | ||
174 | if (unlikely(error)) | ||
175 | goto out_free_acl; | ||
176 | |||
157 | if (!tmpfile) { | 177 | if (!tmpfile) { |
158 | xfs_dentry_to_name(&name, dentry, mode); | ||
159 | error = xfs_create(XFS_I(dir), &name, mode, rdev, &ip); | 178 | error = xfs_create(XFS_I(dir), &name, mode, rdev, &ip); |
160 | } else { | 179 | } else { |
161 | error = xfs_create_tmpfile(XFS_I(dir), dentry, mode, &ip); | 180 | error = xfs_create_tmpfile(XFS_I(dir), dentry, mode, &ip); |
@@ -248,7 +267,7 @@ xfs_vn_lookup( | |||
248 | if (dentry->d_name.len >= MAXNAMELEN) | 267 | if (dentry->d_name.len >= MAXNAMELEN) |
249 | return ERR_PTR(-ENAMETOOLONG); | 268 | return ERR_PTR(-ENAMETOOLONG); |
250 | 269 | ||
251 | xfs_dentry_to_name(&name, dentry, 0); | 270 | xfs_dentry_to_name(&name, dentry); |
252 | error = xfs_lookup(XFS_I(dir), &name, &cip, NULL); | 271 | error = xfs_lookup(XFS_I(dir), &name, &cip, NULL); |
253 | if (unlikely(error)) { | 272 | if (unlikely(error)) { |
254 | if (unlikely(error != -ENOENT)) | 273 | if (unlikely(error != -ENOENT)) |
@@ -275,7 +294,7 @@ xfs_vn_ci_lookup( | |||
275 | if (dentry->d_name.len >= MAXNAMELEN) | 294 | if (dentry->d_name.len >= MAXNAMELEN) |
276 | return ERR_PTR(-ENAMETOOLONG); | 295 | return ERR_PTR(-ENAMETOOLONG); |
277 | 296 | ||
278 | xfs_dentry_to_name(&xname, dentry, 0); | 297 | xfs_dentry_to_name(&xname, dentry); |
279 | error = xfs_lookup(XFS_I(dir), &xname, &ip, &ci_name); | 298 | error = xfs_lookup(XFS_I(dir), &xname, &ip, &ci_name); |
280 | if (unlikely(error)) { | 299 | if (unlikely(error)) { |
281 | if (unlikely(error != -ENOENT)) | 300 | if (unlikely(error != -ENOENT)) |
@@ -310,7 +329,9 @@ xfs_vn_link( | |||
310 | struct xfs_name name; | 329 | struct xfs_name name; |
311 | int error; | 330 | int error; |
312 | 331 | ||
313 | xfs_dentry_to_name(&name, dentry, inode->i_mode); | 332 | error = xfs_dentry_mode_to_name(&name, dentry, inode->i_mode); |
333 | if (unlikely(error)) | ||
334 | return error; | ||
314 | 335 | ||
315 | error = xfs_link(XFS_I(dir), XFS_I(inode), &name); | 336 | error = xfs_link(XFS_I(dir), XFS_I(inode), &name); |
316 | if (unlikely(error)) | 337 | if (unlikely(error)) |
@@ -329,7 +350,7 @@ xfs_vn_unlink( | |||
329 | struct xfs_name name; | 350 | struct xfs_name name; |
330 | int error; | 351 | int error; |
331 | 352 | ||
332 | xfs_dentry_to_name(&name, dentry, 0); | 353 | xfs_dentry_to_name(&name, dentry); |
333 | 354 | ||
334 | error = xfs_remove(XFS_I(dir), &name, XFS_I(d_inode(dentry))); | 355 | error = xfs_remove(XFS_I(dir), &name, XFS_I(d_inode(dentry))); |
335 | if (error) | 356 | if (error) |
@@ -359,7 +380,9 @@ xfs_vn_symlink( | |||
359 | 380 | ||
360 | mode = S_IFLNK | | 381 | mode = S_IFLNK | |
361 | (irix_symlink_mode ? 0777 & ~current_umask() : S_IRWXUGO); | 382 | (irix_symlink_mode ? 0777 & ~current_umask() : S_IRWXUGO); |
362 | xfs_dentry_to_name(&name, dentry, mode); | 383 | error = xfs_dentry_mode_to_name(&name, dentry, mode); |
384 | if (unlikely(error)) | ||
385 | goto out; | ||
363 | 386 | ||
364 | error = xfs_symlink(XFS_I(dir), &name, symname, mode, &cip); | 387 | error = xfs_symlink(XFS_I(dir), &name, symname, mode, &cip); |
365 | if (unlikely(error)) | 388 | if (unlikely(error)) |
@@ -395,6 +418,7 @@ xfs_vn_rename( | |||
395 | { | 418 | { |
396 | struct inode *new_inode = d_inode(ndentry); | 419 | struct inode *new_inode = d_inode(ndentry); |
397 | int omode = 0; | 420 | int omode = 0; |
421 | int error; | ||
398 | struct xfs_name oname; | 422 | struct xfs_name oname; |
399 | struct xfs_name nname; | 423 | struct xfs_name nname; |
400 | 424 | ||
@@ -405,8 +429,14 @@ xfs_vn_rename( | |||
405 | if (flags & RENAME_EXCHANGE) | 429 | if (flags & RENAME_EXCHANGE) |
406 | omode = d_inode(ndentry)->i_mode; | 430 | omode = d_inode(ndentry)->i_mode; |
407 | 431 | ||
408 | xfs_dentry_to_name(&oname, odentry, omode); | 432 | error = xfs_dentry_mode_to_name(&oname, odentry, omode); |
409 | xfs_dentry_to_name(&nname, ndentry, d_inode(odentry)->i_mode); | 433 | if (omode && unlikely(error)) |
434 | return error; | ||
435 | |||
436 | error = xfs_dentry_mode_to_name(&nname, ndentry, | ||
437 | d_inode(odentry)->i_mode); | ||
438 | if (unlikely(error)) | ||
439 | return error; | ||
410 | 440 | ||
411 | return xfs_rename(XFS_I(odir), &oname, XFS_I(d_inode(odentry)), | 441 | return xfs_rename(XFS_I(odir), &oname, XFS_I(d_inode(odentry)), |
412 | XFS_I(ndir), &nname, | 442 | XFS_I(ndir), &nname, |