diff options
-rw-r--r-- | Documentation/kernel-parameters.txt | 6 | ||||
-rw-r--r-- | security/integrity/evm/evm_main.c | 77 |
2 files changed, 69 insertions, 14 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index fd248a318211..db97ff1da8c0 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -48,6 +48,7 @@ parameter is applicable: | |||
48 | EDD BIOS Enhanced Disk Drive Services (EDD) is enabled | 48 | EDD BIOS Enhanced Disk Drive Services (EDD) is enabled |
49 | EFI EFI Partitioning (GPT) is enabled | 49 | EFI EFI Partitioning (GPT) is enabled |
50 | EIDE EIDE/ATAPI support is enabled. | 50 | EIDE EIDE/ATAPI support is enabled. |
51 | EVM Extended Verification Module | ||
51 | FB The frame buffer device is enabled. | 52 | FB The frame buffer device is enabled. |
52 | GCOV GCOV profiling is enabled. | 53 | GCOV GCOV profiling is enabled. |
53 | HW Appropriate hardware is enabled. | 54 | HW Appropriate hardware is enabled. |
@@ -750,6 +751,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
750 | This option is obsoleted by the "netdev=" option, which | 751 | This option is obsoleted by the "netdev=" option, which |
751 | has equivalent usage. See its documentation for details. | 752 | has equivalent usage. See its documentation for details. |
752 | 753 | ||
754 | evm= [EVM] | ||
755 | Format: { "fix" } | ||
756 | Permit 'security.evm' to be updated regardless of | ||
757 | current integrity status. | ||
758 | |||
753 | failslab= | 759 | failslab= |
754 | fail_page_alloc= | 760 | fail_page_alloc= |
755 | fail_make_request=[KNL] | 761 | fail_make_request=[KNL] |
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index eb07f9d13c24..94d66af07aa4 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c | |||
@@ -37,13 +37,25 @@ char *evm_config_xattrnames[] = { | |||
37 | NULL | 37 | NULL |
38 | }; | 38 | }; |
39 | 39 | ||
40 | static int evm_fixmode; | ||
41 | static int __init evm_set_fixmode(char *str) | ||
42 | { | ||
43 | if (strncmp(str, "fix", 3) == 0) | ||
44 | evm_fixmode = 1; | ||
45 | return 0; | ||
46 | } | ||
47 | __setup("evm=", evm_set_fixmode); | ||
48 | |||
40 | /* | 49 | /* |
41 | * evm_verify_hmac - calculate and compare the HMAC with the EVM xattr | 50 | * evm_verify_hmac - calculate and compare the HMAC with the EVM xattr |
42 | * | 51 | * |
43 | * Compute the HMAC on the dentry's protected set of extended attributes | 52 | * Compute the HMAC on the dentry's protected set of extended attributes |
44 | * and compare it against the stored security.evm xattr. (For performance, | 53 | * and compare it against the stored security.evm xattr. |
45 | * use the previoulsy retrieved xattr value and length to calculate the | 54 | * |
46 | * HMAC.) | 55 | * For performance: |
56 | * - use the previoulsy retrieved xattr value and length to calculate the | ||
57 | * HMAC.) | ||
58 | * - cache the verification result in the iint, when available. | ||
47 | * | 59 | * |
48 | * Returns integrity status | 60 | * Returns integrity status |
49 | */ | 61 | */ |
@@ -54,9 +66,10 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, | |||
54 | struct integrity_iint_cache *iint) | 66 | struct integrity_iint_cache *iint) |
55 | { | 67 | { |
56 | struct evm_ima_xattr_data xattr_data; | 68 | struct evm_ima_xattr_data xattr_data; |
69 | enum integrity_status evm_status; | ||
57 | int rc; | 70 | int rc; |
58 | 71 | ||
59 | if (iint->evm_status == INTEGRITY_PASS) | 72 | if (iint && iint->evm_status == INTEGRITY_PASS) |
60 | return iint->evm_status; | 73 | return iint->evm_status; |
61 | 74 | ||
62 | /* if status is not PASS, try to check again - against -ENOMEM */ | 75 | /* if status is not PASS, try to check again - against -ENOMEM */ |
@@ -71,18 +84,21 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, | |||
71 | sizeof xattr_data, GFP_NOFS); | 84 | sizeof xattr_data, GFP_NOFS); |
72 | if (rc < 0) | 85 | if (rc < 0) |
73 | goto err_out; | 86 | goto err_out; |
74 | iint->evm_status = INTEGRITY_PASS; | 87 | evm_status = INTEGRITY_PASS; |
75 | return iint->evm_status; | 88 | goto out; |
76 | 89 | ||
77 | err_out: | 90 | err_out: |
78 | switch (rc) { | 91 | switch (rc) { |
79 | case -ENODATA: /* file not labelled */ | 92 | case -ENODATA: /* file not labelled */ |
80 | iint->evm_status = INTEGRITY_NOLABEL; | 93 | evm_status = INTEGRITY_NOLABEL; |
81 | break; | 94 | break; |
82 | default: | 95 | default: |
83 | iint->evm_status = INTEGRITY_FAIL; | 96 | evm_status = INTEGRITY_FAIL; |
84 | } | 97 | } |
85 | return iint->evm_status; | 98 | out: |
99 | if (iint) | ||
100 | iint->evm_status = evm_status; | ||
101 | return evm_status; | ||
86 | } | 102 | } |
87 | 103 | ||
88 | static int evm_protected_xattr(const char *req_xattr_name) | 104 | static int evm_protected_xattr(const char *req_xattr_name) |
@@ -157,6 +173,22 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name, | |||
157 | return 0; | 173 | return 0; |
158 | } | 174 | } |
159 | 175 | ||
176 | /* | ||
177 | * evm_verify_current_integrity - verify the dentry's metadata integrity | ||
178 | * @dentry: pointer to the affected dentry | ||
179 | * | ||
180 | * Verify and return the dentry's metadata integrity. The exceptions are | ||
181 | * before EVM is initialized or in 'fix' mode. | ||
182 | */ | ||
183 | static enum integrity_status evm_verify_current_integrity(struct dentry *dentry) | ||
184 | { | ||
185 | struct inode *inode = dentry->d_inode; | ||
186 | |||
187 | if (!evm_initialized || !S_ISREG(inode->i_mode) || evm_fixmode) | ||
188 | return 0; | ||
189 | return evm_verify_hmac(dentry, NULL, NULL, 0, NULL); | ||
190 | } | ||
191 | |||
160 | /** | 192 | /** |
161 | * evm_inode_setxattr - protect the EVM extended attribute | 193 | * evm_inode_setxattr - protect the EVM extended attribute |
162 | * @dentry: pointer to the affected dentry | 194 | * @dentry: pointer to the affected dentry |
@@ -164,13 +196,22 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name, | |||
164 | * @xattr_value: pointer to the new extended attribute value | 196 | * @xattr_value: pointer to the new extended attribute value |
165 | * @xattr_value_len: pointer to the new extended attribute value length | 197 | * @xattr_value_len: pointer to the new extended attribute value length |
166 | * | 198 | * |
167 | * Prevent 'security.evm' from being modified | 199 | * Updating 'security.evm' requires CAP_SYS_ADMIN privileges and that |
200 | * the current value is valid. | ||
168 | */ | 201 | */ |
169 | int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name, | 202 | int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name, |
170 | const void *xattr_value, size_t xattr_value_len) | 203 | const void *xattr_value, size_t xattr_value_len) |
171 | { | 204 | { |
172 | return evm_protect_xattr(dentry, xattr_name, xattr_value, | 205 | |
173 | xattr_value_len); | 206 | enum integrity_status evm_status; |
207 | int ret; | ||
208 | |||
209 | ret = evm_protect_xattr(dentry, xattr_name, xattr_value, | ||
210 | xattr_value_len); | ||
211 | if (ret) | ||
212 | return ret; | ||
213 | evm_status = evm_verify_current_integrity(dentry); | ||
214 | return evm_status == INTEGRITY_PASS ? 0 : -EPERM; | ||
174 | } | 215 | } |
175 | 216 | ||
176 | /** | 217 | /** |
@@ -178,11 +219,19 @@ int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name, | |||
178 | * @dentry: pointer to the affected dentry | 219 | * @dentry: pointer to the affected dentry |
179 | * @xattr_name: pointer to the affected extended attribute name | 220 | * @xattr_name: pointer to the affected extended attribute name |
180 | * | 221 | * |
181 | * Prevent 'security.evm' from being removed. | 222 | * Removing 'security.evm' requires CAP_SYS_ADMIN privileges and that |
223 | * the current value is valid. | ||
182 | */ | 224 | */ |
183 | int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name) | 225 | int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name) |
184 | { | 226 | { |
185 | return evm_protect_xattr(dentry, xattr_name, NULL, 0); | 227 | enum integrity_status evm_status; |
228 | int ret; | ||
229 | |||
230 | ret = evm_protect_xattr(dentry, xattr_name, NULL, 0); | ||
231 | if (ret) | ||
232 | return ret; | ||
233 | evm_status = evm_verify_current_integrity(dentry); | ||
234 | return evm_status == INTEGRITY_PASS ? 0 : -EPERM; | ||
186 | } | 235 | } |
187 | 236 | ||
188 | /** | 237 | /** |