summaryrefslogtreecommitdiffstats
path: root/fs/overlayfs/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/overlayfs/file.c')
-rw-r--r--fs/overlayfs/file.c101
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
412static unsigned int ovl_get_inode_flags(struct inode *inode) 409static 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
429static 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);
462unlock: 439unlock:
@@ -468,17 +445,79 @@ unlock:
468 445
469} 446}
470 447
448static 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
464static 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
476static 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
492static 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
471static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 505static 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: