From: Greg Kroah-Hartman Date: Sun, 1 Nov 2020 10:32:46 +0000 (+0100) Subject: 4.9-stable patches X-Git-Tag: v5.4.74~4 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4e7fa9e7a9677644a769f442afa7ef198b12d992;p=thirdparty%2Fkernel%2Fstable-queue.git 4.9-stable patches added patches: fscrypt-return-exdev-for-incompatible-rename-or-link-into-encrypted-dir.patch fscrypt-use-eexist-when-file-already-uses-different-policy.patch fscrypto-move-ioctl-processing-more-fully-into-common-code.patch --- diff --git a/queue-4.9/fscrypt-return-exdev-for-incompatible-rename-or-link-into-encrypted-dir.patch b/queue-4.9/fscrypt-return-exdev-for-incompatible-rename-or-link-into-encrypted-dir.patch new file mode 100644 index 00000000000..007b9b09d81 --- /dev/null +++ b/queue-4.9/fscrypt-return-exdev-for-incompatible-rename-or-link-into-encrypted-dir.patch @@ -0,0 +1,136 @@ +From f5e55e777cc93eae1416f0fa4908e8846b6d7825 Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Tue, 22 Jan 2019 16:20:21 -0800 +Subject: fscrypt: return -EXDEV for incompatible rename or link into encrypted dir + +From: Eric Biggers + +commit f5e55e777cc93eae1416f0fa4908e8846b6d7825 upstream. + +Currently, trying to rename or link a regular file, directory, or +symlink into an encrypted directory fails with EPERM when the source +file is unencrypted or is encrypted with a different encryption policy, +and is on the same mountpoint. It is correct for the operation to fail, +but the choice of EPERM breaks tools like 'mv' that know to copy rather +than rename if they see EXDEV, but don't know what to do with EPERM. + +Our original motivation for EPERM was to encourage users to securely +handle their data. Encrypting files by "moving" them into an encrypted +directory can be insecure because the unencrypted data may remain in +free space on disk, where it can later be recovered by an attacker. +It's much better to encrypt the data from the start, or at least try to +securely delete the source data e.g. using the 'shred' program. + +However, the current behavior hasn't been effective at achieving its +goal because users tend to be confused, hack around it, and complain; +see e.g. https://github.com/google/fscrypt/issues/76. And in some cases +it's actually inconsistent or unnecessary. For example, 'mv'-ing files +between differently encrypted directories doesn't work even in cases +where it can be secure, such as when in userspace the same passphrase +protects both directories. Yet, you *can* already 'mv' unencrypted +files into an encrypted directory if the source files are on a different +mountpoint, even though doing so is often insecure. + +There are probably better ways to teach users to securely handle their +files. For example, the 'fscrypt' userspace tool could provide a +command that migrates unencrypted files into an encrypted directory, +acting like 'shred' on the source files and providing appropriate +warnings depending on the type of the source filesystem and disk. + +Receiving errors on unimportant files might also force some users to +disable encryption, thus making the behavior counterproductive. It's +desirable to make encryption as unobtrusive as possible. + +Therefore, change the error code from EPERM to EXDEV so that tools +looking for EXDEV will fall back to a copy. + +This, of course, doesn't prevent users from still doing the right things +to securely manage their files. Note that this also matches the +behavior when a file is renamed between two project quota hierarchies; +so there's precedent for using EXDEV for things other than mountpoints. + +xfstests generic/398 will require an update with this change. + +[Rewritten from an earlier patch series by Michael Halcrow.] + +Cc: Michael Halcrow +Cc: Joe Richey +Signed-off-by: Eric Biggers +Signed-off-by: Greg Kroah-Hartman + +--- + fs/crypto/policy.c | 3 +-- + fs/ext4/namei.c | 6 +++--- + fs/f2fs/namei.c | 6 +++--- + 3 files changed, 7 insertions(+), 8 deletions(-) + +--- a/fs/crypto/policy.c ++++ b/fs/crypto/policy.c +@@ -180,8 +180,7 @@ EXPORT_SYMBOL(fscrypt_get_policy); + * malicious offline violations of this constraint, while the link and rename + * checks are needed to prevent online violations of this constraint. + * +- * Return: 1 if permitted, 0 if forbidden. If forbidden, the caller must fail +- * the filesystem operation with EPERM. ++ * Return: 1 if permitted, 0 if forbidden. + */ + int fscrypt_has_permitted_context(struct inode *parent, struct inode *child) + { +--- a/fs/ext4/namei.c ++++ b/fs/ext4/namei.c +@@ -3259,7 +3259,7 @@ static int ext4_link(struct dentry *old_ + return -EMLINK; + if (ext4_encrypted_inode(dir) && + !fscrypt_has_permitted_context(dir, inode)) +- return -EPERM; ++ return -EXDEV; + + if ((ext4_test_inode_flag(dir, EXT4_INODE_PROJINHERIT)) && + (!projid_eq(EXT4_I(dir)->i_projid, +@@ -3597,7 +3597,7 @@ static int ext4_rename(struct inode *old + if ((old.dir != new.dir) && + ext4_encrypted_inode(new.dir) && + !fscrypt_has_permitted_context(new.dir, old.inode)) { +- retval = -EPERM; ++ retval = -EXDEV; + goto end_rename; + } + +@@ -3776,7 +3776,7 @@ static int ext4_cross_rename(struct inod + (old_dir != new_dir) && + (!fscrypt_has_permitted_context(new_dir, old.inode) || + !fscrypt_has_permitted_context(old_dir, new.inode))) +- return -EPERM; ++ return -EXDEV; + + if ((ext4_test_inode_flag(new_dir, EXT4_INODE_PROJINHERIT) && + !projid_eq(EXT4_I(new_dir)->i_projid, +--- a/fs/f2fs/namei.c ++++ b/fs/f2fs/namei.c +@@ -177,7 +177,7 @@ static int f2fs_link(struct dentry *old_ + + if (f2fs_encrypted_inode(dir) && + !fscrypt_has_permitted_context(dir, inode)) +- return -EPERM; ++ return -EXDEV; + + f2fs_balance_fs(sbi, true); + +@@ -667,7 +667,7 @@ static int f2fs_rename(struct inode *old + + if ((old_dir != new_dir) && f2fs_encrypted_inode(new_dir) && + !fscrypt_has_permitted_context(new_dir, old_inode)) { +- err = -EPERM; ++ err = -EXDEV; + goto out; + } + +@@ -855,7 +855,7 @@ static int f2fs_cross_rename(struct inod + (old_dir != new_dir) && + (!fscrypt_has_permitted_context(new_dir, old_inode) || + !fscrypt_has_permitted_context(old_dir, new_inode))) +- return -EPERM; ++ return -EXDEV; + + old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page); + if (!old_entry) { diff --git a/queue-4.9/fscrypt-use-eexist-when-file-already-uses-different-policy.patch b/queue-4.9/fscrypt-use-eexist-when-file-already-uses-different-policy.patch new file mode 100644 index 00000000000..415c8d6b790 --- /dev/null +++ b/queue-4.9/fscrypt-use-eexist-when-file-already-uses-different-policy.patch @@ -0,0 +1,39 @@ +From 8488cd96ff88966ccb076e4f3654f59d84ba686d Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Mon, 5 Dec 2016 11:12:46 -0800 +Subject: fscrypt: use EEXIST when file already uses different policy + +From: Eric Biggers + +commit 8488cd96ff88966ccb076e4f3654f59d84ba686d upstream. + +As part of an effort to clean up fscrypt-related error codes, make +FS_IOC_SET_ENCRYPTION_POLICY fail with EEXIST when the file already uses +a different encryption policy. This is more descriptive than EINVAL, +which was ambiguous with some of the other error cases. + +I am not aware of any users who might be relying on the previous error +code of EINVAL, which was never documented anywhere. + +This failure case will be exercised by an xfstest. + +Signed-off-by: Eric Biggers +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman + + +--- + fs/crypto/policy.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/crypto/policy.c ++++ b/fs/crypto/policy.c +@@ -131,7 +131,7 @@ int fscrypt_ioctl_set_policy(struct file + printk(KERN_WARNING + "%s: Policy inconsistent with encryption context\n", + __func__); +- ret = -EINVAL; ++ ret = -EEXIST; + } + + inode_unlock(inode); diff --git a/queue-4.9/fscrypto-move-ioctl-processing-more-fully-into-common-code.patch b/queue-4.9/fscrypto-move-ioctl-processing-more-fully-into-common-code.patch new file mode 100644 index 00000000000..07a29470fa0 --- /dev/null +++ b/queue-4.9/fscrypto-move-ioctl-processing-more-fully-into-common-code.patch @@ -0,0 +1,255 @@ +From db717d8e26c2d1b0dba3e08668a1e6a7f665adde Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Sat, 26 Nov 2016 19:07:49 -0500 +Subject: fscrypto: move ioctl processing more fully into common code + +From: Eric Biggers + +commit db717d8e26c2d1b0dba3e08668a1e6a7f665adde upstream. + +Multiple bugs were recently fixed in the "set encryption policy" ioctl. +To make it clear that fscrypt_process_policy() and fscrypt_get_policy() +implement ioctls and therefore their implementations must take standard +security and correctness precautions, rename them to +fscrypt_ioctl_set_policy() and fscrypt_ioctl_get_policy(). Make the +latter take in a struct file * to make it consistent with the former. + +Signed-off-by: Eric Biggers +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman + + +--- + fs/crypto/policy.c | 34 +++++++++++++++++++++------------- + fs/ext4/ext4.h | 4 ++-- + fs/ext4/ioctl.c | 32 ++++---------------------------- + fs/f2fs/f2fs.h | 4 ++-- + fs/f2fs/file.c | 19 ++----------------- + include/linux/fscrypto.h | 12 ++++++------ + 6 files changed, 37 insertions(+), 68 deletions(-) + +--- a/fs/crypto/policy.c ++++ b/fs/crypto/policy.c +@@ -93,16 +93,19 @@ static int create_encryption_context_fro + return inode->i_sb->s_cop->set_context(inode, &ctx, sizeof(ctx), NULL); + } + +-int fscrypt_process_policy(struct file *filp, +- const struct fscrypt_policy *policy) ++int fscrypt_ioctl_set_policy(struct file *filp, const void __user *arg) + { ++ struct fscrypt_policy policy; + struct inode *inode = file_inode(filp); + int ret; + ++ if (copy_from_user(&policy, arg, sizeof(policy))) ++ return -EFAULT; ++ + if (!inode_owner_or_capable(inode)) + return -EACCES; + +- if (policy->version != 0) ++ if (policy.version != 0) + return -EINVAL; + + ret = mnt_want_write_file(filp); +@@ -122,9 +125,9 @@ int fscrypt_process_policy(struct file * + ret = -ENOTEMPTY; + else + ret = create_encryption_context_from_policy(inode, +- policy); ++ &policy); + } else if (!is_encryption_context_consistent_with_policy(inode, +- policy)) { ++ &policy)) { + printk(KERN_WARNING + "%s: Policy inconsistent with encryption context\n", + __func__); +@@ -136,11 +139,13 @@ int fscrypt_process_policy(struct file * + mnt_drop_write_file(filp); + return ret; + } +-EXPORT_SYMBOL(fscrypt_process_policy); ++EXPORT_SYMBOL(fscrypt_ioctl_set_policy); + +-int fscrypt_get_policy(struct inode *inode, struct fscrypt_policy *policy) ++int fscrypt_ioctl_get_policy(struct file *filp, void __user *arg) + { ++ struct inode *inode = file_inode(filp); + struct fscrypt_context ctx; ++ struct fscrypt_policy policy; + int res; + + if (!inode->i_sb->s_cop->get_context || +@@ -153,15 +158,18 @@ int fscrypt_get_policy(struct inode *ino + if (ctx.format != FS_ENCRYPTION_CONTEXT_FORMAT_V1) + return -EINVAL; + +- policy->version = 0; +- policy->contents_encryption_mode = ctx.contents_encryption_mode; +- policy->filenames_encryption_mode = ctx.filenames_encryption_mode; +- policy->flags = ctx.flags; +- memcpy(&policy->master_key_descriptor, ctx.master_key_descriptor, ++ policy.version = 0; ++ policy.contents_encryption_mode = ctx.contents_encryption_mode; ++ policy.filenames_encryption_mode = ctx.filenames_encryption_mode; ++ policy.flags = ctx.flags; ++ memcpy(policy.master_key_descriptor, ctx.master_key_descriptor, + FS_KEY_DESCRIPTOR_SIZE); ++ ++ if (copy_to_user(arg, &policy, sizeof(policy))) ++ return -EFAULT; + return 0; + } +-EXPORT_SYMBOL(fscrypt_get_policy); ++EXPORT_SYMBOL(fscrypt_ioctl_get_policy); + + /** + * fscrypt_has_permitted_context() - is a file's encryption policy permitted +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -2354,8 +2354,8 @@ static inline void ext4_fname_free_filen + #define fscrypt_pullback_bio_page fscrypt_notsupp_pullback_bio_page + #define fscrypt_restore_control_page fscrypt_notsupp_restore_control_page + #define fscrypt_zeroout_range fscrypt_notsupp_zeroout_range +-#define fscrypt_process_policy fscrypt_notsupp_process_policy +-#define fscrypt_get_policy fscrypt_notsupp_get_policy ++#define fscrypt_ioctl_set_policy fscrypt_notsupp_ioctl_set_policy ++#define fscrypt_ioctl_get_policy fscrypt_notsupp_ioctl_get_policy + #define fscrypt_has_permitted_context fscrypt_notsupp_has_permitted_context + #define fscrypt_inherit_context fscrypt_notsupp_inherit_context + #define fscrypt_get_encryption_info fscrypt_notsupp_get_encryption_info +--- a/fs/ext4/ioctl.c ++++ b/fs/ext4/ioctl.c +@@ -774,22 +774,12 @@ resizefs_out: + } + case EXT4_IOC_PRECACHE_EXTENTS: + return ext4_ext_precache(inode); +- case EXT4_IOC_SET_ENCRYPTION_POLICY: { +-#ifdef CONFIG_EXT4_FS_ENCRYPTION +- struct fscrypt_policy policy; + ++ case EXT4_IOC_SET_ENCRYPTION_POLICY: + if (!ext4_has_feature_encrypt(sb)) + return -EOPNOTSUPP; ++ return fscrypt_ioctl_set_policy(filp, (const void __user *)arg); + +- if (copy_from_user(&policy, +- (struct fscrypt_policy __user *)arg, +- sizeof(policy))) +- return -EFAULT; +- return fscrypt_process_policy(filp, &policy); +-#else +- return -EOPNOTSUPP; +-#endif +- } + case EXT4_IOC_GET_ENCRYPTION_PWSALT: { + int err, err2; + struct ext4_sb_info *sbi = EXT4_SB(sb); +@@ -826,23 +816,9 @@ resizefs_out: + return -EFAULT; + return 0; + } +- case EXT4_IOC_GET_ENCRYPTION_POLICY: { +-#ifdef CONFIG_EXT4_FS_ENCRYPTION +- struct fscrypt_policy policy; +- int err = 0; ++ case EXT4_IOC_GET_ENCRYPTION_POLICY: ++ return fscrypt_ioctl_get_policy(filp, (void __user *)arg); + +- if (!ext4_encrypted_inode(inode)) +- return -ENOENT; +- err = fscrypt_get_policy(inode, &policy); +- if (err) +- return err; +- if (copy_to_user((void __user *)arg, &policy, sizeof(policy))) +- return -EFAULT; +- return 0; +-#else +- return -EOPNOTSUPP; +-#endif +- } + case EXT4_IOC_FSGETXATTR: + { + struct fsxattr fa; +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -2513,8 +2513,8 @@ static inline bool f2fs_may_encrypt(stru + #define fscrypt_pullback_bio_page fscrypt_notsupp_pullback_bio_page + #define fscrypt_restore_control_page fscrypt_notsupp_restore_control_page + #define fscrypt_zeroout_range fscrypt_notsupp_zeroout_range +-#define fscrypt_process_policy fscrypt_notsupp_process_policy +-#define fscrypt_get_policy fscrypt_notsupp_get_policy ++#define fscrypt_ioctl_set_policy fscrypt_notsupp_ioctl_set_policy ++#define fscrypt_ioctl_get_policy fscrypt_notsupp_ioctl_get_policy + #define fscrypt_has_permitted_context fscrypt_notsupp_has_permitted_context + #define fscrypt_inherit_context fscrypt_notsupp_inherit_context + #define fscrypt_get_encryption_info fscrypt_notsupp_get_encryption_info +--- a/fs/f2fs/file.c ++++ b/fs/f2fs/file.c +@@ -1774,31 +1774,16 @@ static bool uuid_is_nonzero(__u8 u[16]) + + static int f2fs_ioc_set_encryption_policy(struct file *filp, unsigned long arg) + { +- struct fscrypt_policy policy; + struct inode *inode = file_inode(filp); + +- if (copy_from_user(&policy, (struct fscrypt_policy __user *)arg, +- sizeof(policy))) +- return -EFAULT; +- + f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); + +- return fscrypt_process_policy(filp, &policy); ++ return fscrypt_ioctl_set_policy(filp, (const void __user *)arg); + } + + static int f2fs_ioc_get_encryption_policy(struct file *filp, unsigned long arg) + { +- struct fscrypt_policy policy; +- struct inode *inode = file_inode(filp); +- int err; +- +- err = fscrypt_get_policy(inode, &policy); +- if (err) +- return err; +- +- if (copy_to_user((struct fscrypt_policy __user *)arg, &policy, sizeof(policy))) +- return -EFAULT; +- return 0; ++ return fscrypt_ioctl_get_policy(filp, (void __user *)arg); + } + + static int f2fs_ioc_get_encryption_pwsalt(struct file *filp, unsigned long arg) +--- a/include/linux/fscrypto.h ++++ b/include/linux/fscrypto.h +@@ -249,8 +249,8 @@ extern void fscrypt_restore_control_page + extern int fscrypt_zeroout_range(struct inode *, pgoff_t, sector_t, + unsigned int); + /* policy.c */ +-extern int fscrypt_process_policy(struct file *, const struct fscrypt_policy *); +-extern int fscrypt_get_policy(struct inode *, struct fscrypt_policy *); ++extern int fscrypt_ioctl_set_policy(struct file *, const void __user *); ++extern int fscrypt_ioctl_get_policy(struct file *, void __user *); + extern int fscrypt_has_permitted_context(struct inode *, struct inode *); + extern int fscrypt_inherit_context(struct inode *, struct inode *, + void *, bool); +@@ -318,14 +318,14 @@ static inline int fscrypt_notsupp_zeroou + } + + /* policy.c */ +-static inline int fscrypt_notsupp_process_policy(struct file *f, +- const struct fscrypt_policy *p) ++static inline int fscrypt_notsupp_ioctl_set_policy(struct file *f, ++ const void __user *arg) + { + return -EOPNOTSUPP; + } + +-static inline int fscrypt_notsupp_get_policy(struct inode *i, +- struct fscrypt_policy *p) ++static inline int fscrypt_notsupp_ioctl_get_policy(struct file *f, ++ void __user *arg) + { + return -EOPNOTSUPP; + } diff --git a/queue-4.9/series b/queue-4.9/series index 2cafdd82dda..9ac4b81bbaa 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -9,3 +9,6 @@ fuse-fix-page-dereference-after-free.patch p54-avoid-accessing-the-data-mapped-to-streaming-dma.patch mtd-lpddr-fix-bad-logic-in-print_drs_error.patch ata-sata_rcar-fix-dma-boundary-mask.patch +fscrypt-return-exdev-for-incompatible-rename-or-link-into-encrypted-dir.patch +fscrypto-move-ioctl-processing-more-fully-into-common-code.patch +fscrypt-use-eexist-when-file-already-uses-different-policy.patch