diff options
Diffstat (limited to 'fs/overlayfs/file.c')
| -rw-r--r-- | fs/overlayfs/file.c | 101 |
1 files changed, 70 insertions, 31 deletions
diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c index 540a8b845145..e235a635d9ec 100644 --- a/fs/overlayfs/file.c +++ b/fs/overlayfs/file.c | |||
| @@ -1,9 +1,6 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-only | ||
| 1 | /* | 2 | /* |
| 2 | * Copyright (C) 2017 Red Hat, Inc. | 3 | * Copyright (C) 2017 Red Hat, Inc. |
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms of the GNU General Public License version 2 as published by | ||
| 6 | * the Free Software Foundation. | ||
| 7 | */ | 4 | */ |
| 8 | 5 | ||
| 9 | #include <linux/cred.h> | 6 | #include <linux/cred.h> |
| @@ -409,36 +406,16 @@ static long ovl_real_ioctl(struct file *file, unsigned int cmd, | |||
| 409 | return ret; | 406 | return ret; |
| 410 | } | 407 | } |
| 411 | 408 | ||
| 412 | static unsigned int ovl_get_inode_flags(struct inode *inode) | 409 | static long ovl_ioctl_set_flags(struct file *file, unsigned int cmd, |
| 413 | { | 410 | unsigned long arg, unsigned int iflags) |
| 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 long arg) | ||
| 430 | { | 411 | { |
| 431 | long ret; | 412 | long ret; |
| 432 | struct inode *inode = file_inode(file); | 413 | struct inode *inode = file_inode(file); |
| 433 | unsigned int flags; | 414 | unsigned int old_iflags; |
| 434 | unsigned int old_flags; | ||
| 435 | 415 | ||
| 436 | if (!inode_owner_or_capable(inode)) | 416 | if (!inode_owner_or_capable(inode)) |
| 437 | return -EACCES; | 417 | return -EACCES; |
| 438 | 418 | ||
| 439 | if (get_user(flags, (int __user *) arg)) | ||
| 440 | return -EFAULT; | ||
| 441 | |||
| 442 | ret = mnt_want_write_file(file); | 419 | ret = mnt_want_write_file(file); |
| 443 | if (ret) | 420 | if (ret) |
| 444 | return ret; | 421 | return ret; |
| @@ -447,8 +424,8 @@ static long ovl_ioctl_set_flags(struct file *file, unsigned long arg) | |||
| 447 | 424 | ||
| 448 | /* Check the capability before cred override */ | 425 | /* Check the capability before cred override */ |
| 449 | ret = -EPERM; | 426 | ret = -EPERM; |
| 450 | old_flags = ovl_get_inode_flags(inode); | 427 | old_iflags = READ_ONCE(inode->i_flags); |
| 451 | if (((flags ^ old_flags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) && | 428 | if (((iflags ^ old_iflags) & (S_APPEND | S_IMMUTABLE)) && |
| 452 | !capable(CAP_LINUX_IMMUTABLE)) | 429 | !capable(CAP_LINUX_IMMUTABLE)) |
| 453 | goto unlock; | 430 | goto unlock; |
| 454 | 431 | ||
| @@ -456,7 +433,7 @@ static long ovl_ioctl_set_flags(struct file *file, unsigned long arg) | |||
| 456 | if (ret) | 433 | if (ret) |
| 457 | goto unlock; | 434 | goto unlock; |
| 458 | 435 | ||
| 459 | ret = ovl_real_ioctl(file, FS_IOC_SETFLAGS, arg); | 436 | ret = ovl_real_ioctl(file, cmd, arg); |
| 460 | 437 | ||
| 461 | ovl_copyflags(ovl_inode_real(inode), inode); | 438 | ovl_copyflags(ovl_inode_real(inode), inode); |
| 462 | unlock: | 439 | unlock: |
| @@ -468,17 +445,79 @@ unlock: | |||
| 468 | 445 | ||
| 469 | } | 446 | } |
| 470 | 447 | ||
| 448 | static unsigned int ovl_fsflags_to_iflags(unsigned int flags) | ||
| 449 | { | ||
| 450 | unsigned int iflags = 0; | ||
| 451 | |||
| 452 | if (flags & FS_SYNC_FL) | ||
| 453 | iflags |= S_SYNC; | ||
| 454 | if (flags & FS_APPEND_FL) | ||
| 455 | iflags |= S_APPEND; | ||
| 456 | if (flags & FS_IMMUTABLE_FL) | ||
| 457 | iflags |= S_IMMUTABLE; | ||
| 458 | if (flags & FS_NOATIME_FL) | ||
| 459 | iflags |= S_NOATIME; | ||
| 460 | |||
| 461 | return iflags; | ||
| 462 | } | ||
| 463 | |||
| 464 | static long ovl_ioctl_set_fsflags(struct file *file, unsigned int cmd, | ||
| 465 | unsigned long arg) | ||
| 466 | { | ||
| 467 | unsigned int flags; | ||
| 468 | |||
| 469 | if (get_user(flags, (int __user *) arg)) | ||
| 470 | return -EFAULT; | ||
| 471 | |||
| 472 | return ovl_ioctl_set_flags(file, cmd, arg, | ||
| 473 | ovl_fsflags_to_iflags(flags)); | ||
| 474 | } | ||
| 475 | |||
| 476 | static unsigned int ovl_fsxflags_to_iflags(unsigned int xflags) | ||
| 477 | { | ||
| 478 | unsigned int iflags = 0; | ||
| 479 | |||
| 480 | if (xflags & FS_XFLAG_SYNC) | ||
| 481 | iflags |= S_SYNC; | ||
| 482 | if (xflags & FS_XFLAG_APPEND) | ||
| 483 | iflags |= S_APPEND; | ||
| 484 | if (xflags & FS_XFLAG_IMMUTABLE) | ||
| 485 | iflags |= S_IMMUTABLE; | ||
| 486 | if (xflags & FS_XFLAG_NOATIME) | ||
| 487 | iflags |= S_NOATIME; | ||
| 488 | |||
| 489 | return iflags; | ||
| 490 | } | ||
| 491 | |||
| 492 | static long ovl_ioctl_set_fsxflags(struct file *file, unsigned int cmd, | ||
| 493 | unsigned long arg) | ||
| 494 | { | ||
| 495 | struct fsxattr fa; | ||
| 496 | |||
| 497 | memset(&fa, 0, sizeof(fa)); | ||
| 498 | if (copy_from_user(&fa, (void __user *) arg, sizeof(fa))) | ||
| 499 | return -EFAULT; | ||
| 500 | |||
| 501 | return ovl_ioctl_set_flags(file, cmd, arg, | ||
| 502 | ovl_fsxflags_to_iflags(fa.fsx_xflags)); | ||
| 503 | } | ||
| 504 | |||
| 471 | static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 505 | static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
| 472 | { | 506 | { |
| 473 | long ret; | 507 | long ret; |
| 474 | 508 | ||
| 475 | switch (cmd) { | 509 | switch (cmd) { |
| 476 | case FS_IOC_GETFLAGS: | 510 | case FS_IOC_GETFLAGS: |
| 511 | case FS_IOC_FSGETXATTR: | ||
| 477 | ret = ovl_real_ioctl(file, cmd, arg); | 512 | ret = ovl_real_ioctl(file, cmd, arg); |
| 478 | break; | 513 | break; |
| 479 | 514 | ||
| 480 | case FS_IOC_SETFLAGS: | 515 | case FS_IOC_SETFLAGS: |
| 481 | ret = ovl_ioctl_set_flags(file, arg); | 516 | ret = ovl_ioctl_set_fsflags(file, cmd, arg); |
| 517 | break; | ||
| 518 | |||
| 519 | case FS_IOC_FSSETXATTR: | ||
| 520 | ret = ovl_ioctl_set_fsxflags(file, cmd, arg); | ||
| 482 | break; | 521 | break; |
| 483 | 522 | ||
| 484 | default: | 523 | default: |
