aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@google.com>2017-04-07 13:58:37 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-05-20 08:28:41 -0400
commit64a599ac5dcca722e9bcec3fe1e42d9f1774f229 (patch)
treed958cd329c7b08950e08ed9322b2503c44263aad /fs
parent8dd114ef78c855814558472ed13e99357e098e33 (diff)
fscrypt: fix context consistency check when key(s) unavailable
commit 272f98f6846277378e1758a49a49d7bf39343c02 upstream. To mitigate some types of offline attacks, filesystem encryption is designed to enforce that all files in an encrypted directory tree use the same encryption policy (i.e. the same encryption context excluding the nonce). However, the fscrypt_has_permitted_context() function which enforces this relies on comparing struct fscrypt_info's, which are only available when we have the encryption keys. This can cause two incorrect behaviors: 1. If we have the parent directory's key but not the child's key, or vice versa, then fscrypt_has_permitted_context() returned false, causing applications to see EPERM or ENOKEY. This is incorrect if the encryption contexts are in fact consistent. Although we'd normally have either both keys or neither key in that case since the master_key_descriptors would be the same, this is not guaranteed because keys can be added or removed from keyrings at any time. 2. If we have neither the parent's key nor the child's key, then fscrypt_has_permitted_context() returned true, causing applications to see no error (or else an error for some other reason). This is incorrect if the encryption contexts are in fact inconsistent, since in that case we should deny access. To fix this, retrieve and compare the fscrypt_contexts if we are unable to set up both fscrypt_infos. While this slightly hurts performance when accessing an encrypted directory tree without the key, this isn't a case we really need to be optimizing for; access *with* the key is much more important. Furthermore, the performance hit is barely noticeable given that we are already retrieving the fscrypt_context and doing two keyring searches in fscrypt_get_encryption_info(). If we ever actually wanted to optimize this case we might start by caching the fscrypt_contexts. 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>
Diffstat (limited to 'fs')
-rw-r--r--fs/crypto/policy.c87
1 files changed, 68 insertions, 19 deletions
diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c
index abc18847b98d..bb4e209bd809 100644
--- a/fs/crypto/policy.c
+++ b/fs/crypto/policy.c
@@ -161,27 +161,61 @@ int fscrypt_get_policy(struct inode *inode, struct fscrypt_policy *policy)
161} 161}
162EXPORT_SYMBOL(fscrypt_get_policy); 162EXPORT_SYMBOL(fscrypt_get_policy);
163 163
164/**
165 * fscrypt_has_permitted_context() - is a file's encryption policy permitted
166 * within its directory?
167 *
168 * @parent: inode for parent directory
169 * @child: inode for file being looked up, opened, or linked into @parent
170 *
171 * Filesystems must call this before permitting access to an inode in a
172 * situation where the parent directory is encrypted (either before allowing
173 * ->lookup() to succeed, or for a regular file before allowing it to be opened)
174 * and before any operation that involves linking an inode into an encrypted
175 * directory, including link, rename, and cross rename. It enforces the
176 * constraint that within a given encrypted directory tree, all files use the
177 * same encryption policy. The pre-access check is needed to detect potentially
178 * malicious offline violations of this constraint, while the link and rename
179 * checks are needed to prevent online violations of this constraint.
180 *
181 * Return: 1 if permitted, 0 if forbidden. If forbidden, the caller must fail
182 * the filesystem operation with EPERM.
183 */
164int fscrypt_has_permitted_context(struct inode *parent, struct inode *child) 184int fscrypt_has_permitted_context(struct inode *parent, struct inode *child)
165{ 185{
166 struct fscrypt_info *parent_ci, *child_ci; 186 const struct fscrypt_operations *cops = parent->i_sb->s_cop;
187 const struct fscrypt_info *parent_ci, *child_ci;
188 struct fscrypt_context parent_ctx, child_ctx;
167 int res; 189 int res;
168 190
169 if ((parent == NULL) || (child == NULL)) {
170 printk(KERN_ERR "parent %p child %p\n", parent, child);
171 BUG_ON(1);
172 }
173
174 /* No restrictions on file types which are never encrypted */ 191 /* No restrictions on file types which are never encrypted */
175 if (!S_ISREG(child->i_mode) && !S_ISDIR(child->i_mode) && 192 if (!S_ISREG(child->i_mode) && !S_ISDIR(child->i_mode) &&
176 !S_ISLNK(child->i_mode)) 193 !S_ISLNK(child->i_mode))
177 return 1; 194 return 1;
178 195
179 /* no restrictions if the parent directory is not encrypted */ 196 /* No restrictions if the parent directory is unencrypted */
180 if (!parent->i_sb->s_cop->is_encrypted(parent)) 197 if (!cops->is_encrypted(parent))
181 return 1; 198 return 1;
182 /* if the child directory is not encrypted, this is always a problem */ 199
183 if (!parent->i_sb->s_cop->is_encrypted(child)) 200 /* Encrypted directories must not contain unencrypted files */
201 if (!cops->is_encrypted(child))
184 return 0; 202 return 0;
203
204 /*
205 * Both parent and child are encrypted, so verify they use the same
206 * encryption policy. Compare the fscrypt_info structs if the keys are
207 * available, otherwise retrieve and compare the fscrypt_contexts.
208 *
209 * Note that the fscrypt_context retrieval will be required frequently
210 * when accessing an encrypted directory tree without the key.
211 * Performance-wise this is not a big deal because we already don't
212 * really optimize for file access without the key (to the extent that
213 * such access is even possible), given that any attempted access
214 * already causes a fscrypt_context retrieval and keyring search.
215 *
216 * In any case, if an unexpected error occurs, fall back to "forbidden".
217 */
218
185 res = fscrypt_get_encryption_info(parent); 219 res = fscrypt_get_encryption_info(parent);
186 if (res) 220 if (res)
187 return 0; 221 return 0;
@@ -190,17 +224,32 @@ int fscrypt_has_permitted_context(struct inode *parent, struct inode *child)
190 return 0; 224 return 0;
191 parent_ci = parent->i_crypt_info; 225 parent_ci = parent->i_crypt_info;
192 child_ci = child->i_crypt_info; 226 child_ci = child->i_crypt_info;
193 if (!parent_ci && !child_ci) 227
194 return 1; 228 if (parent_ci && child_ci) {
195 if (!parent_ci || !child_ci) 229 return memcmp(parent_ci->ci_master_key, child_ci->ci_master_key,
230 FS_KEY_DESCRIPTOR_SIZE) == 0 &&
231 (parent_ci->ci_data_mode == child_ci->ci_data_mode) &&
232 (parent_ci->ci_filename_mode ==
233 child_ci->ci_filename_mode) &&
234 (parent_ci->ci_flags == child_ci->ci_flags);
235 }
236
237 res = cops->get_context(parent, &parent_ctx, sizeof(parent_ctx));
238 if (res != sizeof(parent_ctx))
196 return 0; 239 return 0;
197 240
198 return (memcmp(parent_ci->ci_master_key, 241 res = cops->get_context(child, &child_ctx, sizeof(child_ctx));
199 child_ci->ci_master_key, 242 if (res != sizeof(child_ctx))
200 FS_KEY_DESCRIPTOR_SIZE) == 0 && 243 return 0;
201 (parent_ci->ci_data_mode == child_ci->ci_data_mode) && 244
202 (parent_ci->ci_filename_mode == child_ci->ci_filename_mode) && 245 return memcmp(parent_ctx.master_key_descriptor,
203 (parent_ci->ci_flags == child_ci->ci_flags)); 246 child_ctx.master_key_descriptor,
247 FS_KEY_DESCRIPTOR_SIZE) == 0 &&
248 (parent_ctx.contents_encryption_mode ==
249 child_ctx.contents_encryption_mode) &&
250 (parent_ctx.filenames_encryption_mode ==
251 child_ctx.filenames_encryption_mode) &&
252 (parent_ctx.flags == child_ctx.flags);
204} 253}
205EXPORT_SYMBOL(fscrypt_has_permitted_context); 254EXPORT_SYMBOL(fscrypt_has_permitted_context);
206 255