diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-09-10 12:18:33 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-09-10 12:18:33 -0400 |
commit | 6905732c80bc7f85602abbe27f7bdc3fe81f56d0 (patch) | |
tree | 8d181da54cd9e57e1004553a0e76f30606bf6142 | |
parent | d0acc7dfd90eb97e90ccd42a567034017ec60fb8 (diff) | |
parent | ba63f23d69a3a10e7e527a02702023da68ef8a6d (diff) |
Merge tag 'for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
Pull fscrypto fixes fromTed Ts'o:
"Fix some brown-paper-bag bugs for fscrypto, including one one which
allows a malicious user to set an encryption policy on an empty
directory which they do not own"
* tag 'for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4:
fscrypto: require write access to mount to set encryption policy
fscrypto: only allow setting encryption policy on directories
fscrypto: add authorization check for setting encryption policy
-rw-r--r-- | fs/crypto/policy.c | 41 | ||||
-rw-r--r-- | fs/ext4/ioctl.c | 2 | ||||
-rw-r--r-- | fs/f2fs/file.c | 9 | ||||
-rw-r--r-- | include/linux/fscrypto.h | 5 |
4 files changed, 33 insertions, 24 deletions
diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c index 0f9961eede1e..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,26 +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 | |||
102 | if (!inode_owner_or_capable(inode)) | ||
103 | return -EACCES; | ||
104 | |||
98 | if (policy->version != 0) | 105 | if (policy->version != 0) |
99 | return -EINVAL; | 106 | return -EINVAL; |
100 | 107 | ||
108 | ret = mnt_want_write_file(filp); | ||
109 | if (ret) | ||
110 | return ret; | ||
111 | |||
101 | if (!inode_has_encryption_context(inode)) { | 112 | if (!inode_has_encryption_context(inode)) { |
102 | if (!inode->i_sb->s_cop->empty_dir) | 113 | if (!S_ISDIR(inode->i_mode)) |
103 | return -EOPNOTSUPP; | 114 | ret = -EINVAL; |
104 | if (!inode->i_sb->s_cop->empty_dir(inode)) | 115 | else if (!inode->i_sb->s_cop->empty_dir) |
105 | return -ENOTEMPTY; | 116 | ret = -EOPNOTSUPP; |
106 | return create_encryption_context_from_policy(inode, policy); | 117 | else if (!inode->i_sb->s_cop->empty_dir(inode)) |
118 | ret = -ENOTEMPTY; | ||
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; | ||
107 | } | 128 | } |
108 | 129 | ||
109 | if (is_encryption_context_consistent_with_policy(inode, policy)) | 130 | mnt_drop_write_file(filp); |
110 | return 0; | 131 | return ret; |
111 | |||
112 | printk(KERN_WARNING "%s: Policy inconsistent with encryption context\n", | ||
113 | __func__); | ||
114 | return -EINVAL; | ||
115 | } | 132 | } |
116 | EXPORT_SYMBOL(fscrypt_process_policy); | 133 | EXPORT_SYMBOL(fscrypt_process_policy); |
117 | 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) |
diff --git a/include/linux/fscrypto.h b/include/linux/fscrypto.h index cfa6cde25f8e..76cff18bb032 100644 --- a/include/linux/fscrypto.h +++ b/include/linux/fscrypto.h | |||
@@ -274,8 +274,7 @@ extern void fscrypt_restore_control_page(struct page *); | |||
274 | extern int fscrypt_zeroout_range(struct inode *, pgoff_t, sector_t, | 274 | extern int fscrypt_zeroout_range(struct inode *, pgoff_t, sector_t, |
275 | unsigned int); | 275 | unsigned int); |
276 | /* policy.c */ | 276 | /* policy.c */ |
277 | extern int fscrypt_process_policy(struct inode *, | 277 | extern int fscrypt_process_policy(struct file *, const struct fscrypt_policy *); |
278 | const struct fscrypt_policy *); | ||
279 | extern int fscrypt_get_policy(struct inode *, struct fscrypt_policy *); | 278 | extern int fscrypt_get_policy(struct inode *, struct fscrypt_policy *); |
280 | extern int fscrypt_has_permitted_context(struct inode *, struct inode *); | 279 | extern int fscrypt_has_permitted_context(struct inode *, struct inode *); |
281 | extern int fscrypt_inherit_context(struct inode *, struct inode *, | 280 | extern int fscrypt_inherit_context(struct inode *, struct inode *, |
@@ -345,7 +344,7 @@ static inline int fscrypt_notsupp_zeroout_range(struct inode *i, pgoff_t p, | |||
345 | } | 344 | } |
346 | 345 | ||
347 | /* policy.c */ | 346 | /* policy.c */ |
348 | static inline int fscrypt_notsupp_process_policy(struct inode *i, | 347 | static inline int fscrypt_notsupp_process_policy(struct file *f, |
349 | const struct fscrypt_policy *p) | 348 | const struct fscrypt_policy *p) |
350 | { | 349 | { |
351 | return -EOPNOTSUPP; | 350 | return -EOPNOTSUPP; |