From: Greg Kroah-Hartman Date: Thu, 13 Jun 2019 07:55:07 +0000 (+0200) Subject: 5.1-stable patches X-Git-Tag: v5.1.10~8 X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fkernel%2Fstable-queue.git;a=commitdiff_plain;h=9208eabb610dae7d5a3f29d05fb7a28454932d55 5.1-stable patches added patches: ovl-check-the-capability-before-cred-overridden.patch ovl-support-stacked-seek_hole-seek_data.patch --- diff --git a/queue-5.1/ovl-check-the-capability-before-cred-overridden.patch b/queue-5.1/ovl-check-the-capability-before-cred-overridden.patch new file mode 100644 index 0000000000..61ba1288ca --- /dev/null +++ b/queue-5.1/ovl-check-the-capability-before-cred-overridden.patch @@ -0,0 +1,141 @@ +From 98487de318a6f33312471ae1e2afa16fbf8361fe Mon Sep 17 00:00:00 2001 +From: Jiufei Xue +Date: Mon, 6 May 2019 15:41:02 +0800 +Subject: ovl: check the capability before cred overridden + +From: Jiufei Xue + +commit 98487de318a6f33312471ae1e2afa16fbf8361fe upstream. + +We found that it return success when we set IMMUTABLE_FL flag to a file in +docker even though the docker didn't have the capability +CAP_LINUX_IMMUTABLE. + +The commit d1d04ef8572b ("ovl: stack file ops") and dab5ca8fd9dd ("ovl: add +lsattr/chattr support") implemented chattr operations on a regular overlay +file. ovl_real_ioctl() overridden the current process's subjective +credentials with ofs->creator_cred which have the capability +CAP_LINUX_IMMUTABLE so that it will return success in +vfs_ioctl()->cap_capable(). + +Fix this by checking the capability before cred overridden. And here we +only care about APPEND_FL and IMMUTABLE_FL, so get these information from +inode. + +[SzM: move check and call to underlying fs inside inode locked region to +prevent two such calls from racing with each other] + +Signed-off-by: Jiufei Xue +Signed-off-by: Miklos Szeredi +Cc: Amir Goldstein +Signed-off-by: Greg Kroah-Hartman + +--- + fs/overlayfs/file.c | 79 ++++++++++++++++++++++++++++++++++++++++------------ + 1 file changed, 61 insertions(+), 18 deletions(-) + +--- a/fs/overlayfs/file.c ++++ b/fs/overlayfs/file.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include "overlayfs.h" + + static char ovl_whatisit(struct inode *inode, struct inode *realinode) +@@ -372,10 +373,68 @@ static long ovl_real_ioctl(struct file * + return ret; + } + +-static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++static unsigned int ovl_get_inode_flags(struct inode *inode) ++{ ++ unsigned int flags = READ_ONCE(inode->i_flags); ++ unsigned int ovl_iflags = 0; ++ ++ if (flags & S_SYNC) ++ ovl_iflags |= FS_SYNC_FL; ++ if (flags & S_APPEND) ++ ovl_iflags |= FS_APPEND_FL; ++ if (flags & S_IMMUTABLE) ++ ovl_iflags |= FS_IMMUTABLE_FL; ++ if (flags & S_NOATIME) ++ ovl_iflags |= FS_NOATIME_FL; ++ ++ return ovl_iflags; ++} ++ ++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; ++ ++} ++ ++static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long ret; + + switch (cmd) { + case FS_IOC_GETFLAGS: +@@ -383,23 +442,7 @@ static long ovl_ioctl(struct file *file, + 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_maybe_copy_up(file_dentry(file), O_WRONLY); +- 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); ++ ret = ovl_ioctl_set_flags(file, arg); + break; + + default: diff --git a/queue-5.1/ovl-support-stacked-seek_hole-seek_data.patch b/queue-5.1/ovl-support-stacked-seek_hole-seek_data.patch new file mode 100644 index 0000000000..ed7f2346c6 --- /dev/null +++ b/queue-5.1/ovl-support-stacked-seek_hole-seek_data.patch @@ -0,0 +1,82 @@ +From 9e46b840c7053b5f7a245e98cd239b60d189a96c Mon Sep 17 00:00:00 2001 +From: Amir Goldstein +Date: Wed, 27 Feb 2019 13:32:11 +0200 +Subject: ovl: support stacked SEEK_HOLE/SEEK_DATA + +From: Amir Goldstein + +commit 9e46b840c7053b5f7a245e98cd239b60d189a96c upstream. + +Overlay file f_pos is the master copy that is preserved +through copy up and modified on read/write, but only real +fs knows how to SEEK_HOLE/SEEK_DATA and real fs may impose +limitations that are more strict than ->s_maxbytes for specific +files, so we use the real file to perform seeks. + +We do not call real fs for SEEK_CUR:0 query and for SEEK_SET:0 +requests. + +Fixes: d1d04ef8572b ("ovl: stack file ops") +Reported-by: Eddie Horng +Signed-off-by: Amir Goldstein +Signed-off-by: Miklos Szeredi +Signed-off-by: Greg Kroah-Hartman + +--- + fs/overlayfs/file.c | 44 ++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 40 insertions(+), 4 deletions(-) + +--- a/fs/overlayfs/file.c ++++ b/fs/overlayfs/file.c +@@ -146,11 +146,47 @@ static int ovl_release(struct inode *ino + + static loff_t ovl_llseek(struct file *file, loff_t offset, int whence) + { +- struct inode *realinode = ovl_inode_real(file_inode(file)); ++ struct inode *inode = file_inode(file); ++ struct fd real; ++ const struct cred *old_cred; ++ ssize_t ret; + +- return generic_file_llseek_size(file, offset, whence, +- realinode->i_sb->s_maxbytes, +- i_size_read(realinode)); ++ /* ++ * The two special cases below do not need to involve real fs, ++ * so we can optimizing concurrent callers. ++ */ ++ if (offset == 0) { ++ if (whence == SEEK_CUR) ++ return file->f_pos; ++ ++ if (whence == SEEK_SET) ++ return vfs_setpos(file, 0, 0); ++ } ++ ++ ret = ovl_real_fdget(file, &real); ++ if (ret) ++ return ret; ++ ++ /* ++ * Overlay file f_pos is the master copy that is preserved ++ * through copy up and modified on read/write, but only real ++ * fs knows how to SEEK_HOLE/SEEK_DATA and real fs may impose ++ * limitations that are more strict than ->s_maxbytes for specific ++ * files, so we use the real file to perform seeks. ++ */ ++ inode_lock(inode); ++ real.file->f_pos = file->f_pos; ++ ++ old_cred = ovl_override_creds(inode->i_sb); ++ ret = vfs_llseek(real.file, offset, whence); ++ revert_creds(old_cred); ++ ++ file->f_pos = real.file->f_pos; ++ inode_unlock(inode); ++ ++ fdput(real); ++ ++ return ret; + } + + static void ovl_file_accessed(struct file *file) diff --git a/queue-5.1/series b/queue-5.1/series index 2d542a4066..3102370abe 100644 --- a/queue-5.1/series +++ b/queue-5.1/series @@ -151,3 +151,5 @@ gpio-vf610-do-not-share-irq_chip.patch percpu-do-not-search-past-bitmap-when-allocating-an-.patch revert-bluetooth-align-minimum-encryption-key-size-for-le-and-br-edr-connections.patch revert-drm-nouveau-add-kconfig-option-to-turn-off-nouveau-legacy-contexts.-v3.patch +ovl-check-the-capability-before-cred-overridden.patch +ovl-support-stacked-seek_hole-seek_data.patch