diff options
Diffstat (limited to 'security/integrity/evm/evm_main.c')
-rw-r--r-- | security/integrity/evm/evm_main.c | 284 |
1 files changed, 284 insertions, 0 deletions
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c new file mode 100644 index 000000000000..a8fa45fef8f1 --- /dev/null +++ b/security/integrity/evm/evm_main.c | |||
@@ -0,0 +1,284 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005-2010 IBM Corporation | ||
3 | * | ||
4 | * Author: | ||
5 | * Mimi Zohar <zohar@us.ibm.com> | ||
6 | * Kylene Hall <kjhall@us.ibm.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation, version 2 of the License. | ||
11 | * | ||
12 | * File: evm_main.c | ||
13 | * implements evm_inode_setxattr, evm_inode_post_setxattr, | ||
14 | * evm_inode_removexattr, and evm_verifyxattr | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/crypto.h> | ||
19 | #include <linux/xattr.h> | ||
20 | #include <linux/integrity.h> | ||
21 | #include "evm.h" | ||
22 | |||
23 | int evm_initialized; | ||
24 | |||
25 | char *evm_hmac = "hmac(sha1)"; | ||
26 | |||
27 | char *evm_config_xattrnames[] = { | ||
28 | #ifdef CONFIG_SECURITY_SELINUX | ||
29 | XATTR_NAME_SELINUX, | ||
30 | #endif | ||
31 | #ifdef CONFIG_SECURITY_SMACK | ||
32 | XATTR_NAME_SMACK, | ||
33 | #endif | ||
34 | XATTR_NAME_CAPS, | ||
35 | NULL | ||
36 | }; | ||
37 | |||
38 | /* | ||
39 | * evm_verify_hmac - calculate and compare the HMAC with the EVM xattr | ||
40 | * | ||
41 | * Compute the HMAC on the dentry's protected set of extended attributes | ||
42 | * and compare it against the stored security.evm xattr. (For performance, | ||
43 | * use the previoulsy retrieved xattr value and length to calculate the | ||
44 | * HMAC.) | ||
45 | * | ||
46 | * Returns integrity status | ||
47 | */ | ||
48 | static enum integrity_status evm_verify_hmac(struct dentry *dentry, | ||
49 | const char *xattr_name, | ||
50 | char *xattr_value, | ||
51 | size_t xattr_value_len, | ||
52 | struct integrity_iint_cache *iint) | ||
53 | { | ||
54 | char hmac_val[SHA1_DIGEST_SIZE]; | ||
55 | int rc; | ||
56 | |||
57 | if (iint->hmac_status != INTEGRITY_UNKNOWN) | ||
58 | return iint->hmac_status; | ||
59 | |||
60 | memset(hmac_val, 0, sizeof hmac_val); | ||
61 | rc = evm_calc_hmac(dentry, xattr_name, xattr_value, | ||
62 | xattr_value_len, hmac_val); | ||
63 | if (rc < 0) | ||
64 | return INTEGRITY_UNKNOWN; | ||
65 | |||
66 | rc = vfs_xattr_cmp(dentry, XATTR_NAME_EVM, hmac_val, sizeof hmac_val, | ||
67 | GFP_NOFS); | ||
68 | if (rc < 0) | ||
69 | goto err_out; | ||
70 | iint->hmac_status = INTEGRITY_PASS; | ||
71 | return iint->hmac_status; | ||
72 | |||
73 | err_out: | ||
74 | switch (rc) { | ||
75 | case -ENODATA: /* file not labelled */ | ||
76 | iint->hmac_status = INTEGRITY_NOLABEL; | ||
77 | break; | ||
78 | case -EINVAL: | ||
79 | iint->hmac_status = INTEGRITY_FAIL; | ||
80 | break; | ||
81 | default: | ||
82 | iint->hmac_status = INTEGRITY_UNKNOWN; | ||
83 | } | ||
84 | return iint->hmac_status; | ||
85 | } | ||
86 | |||
87 | static int evm_protected_xattr(const char *req_xattr_name) | ||
88 | { | ||
89 | char **xattrname; | ||
90 | int namelen; | ||
91 | int found = 0; | ||
92 | |||
93 | namelen = strlen(req_xattr_name); | ||
94 | for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) { | ||
95 | if ((strlen(*xattrname) == namelen) | ||
96 | && (strncmp(req_xattr_name, *xattrname, namelen) == 0)) { | ||
97 | found = 1; | ||
98 | break; | ||
99 | } | ||
100 | } | ||
101 | return found; | ||
102 | } | ||
103 | |||
104 | /** | ||
105 | * evm_verifyxattr - verify the integrity of the requested xattr | ||
106 | * @dentry: object of the verify xattr | ||
107 | * @xattr_name: requested xattr | ||
108 | * @xattr_value: requested xattr value | ||
109 | * @xattr_value_len: requested xattr value length | ||
110 | * | ||
111 | * Calculate the HMAC for the given dentry and verify it against the stored | ||
112 | * security.evm xattr. For performance, use the xattr value and length | ||
113 | * previously retrieved to calculate the HMAC. | ||
114 | * | ||
115 | * Returns the xattr integrity status. | ||
116 | * | ||
117 | * This function requires the caller to lock the inode's i_mutex before it | ||
118 | * is executed. | ||
119 | */ | ||
120 | enum integrity_status evm_verifyxattr(struct dentry *dentry, | ||
121 | const char *xattr_name, | ||
122 | void *xattr_value, size_t xattr_value_len) | ||
123 | { | ||
124 | struct inode *inode = dentry->d_inode; | ||
125 | struct integrity_iint_cache *iint; | ||
126 | enum integrity_status status; | ||
127 | |||
128 | if (!evm_initialized || !evm_protected_xattr(xattr_name)) | ||
129 | return INTEGRITY_UNKNOWN; | ||
130 | |||
131 | iint = integrity_iint_find(inode); | ||
132 | if (!iint) | ||
133 | return INTEGRITY_UNKNOWN; | ||
134 | status = evm_verify_hmac(dentry, xattr_name, xattr_value, | ||
135 | xattr_value_len, iint); | ||
136 | return status; | ||
137 | } | ||
138 | EXPORT_SYMBOL_GPL(evm_verifyxattr); | ||
139 | |||
140 | /* | ||
141 | * evm_protect_xattr - protect the EVM extended attribute | ||
142 | * | ||
143 | * Prevent security.evm from being modified or removed. | ||
144 | */ | ||
145 | static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name, | ||
146 | const void *xattr_value, size_t xattr_value_len) | ||
147 | { | ||
148 | if (strcmp(xattr_name, XATTR_NAME_EVM) == 0) { | ||
149 | if (!capable(CAP_SYS_ADMIN)) | ||
150 | return -EPERM; | ||
151 | } | ||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | /** | ||
156 | * evm_inode_setxattr - protect the EVM extended attribute | ||
157 | * @dentry: pointer to the affected dentry | ||
158 | * @xattr_name: pointer to the affected extended attribute name | ||
159 | * @xattr_value: pointer to the new extended attribute value | ||
160 | * @xattr_value_len: pointer to the new extended attribute value length | ||
161 | * | ||
162 | * Prevent 'security.evm' from being modified | ||
163 | */ | ||
164 | int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name, | ||
165 | const void *xattr_value, size_t xattr_value_len) | ||
166 | { | ||
167 | return evm_protect_xattr(dentry, xattr_name, xattr_value, | ||
168 | xattr_value_len); | ||
169 | } | ||
170 | |||
171 | /** | ||
172 | * evm_inode_removexattr - protect the EVM extended attribute | ||
173 | * @dentry: pointer to the affected dentry | ||
174 | * @xattr_name: pointer to the affected extended attribute name | ||
175 | * | ||
176 | * Prevent 'security.evm' from being removed. | ||
177 | */ | ||
178 | int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name) | ||
179 | { | ||
180 | return evm_protect_xattr(dentry, xattr_name, NULL, 0); | ||
181 | } | ||
182 | |||
183 | /** | ||
184 | * evm_inode_post_setxattr - update 'security.evm' to reflect the changes | ||
185 | * @dentry: pointer to the affected dentry | ||
186 | * @xattr_name: pointer to the affected extended attribute name | ||
187 | * @xattr_value: pointer to the new extended attribute value | ||
188 | * @xattr_value_len: pointer to the new extended attribute value length | ||
189 | * | ||
190 | * Update the HMAC stored in 'security.evm' to reflect the change. | ||
191 | * | ||
192 | * No need to take the i_mutex lock here, as this function is called from | ||
193 | * __vfs_setxattr_noperm(). The caller of which has taken the inode's | ||
194 | * i_mutex lock. | ||
195 | */ | ||
196 | void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name, | ||
197 | const void *xattr_value, size_t xattr_value_len) | ||
198 | { | ||
199 | if (!evm_initialized || !evm_protected_xattr(xattr_name)) | ||
200 | return; | ||
201 | |||
202 | evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len); | ||
203 | return; | ||
204 | } | ||
205 | |||
206 | /** | ||
207 | * evm_inode_post_removexattr - update 'security.evm' after removing the xattr | ||
208 | * @dentry: pointer to the affected dentry | ||
209 | * @xattr_name: pointer to the affected extended attribute name | ||
210 | * | ||
211 | * Update the HMAC stored in 'security.evm' to reflect removal of the xattr. | ||
212 | */ | ||
213 | void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name) | ||
214 | { | ||
215 | struct inode *inode = dentry->d_inode; | ||
216 | |||
217 | if (!evm_initialized || !evm_protected_xattr(xattr_name)) | ||
218 | return; | ||
219 | |||
220 | mutex_lock(&inode->i_mutex); | ||
221 | evm_update_evmxattr(dentry, xattr_name, NULL, 0); | ||
222 | mutex_unlock(&inode->i_mutex); | ||
223 | return; | ||
224 | } | ||
225 | |||
226 | /** | ||
227 | * evm_inode_post_setattr - update 'security.evm' after modifying metadata | ||
228 | * @dentry: pointer to the affected dentry | ||
229 | * @ia_valid: for the UID and GID status | ||
230 | * | ||
231 | * For now, update the HMAC stored in 'security.evm' to reflect UID/GID | ||
232 | * changes. | ||
233 | * | ||
234 | * This function is called from notify_change(), which expects the caller | ||
235 | * to lock the inode's i_mutex. | ||
236 | */ | ||
237 | void evm_inode_post_setattr(struct dentry *dentry, int ia_valid) | ||
238 | { | ||
239 | if (!evm_initialized) | ||
240 | return; | ||
241 | |||
242 | if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)) | ||
243 | evm_update_evmxattr(dentry, NULL, NULL, 0); | ||
244 | return; | ||
245 | } | ||
246 | |||
247 | static struct crypto_hash *tfm_hmac; /* preload crypto alg */ | ||
248 | static int __init init_evm(void) | ||
249 | { | ||
250 | int error; | ||
251 | |||
252 | tfm_hmac = crypto_alloc_hash(evm_hmac, 0, CRYPTO_ALG_ASYNC); | ||
253 | error = evm_init_secfs(); | ||
254 | if (error < 0) { | ||
255 | printk(KERN_INFO "EVM: Error registering secfs\n"); | ||
256 | goto err; | ||
257 | } | ||
258 | err: | ||
259 | return error; | ||
260 | } | ||
261 | |||
262 | static void __exit cleanup_evm(void) | ||
263 | { | ||
264 | evm_cleanup_secfs(); | ||
265 | crypto_free_hash(tfm_hmac); | ||
266 | } | ||
267 | |||
268 | /* | ||
269 | * evm_display_config - list the EVM protected security extended attributes | ||
270 | */ | ||
271 | static int __init evm_display_config(void) | ||
272 | { | ||
273 | char **xattrname; | ||
274 | |||
275 | for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) | ||
276 | printk(KERN_INFO "EVM: %s\n", *xattrname); | ||
277 | return 0; | ||
278 | } | ||
279 | |||
280 | pure_initcall(evm_display_config); | ||
281 | late_initcall(init_evm); | ||
282 | |||
283 | MODULE_DESCRIPTION("Extended Verification Module"); | ||
284 | MODULE_LICENSE("GPL"); | ||