--- /dev/null
+From f5e55e777cc93eae1416f0fa4908e8846b6d7825 Mon Sep 17 00:00:00 2001
+From: Eric Biggers <ebiggers@google.com>
+Date: Tue, 22 Jan 2019 16:20:21 -0800
+Subject: fscrypt: return -EXDEV for incompatible rename or link into encrypted dir
+
+From: Eric Biggers <ebiggers@google.com>
+
+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 <mhalcrow@google.com>
+Cc: Joe Richey <joerichey@google.com>
+Signed-off-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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) {
--- /dev/null
+From db717d8e26c2d1b0dba3e08668a1e6a7f665adde Mon Sep 17 00:00:00 2001
+From: Eric Biggers <ebiggers@google.com>
+Date: Sat, 26 Nov 2016 19:07:49 -0500
+Subject: fscrypto: move ioctl processing more fully into common code
+
+From: Eric Biggers <ebiggers@google.com>
+
+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 <ebiggers@google.com>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ 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;
+ }