aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@google.com>2016-09-08 17:20:38 -0400
committerTheodore Ts'o <tytso@mit.edu>2016-09-10 01:18:57 -0400
commitba63f23d69a3a10e7e527a02702023da68ef8a6d (patch)
treeef70ece0179f4d642e0b0b4d5f6aa6cfed7c9e74 /fs
parent002ced4be6429918800ce3e41d5cbc2d7c01822c (diff)
fscrypto: require write access to mount to set encryption policy
Since setting an encryption policy requires writing metadata to the filesystem, it should be guarded by mnt_want_write/mnt_drop_write. Otherwise, a user could cause a write to a frozen or readonly filesystem. This was handled correctly by f2fs but not by ext4. Make fscrypt_process_policy() handle it rather than relying on the filesystem to get it right. Signed-off-by: Eric Biggers <ebiggers@google.com> Cc: stable@vger.kernel.org # 4.1+; check fs/{ext4,f2fs} Signed-off-by: Theodore Ts'o <tytso@mit.edu> Acked-by: Jaegeuk Kim <jaegeuk@kernel.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/crypto/policy.c38
-rw-r--r--fs/ext4/ioctl.c2
-rw-r--r--fs/f2fs/file.c9
3 files changed, 27 insertions, 22 deletions
diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c
index f96547f83cab..ed115acb5dee 100644
--- a/fs/crypto/policy.c
+++ b/fs/crypto/policy.c
@@ -11,6 +11,7 @@
11#include <linux/random.h> 11#include <linux/random.h>
12#include <linux/string.h> 12#include <linux/string.h>
13#include <linux/fscrypto.h> 13#include <linux/fscrypto.h>
14#include <linux/mount.h>
14 15
15static int inode_has_encryption_context(struct inode *inode) 16static int inode_has_encryption_context(struct inode *inode)
16{ 17{
@@ -92,31 +93,42 @@ static int create_encryption_context_from_policy(struct inode *inode,
92 return inode->i_sb->s_cop->set_context(inode, &ctx, sizeof(ctx), NULL); 93 return inode->i_sb->s_cop->set_context(inode, &ctx, sizeof(ctx), NULL);
93} 94}
94 95
95int fscrypt_process_policy(struct inode *inode, 96int fscrypt_process_policy(struct file *filp,
96 const struct fscrypt_policy *policy) 97 const struct fscrypt_policy *policy)
97{ 98{
99 struct inode *inode = file_inode(filp);
100 int ret;
101
98 if (!inode_owner_or_capable(inode)) 102 if (!inode_owner_or_capable(inode))
99 return -EACCES; 103 return -EACCES;
100 104
101 if (policy->version != 0) 105 if (policy->version != 0)
102 return -EINVAL; 106 return -EINVAL;
103 107
108 ret = mnt_want_write_file(filp);
109 if (ret)
110 return ret;
111
104 if (!inode_has_encryption_context(inode)) { 112 if (!inode_has_encryption_context(inode)) {
105 if (!S_ISDIR(inode->i_mode)) 113 if (!S_ISDIR(inode->i_mode))
106 return -EINVAL; 114 ret = -EINVAL;
107 if (!inode->i_sb->s_cop->empty_dir) 115 else if (!inode->i_sb->s_cop->empty_dir)
108 return -EOPNOTSUPP; 116 ret = -EOPNOTSUPP;
109 if (!inode->i_sb->s_cop->empty_dir(inode)) 117 else if (!inode->i_sb->s_cop->empty_dir(inode))
110 return -ENOTEMPTY; 118 ret = -ENOTEMPTY;
111 return create_encryption_context_from_policy(inode, policy); 119 else
120 ret = create_encryption_context_from_policy(inode,
121 policy);
122 } else if (!is_encryption_context_consistent_with_policy(inode,
123 policy)) {
124 printk(KERN_WARNING
125 "%s: Policy inconsistent with encryption context\n",
126 __func__);
127 ret = -EINVAL;
112 } 128 }
113 129
114 if (is_encryption_context_consistent_with_policy(inode, policy)) 130 mnt_drop_write_file(filp);
115 return 0; 131 return ret;
116
117 printk(KERN_WARNING "%s: Policy inconsistent with encryption context\n",
118 __func__);
119 return -EINVAL;
120} 132}
121EXPORT_SYMBOL(fscrypt_process_policy); 133EXPORT_SYMBOL(fscrypt_process_policy);
122 134
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
index 10686fd67fb4..1bb7df5e4536 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -776,7 +776,7 @@ resizefs_out:
776 (struct fscrypt_policy __user *)arg, 776 (struct fscrypt_policy __user *)arg,
777 sizeof(policy))) 777 sizeof(policy)))
778 return -EFAULT; 778 return -EFAULT;
779 return fscrypt_process_policy(inode, &policy); 779 return fscrypt_process_policy(filp, &policy);
780#else 780#else
781 return -EOPNOTSUPP; 781 return -EOPNOTSUPP;
782#endif 782#endif
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 47abb96098e4..28f4f4cbb8d8 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -1757,21 +1757,14 @@ static int f2fs_ioc_set_encryption_policy(struct file *filp, unsigned long arg)
1757{ 1757{
1758 struct fscrypt_policy policy; 1758 struct fscrypt_policy policy;
1759 struct inode *inode = file_inode(filp); 1759 struct inode *inode = file_inode(filp);
1760 int ret;
1761 1760
1762 if (copy_from_user(&policy, (struct fscrypt_policy __user *)arg, 1761 if (copy_from_user(&policy, (struct fscrypt_policy __user *)arg,
1763 sizeof(policy))) 1762 sizeof(policy)))
1764 return -EFAULT; 1763 return -EFAULT;
1765 1764
1766 ret = mnt_want_write_file(filp);
1767 if (ret)
1768 return ret;
1769
1770 f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); 1765 f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
1771 ret = fscrypt_process_policy(inode, &policy);
1772 1766
1773 mnt_drop_write_file(filp); 1767 return fscrypt_process_policy(filp, &policy);
1774 return ret;
1775} 1768}
1776 1769
1777static int f2fs_ioc_get_encryption_policy(struct file *filp, unsigned long arg) 1770static int f2fs_ioc_get_encryption_policy(struct file *filp, unsigned long arg)