diff options
author | Eric Biggers <ebiggers@google.com> | 2016-09-08 17:20:38 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2016-09-10 01:18:57 -0400 |
commit | ba63f23d69a3a10e7e527a02702023da68ef8a6d (patch) | |
tree | ef70ece0179f4d642e0b0b4d5f6aa6cfed7c9e74 /fs | |
parent | 002ced4be6429918800ce3e41d5cbc2d7c01822c (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.c | 38 | ||||
-rw-r--r-- | fs/ext4/ioctl.c | 2 | ||||
-rw-r--r-- | fs/f2fs/file.c | 9 |
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 | ||
15 | static int inode_has_encryption_context(struct inode *inode) | 16 | static 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 | ||
95 | int fscrypt_process_policy(struct inode *inode, | 96 | int 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 | } |
121 | EXPORT_SYMBOL(fscrypt_process_policy); | 133 | EXPORT_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 | ||
1777 | static int f2fs_ioc_get_encryption_policy(struct file *filp, unsigned long arg) | 1770 | static int f2fs_ioc_get_encryption_policy(struct file *filp, unsigned long arg) |