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