diff options
| author | Amir Goldstein <amir73il@gmail.com> | 2019-06-11 11:09:28 -0400 |
|---|---|---|
| committer | Miklos Szeredi <mszeredi@redhat.com> | 2019-06-11 11:17:41 -0400 |
| commit | 941d935ac7636911a3fd8fa80e758e52b0b11e20 (patch) | |
| tree | 54fdae5004d26421871f47ef8980bb334dd25bdf | |
| parent | d1fdb6d8f6a4109a4263176c84b899076a5f8008 (diff) | |
ovl: fix wrong flags check in FS_IOC_FS[SG]ETXATTR ioctls
The ioctl argument was parsed as the wrong type.
Fixes: b21d9c435f93 ("ovl: support the FS_IOC_FS[SG]ETXATTR ioctls")
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
| -rw-r--r-- | fs/overlayfs/file.c | 91 |
1 files changed, 65 insertions, 26 deletions
diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c index 340a6ad45914..75d8d00fa087 100644 --- a/fs/overlayfs/file.c +++ b/fs/overlayfs/file.c | |||
| @@ -409,37 +409,16 @@ static long ovl_real_ioctl(struct file *file, unsigned int cmd, | |||
| 409 | return ret; | 409 | return ret; |
| 410 | } | 410 | } |
| 411 | 411 | ||
| 412 | static unsigned int ovl_get_inode_flags(struct inode *inode) | ||
| 413 | { | ||
| 414 | unsigned int flags = READ_ONCE(inode->i_flags); | ||
| 415 | unsigned int ovl_iflags = 0; | ||
| 416 | |||
| 417 | if (flags & S_SYNC) | ||
| 418 | ovl_iflags |= FS_SYNC_FL; | ||
| 419 | if (flags & S_APPEND) | ||
| 420 | ovl_iflags |= FS_APPEND_FL; | ||
| 421 | if (flags & S_IMMUTABLE) | ||
| 422 | ovl_iflags |= FS_IMMUTABLE_FL; | ||
| 423 | if (flags & S_NOATIME) | ||
| 424 | ovl_iflags |= FS_NOATIME_FL; | ||
| 425 | |||
| 426 | return ovl_iflags; | ||
| 427 | } | ||
| 428 | |||
| 429 | static long ovl_ioctl_set_flags(struct file *file, unsigned int cmd, | 412 | static long ovl_ioctl_set_flags(struct file *file, unsigned int cmd, |
| 430 | unsigned long arg) | 413 | unsigned long arg, unsigned int iflags) |
| 431 | { | 414 | { |
| 432 | long ret; | 415 | long ret; |
| 433 | struct inode *inode = file_inode(file); | 416 | struct inode *inode = file_inode(file); |
| 434 | unsigned int flags; | 417 | unsigned int old_iflags; |
| 435 | unsigned int old_flags; | ||
| 436 | 418 | ||
| 437 | if (!inode_owner_or_capable(inode)) | 419 | if (!inode_owner_or_capable(inode)) |
| 438 | return -EACCES; | 420 | return -EACCES; |
| 439 | 421 | ||
| 440 | if (get_user(flags, (int __user *) arg)) | ||
| 441 | return -EFAULT; | ||
| 442 | |||
| 443 | ret = mnt_want_write_file(file); | 422 | ret = mnt_want_write_file(file); |
| 444 | if (ret) | 423 | if (ret) |
| 445 | return ret; | 424 | return ret; |
| @@ -448,8 +427,8 @@ static long ovl_ioctl_set_flags(struct file *file, unsigned int cmd, | |||
| 448 | 427 | ||
| 449 | /* Check the capability before cred override */ | 428 | /* Check the capability before cred override */ |
| 450 | ret = -EPERM; | 429 | ret = -EPERM; |
| 451 | old_flags = ovl_get_inode_flags(inode); | 430 | old_iflags = READ_ONCE(inode->i_flags); |
| 452 | if (((flags ^ old_flags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) && | 431 | if (((iflags ^ old_iflags) & (S_APPEND | S_IMMUTABLE)) && |
| 453 | !capable(CAP_LINUX_IMMUTABLE)) | 432 | !capable(CAP_LINUX_IMMUTABLE)) |
| 454 | goto unlock; | 433 | goto unlock; |
| 455 | 434 | ||
| @@ -469,6 +448,63 @@ unlock: | |||
| 469 | 448 | ||
| 470 | } | 449 | } |
| 471 | 450 | ||
| 451 | static unsigned int ovl_fsflags_to_iflags(unsigned int flags) | ||
| 452 | { | ||
| 453 | unsigned int iflags = 0; | ||
| 454 | |||
| 455 | if (flags & FS_SYNC_FL) | ||
| 456 | iflags |= S_SYNC; | ||
| 457 | if (flags & FS_APPEND_FL) | ||
| 458 | iflags |= S_APPEND; | ||
| 459 | if (flags & FS_IMMUTABLE_FL) | ||
| 460 | iflags |= S_IMMUTABLE; | ||
| 461 | if (flags & FS_NOATIME_FL) | ||
| 462 | iflags |= S_NOATIME; | ||
| 463 | |||
| 464 | return iflags; | ||
| 465 | } | ||
| 466 | |||
| 467 | static long ovl_ioctl_set_fsflags(struct file *file, unsigned int cmd, | ||
| 468 | unsigned long arg) | ||
| 469 | { | ||
| 470 | unsigned int flags; | ||
| 471 | |||
| 472 | if (get_user(flags, (int __user *) arg)) | ||
| 473 | return -EFAULT; | ||
| 474 | |||
| 475 | return ovl_ioctl_set_flags(file, cmd, arg, | ||
| 476 | ovl_fsflags_to_iflags(flags)); | ||
| 477 | } | ||
| 478 | |||
| 479 | static unsigned int ovl_fsxflags_to_iflags(unsigned int xflags) | ||
| 480 | { | ||
| 481 | unsigned int iflags = 0; | ||
| 482 | |||
| 483 | if (xflags & FS_XFLAG_SYNC) | ||
| 484 | iflags |= S_SYNC; | ||
| 485 | if (xflags & FS_XFLAG_APPEND) | ||
| 486 | iflags |= S_APPEND; | ||
| 487 | if (xflags & FS_XFLAG_IMMUTABLE) | ||
| 488 | iflags |= S_IMMUTABLE; | ||
| 489 | if (xflags & FS_XFLAG_NOATIME) | ||
| 490 | iflags |= S_NOATIME; | ||
| 491 | |||
| 492 | return iflags; | ||
| 493 | } | ||
| 494 | |||
| 495 | static long ovl_ioctl_set_fsxflags(struct file *file, unsigned int cmd, | ||
| 496 | unsigned long arg) | ||
| 497 | { | ||
| 498 | struct fsxattr fa; | ||
| 499 | |||
| 500 | memset(&fa, 0, sizeof(fa)); | ||
| 501 | if (copy_from_user(&fa, (void __user *) arg, sizeof(fa))) | ||
| 502 | return -EFAULT; | ||
| 503 | |||
| 504 | return ovl_ioctl_set_flags(file, cmd, arg, | ||
| 505 | ovl_fsxflags_to_iflags(fa.fsx_xflags)); | ||
| 506 | } | ||
| 507 | |||
| 472 | static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 508 | static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
| 473 | { | 509 | { |
| 474 | long ret; | 510 | long ret; |
| @@ -480,8 +516,11 @@ static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
| 480 | break; | 516 | break; |
| 481 | 517 | ||
| 482 | case FS_IOC_SETFLAGS: | 518 | case FS_IOC_SETFLAGS: |
| 519 | ret = ovl_ioctl_set_fsflags(file, cmd, arg); | ||
| 520 | break; | ||
| 521 | |||
| 483 | case FS_IOC_FSSETXATTR: | 522 | case FS_IOC_FSSETXATTR: |
| 484 | ret = ovl_ioctl_set_flags(file, cmd, arg); | 523 | ret = ovl_ioctl_set_fsxflags(file, cmd, arg); |
| 485 | break; | 524 | break; |
| 486 | 525 | ||
| 487 | default: | 526 | default: |
