1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2010 IBM Corporation |
4 | * |
5 | * Authors: |
6 | * Mimi Zohar <zohar@us.ibm.com> |
7 | * |
8 | * File: evm_secfs.c |
9 | * - Used to signal when key is on keyring |
10 | * - Get the key and enable EVM |
11 | */ |
12 | |
13 | #include <linux/audit.h> |
14 | #include <linux/uaccess.h> |
15 | #include <linux/init.h> |
16 | #include <linux/mutex.h> |
17 | #include "evm.h" |
18 | |
19 | static struct dentry *evm_dir; |
20 | static struct dentry *evm_init_tpm; |
21 | static struct dentry *evm_symlink; |
22 | |
23 | #ifdef CONFIG_EVM_ADD_XATTRS |
24 | static struct dentry *evm_xattrs; |
25 | static DEFINE_MUTEX(xattr_list_mutex); |
26 | static int evm_xattrs_locked; |
27 | #endif |
28 | |
29 | /** |
30 | * evm_read_key - read() for <securityfs>/evm |
31 | * |
32 | * @filp: file pointer, not actually used |
33 | * @buf: where to put the result |
34 | * @count: maximum to send along |
35 | * @ppos: where to start |
36 | * |
37 | * Returns number of bytes read or error code, as appropriate |
38 | */ |
39 | static ssize_t evm_read_key(struct file *filp, char __user *buf, |
40 | size_t count, loff_t *ppos) |
41 | { |
42 | char temp[80]; |
43 | ssize_t rc; |
44 | |
45 | if (*ppos != 0) |
46 | return 0; |
47 | |
48 | sprintf(buf: temp, fmt: "%d" , (evm_initialized & ~EVM_SETUP_COMPLETE)); |
49 | rc = simple_read_from_buffer(to: buf, count, ppos, from: temp, strlen(temp)); |
50 | |
51 | return rc; |
52 | } |
53 | |
54 | /** |
55 | * evm_write_key - write() for <securityfs>/evm |
56 | * @file: file pointer, not actually used |
57 | * @buf: where to get the data from |
58 | * @count: bytes sent |
59 | * @ppos: where to start |
60 | * |
61 | * Used to signal that key is on the kernel key ring. |
62 | * - get the integrity hmac key from the kernel key ring |
63 | * - create list of hmac protected extended attributes |
64 | * Returns number of bytes written or error code, as appropriate |
65 | */ |
66 | static ssize_t evm_write_key(struct file *file, const char __user *buf, |
67 | size_t count, loff_t *ppos) |
68 | { |
69 | unsigned int i; |
70 | int ret; |
71 | |
72 | if (!capable(CAP_SYS_ADMIN) || (evm_initialized & EVM_SETUP_COMPLETE)) |
73 | return -EPERM; |
74 | |
75 | ret = kstrtouint_from_user(s: buf, count, base: 0, res: &i); |
76 | |
77 | if (ret) |
78 | return ret; |
79 | |
80 | /* Reject invalid values */ |
81 | if (!i || (i & ~EVM_INIT_MASK) != 0) |
82 | return -EINVAL; |
83 | |
84 | /* |
85 | * Don't allow a request to enable metadata writes if |
86 | * an HMAC key is loaded. |
87 | */ |
88 | if ((i & EVM_ALLOW_METADATA_WRITES) && |
89 | (evm_initialized & EVM_INIT_HMAC) != 0) |
90 | return -EPERM; |
91 | |
92 | if (i & EVM_INIT_HMAC) { |
93 | ret = evm_init_key(); |
94 | if (ret != 0) |
95 | return ret; |
96 | /* Forbid further writes after the symmetric key is loaded */ |
97 | i |= EVM_SETUP_COMPLETE; |
98 | } |
99 | |
100 | evm_initialized |= i; |
101 | |
102 | /* Don't allow protected metadata modification if a symmetric key |
103 | * is loaded |
104 | */ |
105 | if (evm_initialized & EVM_INIT_HMAC) |
106 | evm_initialized &= ~(EVM_ALLOW_METADATA_WRITES); |
107 | |
108 | return count; |
109 | } |
110 | |
111 | static const struct file_operations evm_key_ops = { |
112 | .read = evm_read_key, |
113 | .write = evm_write_key, |
114 | }; |
115 | |
116 | #ifdef CONFIG_EVM_ADD_XATTRS |
117 | /** |
118 | * evm_read_xattrs - read() for <securityfs>/evm_xattrs |
119 | * |
120 | * @filp: file pointer, not actually used |
121 | * @buf: where to put the result |
122 | * @count: maximum to send along |
123 | * @ppos: where to start |
124 | * |
125 | * Returns number of bytes read or error code, as appropriate |
126 | */ |
127 | static ssize_t evm_read_xattrs(struct file *filp, char __user *buf, |
128 | size_t count, loff_t *ppos) |
129 | { |
130 | char *temp; |
131 | int offset = 0; |
132 | ssize_t rc, size = 0; |
133 | struct xattr_list *xattr; |
134 | |
135 | if (*ppos != 0) |
136 | return 0; |
137 | |
138 | rc = mutex_lock_interruptible(&xattr_list_mutex); |
139 | if (rc) |
140 | return -ERESTARTSYS; |
141 | |
142 | list_for_each_entry(xattr, &evm_config_xattrnames, list) { |
143 | if (!xattr->enabled) |
144 | continue; |
145 | |
146 | size += strlen(xattr->name) + 1; |
147 | } |
148 | |
149 | temp = kmalloc(size: size + 1, GFP_KERNEL); |
150 | if (!temp) { |
151 | mutex_unlock(lock: &xattr_list_mutex); |
152 | return -ENOMEM; |
153 | } |
154 | |
155 | list_for_each_entry(xattr, &evm_config_xattrnames, list) { |
156 | if (!xattr->enabled) |
157 | continue; |
158 | |
159 | sprintf(buf: temp + offset, fmt: "%s\n" , xattr->name); |
160 | offset += strlen(xattr->name) + 1; |
161 | } |
162 | |
163 | mutex_unlock(lock: &xattr_list_mutex); |
164 | rc = simple_read_from_buffer(to: buf, count, ppos, from: temp, strlen(temp)); |
165 | |
166 | kfree(objp: temp); |
167 | |
168 | return rc; |
169 | } |
170 | |
171 | /** |
172 | * evm_write_xattrs - write() for <securityfs>/evm_xattrs |
173 | * @file: file pointer, not actually used |
174 | * @buf: where to get the data from |
175 | * @count: bytes sent |
176 | * @ppos: where to start |
177 | * |
178 | * Returns number of bytes written or error code, as appropriate |
179 | */ |
180 | static ssize_t evm_write_xattrs(struct file *file, const char __user *buf, |
181 | size_t count, loff_t *ppos) |
182 | { |
183 | int len, err; |
184 | struct xattr_list *xattr, *tmp; |
185 | struct audit_buffer *ab; |
186 | struct iattr newattrs; |
187 | struct inode *inode; |
188 | |
189 | if (!capable(CAP_SYS_ADMIN) || evm_xattrs_locked) |
190 | return -EPERM; |
191 | |
192 | if (*ppos != 0) |
193 | return -EINVAL; |
194 | |
195 | if (count > XATTR_NAME_MAX) |
196 | return -E2BIG; |
197 | |
198 | ab = audit_log_start(ctx: audit_context(), GFP_KERNEL, |
199 | AUDIT_INTEGRITY_EVM_XATTR); |
200 | if (!ab && IS_ENABLED(CONFIG_AUDIT)) |
201 | return -ENOMEM; |
202 | |
203 | xattr = kmalloc(size: sizeof(struct xattr_list), GFP_KERNEL); |
204 | if (!xattr) { |
205 | err = -ENOMEM; |
206 | goto out; |
207 | } |
208 | |
209 | xattr->enabled = true; |
210 | xattr->name = memdup_user_nul(buf, count); |
211 | if (IS_ERR(ptr: xattr->name)) { |
212 | err = PTR_ERR(ptr: xattr->name); |
213 | xattr->name = NULL; |
214 | goto out; |
215 | } |
216 | |
217 | /* Remove any trailing newline */ |
218 | len = strlen(xattr->name); |
219 | if (len && xattr->name[len-1] == '\n') |
220 | xattr->name[len-1] = '\0'; |
221 | |
222 | audit_log_format(ab, fmt: "xattr=" ); |
223 | audit_log_untrustedstring(ab, string: xattr->name); |
224 | |
225 | if (strcmp(xattr->name, "." ) == 0) { |
226 | evm_xattrs_locked = 1; |
227 | newattrs.ia_mode = S_IFREG | 0440; |
228 | newattrs.ia_valid = ATTR_MODE; |
229 | inode = evm_xattrs->d_inode; |
230 | inode_lock(inode); |
231 | err = simple_setattr(&nop_mnt_idmap, evm_xattrs, &newattrs); |
232 | inode_unlock(inode); |
233 | if (!err) |
234 | err = count; |
235 | goto out; |
236 | } |
237 | |
238 | if (strncmp(xattr->name, XATTR_SECURITY_PREFIX, |
239 | XATTR_SECURITY_PREFIX_LEN) != 0) { |
240 | err = -EINVAL; |
241 | goto out; |
242 | } |
243 | |
244 | /* |
245 | * xattr_list_mutex guards against races in evm_read_xattrs(). |
246 | * Entries are only added to the evm_config_xattrnames list |
247 | * and never deleted. Therefore, the list is traversed |
248 | * using list_for_each_entry_lockless() without holding |
249 | * the mutex in evm_calc_hmac_or_hash(), evm_find_protected_xattrs() |
250 | * and evm_protected_xattr(). |
251 | */ |
252 | mutex_lock(&xattr_list_mutex); |
253 | list_for_each_entry(tmp, &evm_config_xattrnames, list) { |
254 | if (strcmp(xattr->name, tmp->name) == 0) { |
255 | err = -EEXIST; |
256 | if (!tmp->enabled) { |
257 | tmp->enabled = true; |
258 | err = count; |
259 | } |
260 | mutex_unlock(lock: &xattr_list_mutex); |
261 | goto out; |
262 | } |
263 | } |
264 | list_add_tail_rcu(new: &xattr->list, head: &evm_config_xattrnames); |
265 | mutex_unlock(lock: &xattr_list_mutex); |
266 | |
267 | audit_log_format(ab, fmt: " res=0" ); |
268 | audit_log_end(ab); |
269 | return count; |
270 | out: |
271 | audit_log_format(ab, fmt: " res=%d" , (err < 0) ? err : 0); |
272 | audit_log_end(ab); |
273 | if (xattr) { |
274 | kfree(objp: xattr->name); |
275 | kfree(objp: xattr); |
276 | } |
277 | return err; |
278 | } |
279 | |
280 | static const struct file_operations evm_xattr_ops = { |
281 | .read = evm_read_xattrs, |
282 | .write = evm_write_xattrs, |
283 | }; |
284 | |
285 | static int evm_init_xattrs(void) |
286 | { |
287 | evm_xattrs = securityfs_create_file(name: "evm_xattrs" , mode: 0660, parent: evm_dir, NULL, |
288 | fops: &evm_xattr_ops); |
289 | if (!evm_xattrs || IS_ERR(ptr: evm_xattrs)) |
290 | return -EFAULT; |
291 | |
292 | return 0; |
293 | } |
294 | #else |
295 | static int evm_init_xattrs(void) |
296 | { |
297 | return 0; |
298 | } |
299 | #endif |
300 | |
301 | int __init evm_init_secfs(void) |
302 | { |
303 | int error = 0; |
304 | |
305 | evm_dir = securityfs_create_dir(name: "evm" , parent: integrity_dir); |
306 | if (!evm_dir || IS_ERR(ptr: evm_dir)) |
307 | return -EFAULT; |
308 | |
309 | evm_init_tpm = securityfs_create_file(name: "evm" , mode: 0660, |
310 | parent: evm_dir, NULL, fops: &evm_key_ops); |
311 | if (!evm_init_tpm || IS_ERR(ptr: evm_init_tpm)) { |
312 | error = -EFAULT; |
313 | goto out; |
314 | } |
315 | |
316 | evm_symlink = securityfs_create_symlink(name: "evm" , NULL, |
317 | target: "integrity/evm/evm" , NULL); |
318 | if (!evm_symlink || IS_ERR(ptr: evm_symlink)) { |
319 | error = -EFAULT; |
320 | goto out; |
321 | } |
322 | |
323 | if (evm_init_xattrs() != 0) { |
324 | error = -EFAULT; |
325 | goto out; |
326 | } |
327 | |
328 | return 0; |
329 | out: |
330 | securityfs_remove(dentry: evm_symlink); |
331 | securityfs_remove(dentry: evm_init_tpm); |
332 | securityfs_remove(dentry: evm_dir); |
333 | return error; |
334 | } |
335 | |