diff options
| author | Amir Goldstein <amir73il@gmail.com> | 2017-01-17 14:41:44 -0500 |
|---|---|---|
| committer | Darrick J. Wong <darrick.wong@oracle.com> | 2017-01-17 14:42:22 -0500 |
| commit | fab8eef86c814c3dd46bc5d760b6e4a53d5fc5a6 (patch) | |
| tree | d34fab3b0f9f5793aa599e8f7a63399fadbbc129 /fs | |
| parent | 1fc4d33fed124fb182e8e6c214e973a29389ae83 (diff) | |
xfs: sanity check inode mode when creating new dentry
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>
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 821f08d4e256..22c16155f1b4 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, |
