]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
0b81d077 JK |
2 | /* |
3 | * Encryption policy functions for per-file encryption support. | |
4 | * | |
5 | * Copyright (C) 2015, Google, Inc. | |
6 | * Copyright (C) 2015, Motorola Mobility. | |
7 | * | |
8 | * Written by Michael Halcrow, 2015. | |
9 | * Modified by Jaegeuk Kim, 2015. | |
10 | */ | |
11 | ||
12 | #include <linux/random.h> | |
13 | #include <linux/string.h> | |
ba63f23d | 14 | #include <linux/mount.h> |
cc4e0df0 | 15 | #include "fscrypt_private.h" |
0b81d077 | 16 | |
0b81d077 | 17 | /* |
efee590e | 18 | * check whether an encryption policy is consistent with an encryption context |
0b81d077 | 19 | */ |
efee590e EB |
20 | static bool is_encryption_context_consistent_with_policy( |
21 | const struct fscrypt_context *ctx, | |
0b81d077 JK |
22 | const struct fscrypt_policy *policy) |
23 | { | |
efee590e EB |
24 | return memcmp(ctx->master_key_descriptor, policy->master_key_descriptor, |
25 | FS_KEY_DESCRIPTOR_SIZE) == 0 && | |
26 | (ctx->flags == policy->flags) && | |
27 | (ctx->contents_encryption_mode == | |
28 | policy->contents_encryption_mode) && | |
29 | (ctx->filenames_encryption_mode == | |
30 | policy->filenames_encryption_mode); | |
0b81d077 JK |
31 | } |
32 | ||
33 | static int create_encryption_context_from_policy(struct inode *inode, | |
34 | const struct fscrypt_policy *policy) | |
35 | { | |
36 | struct fscrypt_context ctx; | |
0b81d077 | 37 | |
0b81d077 JK |
38 | ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1; |
39 | memcpy(ctx.master_key_descriptor, policy->master_key_descriptor, | |
40 | FS_KEY_DESCRIPTOR_SIZE); | |
41 | ||
b7e7cf7a DW |
42 | if (!fscrypt_valid_enc_modes(policy->contents_encryption_mode, |
43 | policy->filenames_encryption_mode)) | |
0b81d077 | 44 | return -EINVAL; |
0b81d077 JK |
45 | |
46 | if (policy->flags & ~FS_POLICY_FLAGS_VALID) | |
47 | return -EINVAL; | |
48 | ||
49 | ctx.contents_encryption_mode = policy->contents_encryption_mode; | |
50 | ctx.filenames_encryption_mode = policy->filenames_encryption_mode; | |
51 | ctx.flags = policy->flags; | |
52 | BUILD_BUG_ON(sizeof(ctx.nonce) != FS_KEY_DERIVATION_NONCE_SIZE); | |
53 | get_random_bytes(ctx.nonce, FS_KEY_DERIVATION_NONCE_SIZE); | |
54 | ||
55 | return inode->i_sb->s_cop->set_context(inode, &ctx, sizeof(ctx), NULL); | |
56 | } | |
57 | ||
db717d8e | 58 | int fscrypt_ioctl_set_policy(struct file *filp, const void __user *arg) |
0b81d077 | 59 | { |
db717d8e | 60 | struct fscrypt_policy policy; |
ba63f23d EB |
61 | struct inode *inode = file_inode(filp); |
62 | int ret; | |
efee590e | 63 | struct fscrypt_context ctx; |
ba63f23d | 64 | |
db717d8e EB |
65 | if (copy_from_user(&policy, arg, sizeof(policy))) |
66 | return -EFAULT; | |
67 | ||
163ae1c6 EB |
68 | if (!inode_owner_or_capable(inode)) |
69 | return -EACCES; | |
70 | ||
db717d8e | 71 | if (policy.version != 0) |
0b81d077 JK |
72 | return -EINVAL; |
73 | ||
ba63f23d EB |
74 | ret = mnt_want_write_file(filp); |
75 | if (ret) | |
76 | return ret; | |
77 | ||
8906a822 EB |
78 | inode_lock(inode); |
79 | ||
efee590e EB |
80 | ret = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx)); |
81 | if (ret == -ENODATA) { | |
002ced4b | 82 | if (!S_ISDIR(inode->i_mode)) |
dffd0cfa | 83 | ret = -ENOTDIR; |
ba63f23d EB |
84 | else if (!inode->i_sb->s_cop->empty_dir(inode)) |
85 | ret = -ENOTEMPTY; | |
86 | else | |
87 | ret = create_encryption_context_from_policy(inode, | |
db717d8e | 88 | &policy); |
efee590e EB |
89 | } else if (ret == sizeof(ctx) && |
90 | is_encryption_context_consistent_with_policy(&ctx, | |
91 | &policy)) { | |
92 | /* The file already uses the same encryption policy. */ | |
93 | ret = 0; | |
94 | } else if (ret >= 0 || ret == -ERANGE) { | |
95 | /* The file already uses a different encryption policy. */ | |
8488cd96 | 96 | ret = -EEXIST; |
0b81d077 JK |
97 | } |
98 | ||
8906a822 EB |
99 | inode_unlock(inode); |
100 | ||
ba63f23d EB |
101 | mnt_drop_write_file(filp); |
102 | return ret; | |
0b81d077 | 103 | } |
db717d8e | 104 | EXPORT_SYMBOL(fscrypt_ioctl_set_policy); |
0b81d077 | 105 | |
db717d8e | 106 | int fscrypt_ioctl_get_policy(struct file *filp, void __user *arg) |
0b81d077 | 107 | { |
db717d8e | 108 | struct inode *inode = file_inode(filp); |
0b81d077 | 109 | struct fscrypt_context ctx; |
db717d8e | 110 | struct fscrypt_policy policy; |
0b81d077 JK |
111 | int res; |
112 | ||
e0428a26 | 113 | if (!IS_ENCRYPTED(inode)) |
0b81d077 JK |
114 | return -ENODATA; |
115 | ||
116 | res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx)); | |
efee590e EB |
117 | if (res < 0 && res != -ERANGE) |
118 | return res; | |
0b81d077 | 119 | if (res != sizeof(ctx)) |
efee590e | 120 | return -EINVAL; |
0b81d077 JK |
121 | if (ctx.format != FS_ENCRYPTION_CONTEXT_FORMAT_V1) |
122 | return -EINVAL; | |
123 | ||
db717d8e EB |
124 | policy.version = 0; |
125 | policy.contents_encryption_mode = ctx.contents_encryption_mode; | |
126 | policy.filenames_encryption_mode = ctx.filenames_encryption_mode; | |
127 | policy.flags = ctx.flags; | |
128 | memcpy(policy.master_key_descriptor, ctx.master_key_descriptor, | |
0b81d077 | 129 | FS_KEY_DESCRIPTOR_SIZE); |
db717d8e EB |
130 | |
131 | if (copy_to_user(arg, &policy, sizeof(policy))) | |
132 | return -EFAULT; | |
0b81d077 JK |
133 | return 0; |
134 | } | |
db717d8e | 135 | EXPORT_SYMBOL(fscrypt_ioctl_get_policy); |
0b81d077 | 136 | |
272f98f6 EB |
137 | /** |
138 | * fscrypt_has_permitted_context() - is a file's encryption policy permitted | |
139 | * within its directory? | |
140 | * | |
141 | * @parent: inode for parent directory | |
142 | * @child: inode for file being looked up, opened, or linked into @parent | |
143 | * | |
144 | * Filesystems must call this before permitting access to an inode in a | |
145 | * situation where the parent directory is encrypted (either before allowing | |
146 | * ->lookup() to succeed, or for a regular file before allowing it to be opened) | |
147 | * and before any operation that involves linking an inode into an encrypted | |
148 | * directory, including link, rename, and cross rename. It enforces the | |
149 | * constraint that within a given encrypted directory tree, all files use the | |
150 | * same encryption policy. The pre-access check is needed to detect potentially | |
151 | * malicious offline violations of this constraint, while the link and rename | |
152 | * checks are needed to prevent online violations of this constraint. | |
153 | * | |
154 | * Return: 1 if permitted, 0 if forbidden. If forbidden, the caller must fail | |
155 | * the filesystem operation with EPERM. | |
156 | */ | |
0b81d077 JK |
157 | int fscrypt_has_permitted_context(struct inode *parent, struct inode *child) |
158 | { | |
272f98f6 EB |
159 | const struct fscrypt_operations *cops = parent->i_sb->s_cop; |
160 | const struct fscrypt_info *parent_ci, *child_ci; | |
161 | struct fscrypt_context parent_ctx, child_ctx; | |
0b81d077 JK |
162 | int res; |
163 | ||
42d97eb0 EB |
164 | /* No restrictions on file types which are never encrypted */ |
165 | if (!S_ISREG(child->i_mode) && !S_ISDIR(child->i_mode) && | |
166 | !S_ISLNK(child->i_mode)) | |
167 | return 1; | |
168 | ||
272f98f6 | 169 | /* No restrictions if the parent directory is unencrypted */ |
e0428a26 | 170 | if (!IS_ENCRYPTED(parent)) |
0b81d077 | 171 | return 1; |
272f98f6 EB |
172 | |
173 | /* Encrypted directories must not contain unencrypted files */ | |
e0428a26 | 174 | if (!IS_ENCRYPTED(child)) |
0b81d077 | 175 | return 0; |
272f98f6 EB |
176 | |
177 | /* | |
178 | * Both parent and child are encrypted, so verify they use the same | |
179 | * encryption policy. Compare the fscrypt_info structs if the keys are | |
180 | * available, otherwise retrieve and compare the fscrypt_contexts. | |
181 | * | |
182 | * Note that the fscrypt_context retrieval will be required frequently | |
183 | * when accessing an encrypted directory tree without the key. | |
184 | * Performance-wise this is not a big deal because we already don't | |
185 | * really optimize for file access without the key (to the extent that | |
186 | * such access is even possible), given that any attempted access | |
187 | * already causes a fscrypt_context retrieval and keyring search. | |
188 | * | |
189 | * In any case, if an unexpected error occurs, fall back to "forbidden". | |
190 | */ | |
191 | ||
0b81d077 JK |
192 | res = fscrypt_get_encryption_info(parent); |
193 | if (res) | |
194 | return 0; | |
195 | res = fscrypt_get_encryption_info(child); | |
196 | if (res) | |
197 | return 0; | |
198 | parent_ci = parent->i_crypt_info; | |
199 | child_ci = child->i_crypt_info; | |
272f98f6 EB |
200 | |
201 | if (parent_ci && child_ci) { | |
202 | return memcmp(parent_ci->ci_master_key, child_ci->ci_master_key, | |
203 | FS_KEY_DESCRIPTOR_SIZE) == 0 && | |
204 | (parent_ci->ci_data_mode == child_ci->ci_data_mode) && | |
205 | (parent_ci->ci_filename_mode == | |
206 | child_ci->ci_filename_mode) && | |
207 | (parent_ci->ci_flags == child_ci->ci_flags); | |
208 | } | |
209 | ||
210 | res = cops->get_context(parent, &parent_ctx, sizeof(parent_ctx)); | |
211 | if (res != sizeof(parent_ctx)) | |
212 | return 0; | |
213 | ||
214 | res = cops->get_context(child, &child_ctx, sizeof(child_ctx)); | |
215 | if (res != sizeof(child_ctx)) | |
0b81d077 JK |
216 | return 0; |
217 | ||
272f98f6 EB |
218 | return memcmp(parent_ctx.master_key_descriptor, |
219 | child_ctx.master_key_descriptor, | |
220 | FS_KEY_DESCRIPTOR_SIZE) == 0 && | |
221 | (parent_ctx.contents_encryption_mode == | |
222 | child_ctx.contents_encryption_mode) && | |
223 | (parent_ctx.filenames_encryption_mode == | |
224 | child_ctx.filenames_encryption_mode) && | |
225 | (parent_ctx.flags == child_ctx.flags); | |
0b81d077 JK |
226 | } |
227 | EXPORT_SYMBOL(fscrypt_has_permitted_context); | |
228 | ||
229 | /** | |
230 | * fscrypt_inherit_context() - Sets a child context from its parent | |
231 | * @parent: Parent inode from which the context is inherited. | |
232 | * @child: Child inode that inherits the context from @parent. | |
233 | * @fs_data: private data given by FS. | |
5bbdcbbb | 234 | * @preload: preload child i_crypt_info if true |
0b81d077 | 235 | * |
5bbdcbbb | 236 | * Return: 0 on success, -errno on failure |
0b81d077 JK |
237 | */ |
238 | int fscrypt_inherit_context(struct inode *parent, struct inode *child, | |
239 | void *fs_data, bool preload) | |
240 | { | |
241 | struct fscrypt_context ctx; | |
242 | struct fscrypt_info *ci; | |
243 | int res; | |
244 | ||
0b81d077 JK |
245 | res = fscrypt_get_encryption_info(parent); |
246 | if (res < 0) | |
247 | return res; | |
248 | ||
249 | ci = parent->i_crypt_info; | |
250 | if (ci == NULL) | |
251 | return -ENOKEY; | |
252 | ||
253 | ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1; | |
5bbdcbbb TT |
254 | ctx.contents_encryption_mode = ci->ci_data_mode; |
255 | ctx.filenames_encryption_mode = ci->ci_filename_mode; | |
256 | ctx.flags = ci->ci_flags; | |
257 | memcpy(ctx.master_key_descriptor, ci->ci_master_key, | |
258 | FS_KEY_DESCRIPTOR_SIZE); | |
0b81d077 | 259 | get_random_bytes(ctx.nonce, FS_KEY_DERIVATION_NONCE_SIZE); |
af65207c | 260 | BUILD_BUG_ON(sizeof(ctx) != FSCRYPT_SET_CONTEXT_MAX_SIZE); |
0b81d077 JK |
261 | res = parent->i_sb->s_cop->set_context(child, &ctx, |
262 | sizeof(ctx), fs_data); | |
263 | if (res) | |
264 | return res; | |
265 | return preload ? fscrypt_get_encryption_info(child): 0; | |
266 | } | |
267 | EXPORT_SYMBOL(fscrypt_inherit_context); |