static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { long ret; struct inode *inode = file_inode(file); switch (cmd) { case FS_IOC_GETFLAGS: ret = ovl_real_ioctl(file, cmd, arg); break; case FS_IOC_SETFLAGS: if (!inode_owner_or_capable(inode)) return -EACCES; ret = mnt_want_write_file(file); if (ret) return ret; ret = ovl_copy_up_with_data(file_dentry(file)); if (!ret) { ret = ovl_real_ioctl(file, cmd, arg); inode_lock(inode); ovl_copyflags(ovl_inode_real(inode), inode); inode_unlock(inode); } mnt_drop_write_file(file); break; default: ret = -ENOTTY; } return ret; }
static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { long ret; switch (cmd) { case FS_IOC_GETFLAGS: ret = ovl_real_ioctl(file, cmd, arg); break; case FS_IOC_SETFLAGS: ret = ovl_ioctl_set_flags(file, arg); break; default: ret = -ENOTTY; } return ret; }
static long ovl_ioctl_set_flags(struct file *file, unsigned long arg) { long ret; struct inode *inode = file_inode(file); unsigned int flags; unsigned int old_flags; if (!inode_owner_or_capable(inode)) return -EACCES; if (get_user(flags, (int __user *) arg)) return -EFAULT; ret = mnt_want_write_file(file); if (ret) return ret; inode_lock(inode); /* Check the capability before cred override */ ret = -EPERM; old_flags = ovl_get_inode_flags(inode); if (((flags ^ old_flags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) && !capable(CAP_LINUX_IMMUTABLE)) goto unlock; ret = ovl_maybe_copy_up(file_dentry(file), O_WRONLY); if (ret) goto unlock; ret = ovl_real_ioctl(file, FS_IOC_SETFLAGS, arg); ovl_copyflags(ovl_inode_real(inode), inode); unlock: inode_unlock(inode); mnt_drop_write_file(file); return ret; }