.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 2011 IBM Corporation |
---|
3 | 4 | * |
---|
4 | 5 | * Author: |
---|
5 | 6 | * Mimi Zohar <zohar@us.ibm.com> |
---|
6 | | - * |
---|
7 | | - * This program is free software; you can redistribute it and/or modify |
---|
8 | | - * it under the terms of the GNU General Public License as published by |
---|
9 | | - * the Free Software Foundation, version 2 of the License. |
---|
10 | 7 | */ |
---|
11 | | -#include <linux/module.h> |
---|
| 8 | +#include <linux/init.h> |
---|
12 | 9 | #include <linux/file.h> |
---|
13 | 10 | #include <linux/fs.h> |
---|
14 | 11 | #include <linux/xattr.h> |
---|
15 | 12 | #include <linux/magic.h> |
---|
16 | 13 | #include <linux/ima.h> |
---|
17 | 14 | #include <linux/evm.h> |
---|
| 15 | +#include <keys/system_keyring.h> |
---|
18 | 16 | |
---|
19 | 17 | #include "ima.h" |
---|
20 | 18 | |
---|
21 | 19 | static int __init default_appraise_setup(char *str) |
---|
22 | 20 | { |
---|
23 | 21 | #ifdef CONFIG_IMA_APPRAISE_BOOTPARAM |
---|
| 22 | + bool sb_state = arch_ima_get_secureboot(); |
---|
| 23 | + int appraisal_state = ima_appraise; |
---|
| 24 | + |
---|
24 | 25 | if (strncmp(str, "off", 3) == 0) |
---|
25 | | - ima_appraise = 0; |
---|
| 26 | + appraisal_state = 0; |
---|
26 | 27 | else if (strncmp(str, "log", 3) == 0) |
---|
27 | | - ima_appraise = IMA_APPRAISE_LOG; |
---|
| 28 | + appraisal_state = IMA_APPRAISE_LOG; |
---|
28 | 29 | else if (strncmp(str, "fix", 3) == 0) |
---|
29 | | - ima_appraise = IMA_APPRAISE_FIX; |
---|
| 30 | + appraisal_state = IMA_APPRAISE_FIX; |
---|
| 31 | + else if (strncmp(str, "enforce", 7) == 0) |
---|
| 32 | + appraisal_state = IMA_APPRAISE_ENFORCE; |
---|
| 33 | + else |
---|
| 34 | + pr_err("invalid \"%s\" appraise option", str); |
---|
| 35 | + |
---|
| 36 | + /* If appraisal state was changed, but secure boot is enabled, |
---|
| 37 | + * keep its default */ |
---|
| 38 | + if (sb_state) { |
---|
| 39 | + if (!(appraisal_state & IMA_APPRAISE_ENFORCE)) |
---|
| 40 | + pr_info("Secure boot enabled: ignoring ima_appraise=%s option", |
---|
| 41 | + str); |
---|
| 42 | + } else { |
---|
| 43 | + ima_appraise = appraisal_state; |
---|
| 44 | + } |
---|
30 | 45 | #endif |
---|
31 | 46 | return 1; |
---|
32 | 47 | } |
---|
.. | .. |
---|
57 | 72 | |
---|
58 | 73 | security_task_getsecid(current, &secid); |
---|
59 | 74 | return ima_match_policy(inode, current_cred(), secid, func, mask, |
---|
60 | | - IMA_APPRAISE | IMA_HASH, NULL); |
---|
| 75 | + IMA_APPRAISE | IMA_HASH, NULL, NULL, NULL); |
---|
61 | 76 | } |
---|
62 | 77 | |
---|
63 | 78 | static int ima_fix_xattr(struct dentry *dentry, |
---|
.. | .. |
---|
114 | 129 | break; |
---|
115 | 130 | case CREDS_CHECK: |
---|
116 | 131 | iint->ima_creds_status = status; |
---|
| 132 | + break; |
---|
117 | 133 | case FILE_CHECK: |
---|
118 | 134 | case POST_SETATTR: |
---|
119 | 135 | iint->ima_file_status = status; |
---|
.. | .. |
---|
167 | 183 | return sig->hash_algo; |
---|
168 | 184 | break; |
---|
169 | 185 | case IMA_XATTR_DIGEST_NG: |
---|
170 | | - ret = xattr_value->digest[0]; |
---|
| 186 | + /* first byte contains algorithm id */ |
---|
| 187 | + ret = xattr_value->data[0]; |
---|
171 | 188 | if (ret < HASH_ALGO__LAST) |
---|
172 | 189 | return ret; |
---|
173 | 190 | break; |
---|
.. | .. |
---|
175 | 192 | /* this is for backward compatibility */ |
---|
176 | 193 | if (xattr_len == 21) { |
---|
177 | 194 | unsigned int zero = 0; |
---|
178 | | - if (!memcmp(&xattr_value->digest[16], &zero, 4)) |
---|
| 195 | + if (!memcmp(&xattr_value->data[16], &zero, 4)) |
---|
179 | 196 | return HASH_ALGO_MD5; |
---|
180 | 197 | else |
---|
181 | 198 | return HASH_ALGO_SHA1; |
---|
.. | .. |
---|
201 | 218 | } |
---|
202 | 219 | |
---|
203 | 220 | /* |
---|
| 221 | + * xattr_verify - verify xattr digest or signature |
---|
| 222 | + * |
---|
| 223 | + * Verify whether the hash or signature matches the file contents. |
---|
| 224 | + * |
---|
| 225 | + * Return 0 on success, error code otherwise. |
---|
| 226 | + */ |
---|
| 227 | +static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint, |
---|
| 228 | + struct evm_ima_xattr_data *xattr_value, int xattr_len, |
---|
| 229 | + enum integrity_status *status, const char **cause) |
---|
| 230 | +{ |
---|
| 231 | + int rc = -EINVAL, hash_start = 0; |
---|
| 232 | + |
---|
| 233 | + switch (xattr_value->type) { |
---|
| 234 | + case IMA_XATTR_DIGEST_NG: |
---|
| 235 | + /* first byte contains algorithm id */ |
---|
| 236 | + hash_start = 1; |
---|
| 237 | + fallthrough; |
---|
| 238 | + case IMA_XATTR_DIGEST: |
---|
| 239 | + if (iint->flags & IMA_DIGSIG_REQUIRED) { |
---|
| 240 | + *cause = "IMA-signature-required"; |
---|
| 241 | + *status = INTEGRITY_FAIL; |
---|
| 242 | + break; |
---|
| 243 | + } |
---|
| 244 | + clear_bit(IMA_DIGSIG, &iint->atomic_flags); |
---|
| 245 | + if (xattr_len - sizeof(xattr_value->type) - hash_start >= |
---|
| 246 | + iint->ima_hash->length) |
---|
| 247 | + /* |
---|
| 248 | + * xattr length may be longer. md5 hash in previous |
---|
| 249 | + * version occupied 20 bytes in xattr, instead of 16 |
---|
| 250 | + */ |
---|
| 251 | + rc = memcmp(&xattr_value->data[hash_start], |
---|
| 252 | + iint->ima_hash->digest, |
---|
| 253 | + iint->ima_hash->length); |
---|
| 254 | + else |
---|
| 255 | + rc = -EINVAL; |
---|
| 256 | + if (rc) { |
---|
| 257 | + *cause = "invalid-hash"; |
---|
| 258 | + *status = INTEGRITY_FAIL; |
---|
| 259 | + break; |
---|
| 260 | + } |
---|
| 261 | + *status = INTEGRITY_PASS; |
---|
| 262 | + break; |
---|
| 263 | + case EVM_IMA_XATTR_DIGSIG: |
---|
| 264 | + set_bit(IMA_DIGSIG, &iint->atomic_flags); |
---|
| 265 | + rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA, |
---|
| 266 | + (const char *)xattr_value, |
---|
| 267 | + xattr_len, |
---|
| 268 | + iint->ima_hash->digest, |
---|
| 269 | + iint->ima_hash->length); |
---|
| 270 | + if (rc == -EOPNOTSUPP) { |
---|
| 271 | + *status = INTEGRITY_UNKNOWN; |
---|
| 272 | + break; |
---|
| 273 | + } |
---|
| 274 | + if (IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING) && rc && |
---|
| 275 | + func == KEXEC_KERNEL_CHECK) |
---|
| 276 | + rc = integrity_digsig_verify(INTEGRITY_KEYRING_PLATFORM, |
---|
| 277 | + (const char *)xattr_value, |
---|
| 278 | + xattr_len, |
---|
| 279 | + iint->ima_hash->digest, |
---|
| 280 | + iint->ima_hash->length); |
---|
| 281 | + if (rc) { |
---|
| 282 | + *cause = "invalid-signature"; |
---|
| 283 | + *status = INTEGRITY_FAIL; |
---|
| 284 | + } else { |
---|
| 285 | + *status = INTEGRITY_PASS; |
---|
| 286 | + } |
---|
| 287 | + break; |
---|
| 288 | + default: |
---|
| 289 | + *status = INTEGRITY_UNKNOWN; |
---|
| 290 | + *cause = "unknown-ima-data"; |
---|
| 291 | + break; |
---|
| 292 | + } |
---|
| 293 | + |
---|
| 294 | + return rc; |
---|
| 295 | +} |
---|
| 296 | + |
---|
| 297 | +/* |
---|
| 298 | + * modsig_verify - verify modsig signature |
---|
| 299 | + * |
---|
| 300 | + * Verify whether the signature matches the file contents. |
---|
| 301 | + * |
---|
| 302 | + * Return 0 on success, error code otherwise. |
---|
| 303 | + */ |
---|
| 304 | +static int modsig_verify(enum ima_hooks func, const struct modsig *modsig, |
---|
| 305 | + enum integrity_status *status, const char **cause) |
---|
| 306 | +{ |
---|
| 307 | + int rc; |
---|
| 308 | + |
---|
| 309 | + rc = integrity_modsig_verify(INTEGRITY_KEYRING_IMA, modsig); |
---|
| 310 | + if (IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING) && rc && |
---|
| 311 | + func == KEXEC_KERNEL_CHECK) |
---|
| 312 | + rc = integrity_modsig_verify(INTEGRITY_KEYRING_PLATFORM, |
---|
| 313 | + modsig); |
---|
| 314 | + if (rc) { |
---|
| 315 | + *cause = "invalid-signature"; |
---|
| 316 | + *status = INTEGRITY_FAIL; |
---|
| 317 | + } else { |
---|
| 318 | + *status = INTEGRITY_PASS; |
---|
| 319 | + } |
---|
| 320 | + |
---|
| 321 | + return rc; |
---|
| 322 | +} |
---|
| 323 | + |
---|
| 324 | +/* |
---|
| 325 | + * ima_check_blacklist - determine if the binary is blacklisted. |
---|
| 326 | + * |
---|
| 327 | + * Add the hash of the blacklisted binary to the measurement list, based |
---|
| 328 | + * on policy. |
---|
| 329 | + * |
---|
| 330 | + * Returns -EPERM if the hash is blacklisted. |
---|
| 331 | + */ |
---|
| 332 | +int ima_check_blacklist(struct integrity_iint_cache *iint, |
---|
| 333 | + const struct modsig *modsig, int pcr) |
---|
| 334 | +{ |
---|
| 335 | + enum hash_algo hash_algo; |
---|
| 336 | + const u8 *digest = NULL; |
---|
| 337 | + u32 digestsize = 0; |
---|
| 338 | + int rc = 0; |
---|
| 339 | + |
---|
| 340 | + if (!(iint->flags & IMA_CHECK_BLACKLIST)) |
---|
| 341 | + return 0; |
---|
| 342 | + |
---|
| 343 | + if (iint->flags & IMA_MODSIG_ALLOWED && modsig) { |
---|
| 344 | + ima_get_modsig_digest(modsig, &hash_algo, &digest, &digestsize); |
---|
| 345 | + |
---|
| 346 | + rc = is_binary_blacklisted(digest, digestsize); |
---|
| 347 | + if ((rc == -EPERM) && (iint->flags & IMA_MEASURE)) |
---|
| 348 | + process_buffer_measurement(NULL, digest, digestsize, |
---|
| 349 | + "blacklisted-hash", NONE, |
---|
| 350 | + pcr, NULL); |
---|
| 351 | + } |
---|
| 352 | + |
---|
| 353 | + return rc; |
---|
| 354 | +} |
---|
| 355 | + |
---|
| 356 | +/* |
---|
204 | 357 | * ima_appraise_measurement - appraise file measurement |
---|
205 | 358 | * |
---|
206 | 359 | * Call evm_verifyxattr() to verify the integrity of 'security.ima'. |
---|
.. | .. |
---|
212 | 365 | struct integrity_iint_cache *iint, |
---|
213 | 366 | struct file *file, const unsigned char *filename, |
---|
214 | 367 | struct evm_ima_xattr_data *xattr_value, |
---|
215 | | - int xattr_len) |
---|
| 368 | + int xattr_len, const struct modsig *modsig) |
---|
216 | 369 | { |
---|
217 | 370 | static const char op[] = "appraise_data"; |
---|
218 | 371 | const char *cause = "unknown"; |
---|
219 | 372 | struct dentry *dentry = file_dentry(file); |
---|
220 | 373 | struct inode *inode = d_backing_inode(dentry); |
---|
221 | 374 | enum integrity_status status = INTEGRITY_UNKNOWN; |
---|
222 | | - int rc = xattr_len, hash_start = 0; |
---|
| 375 | + int rc = xattr_len; |
---|
| 376 | + bool try_modsig = iint->flags & IMA_MODSIG_ALLOWED && modsig; |
---|
223 | 377 | |
---|
224 | | - if (!(inode->i_opflags & IOP_XATTR)) |
---|
| 378 | + /* If not appraising a modsig, we need an xattr. */ |
---|
| 379 | + if (!(inode->i_opflags & IOP_XATTR) && !try_modsig) |
---|
225 | 380 | return INTEGRITY_UNKNOWN; |
---|
226 | 381 | |
---|
227 | | - if (rc <= 0) { |
---|
| 382 | + /* If reading the xattr failed and there's no modsig, error out. */ |
---|
| 383 | + if (rc <= 0 && !try_modsig) { |
---|
228 | 384 | if (rc && rc != -ENODATA) |
---|
229 | 385 | goto out; |
---|
230 | 386 | |
---|
.. | .. |
---|
240 | 396 | goto out; |
---|
241 | 397 | } |
---|
242 | 398 | |
---|
243 | | - status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value, rc, iint); |
---|
| 399 | + status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value, |
---|
| 400 | + rc < 0 ? 0 : rc, iint); |
---|
244 | 401 | switch (status) { |
---|
245 | 402 | case INTEGRITY_PASS: |
---|
246 | 403 | case INTEGRITY_PASS_IMMUTABLE: |
---|
247 | 404 | case INTEGRITY_UNKNOWN: |
---|
248 | 405 | break; |
---|
249 | 406 | case INTEGRITY_NOXATTRS: /* No EVM protected xattrs. */ |
---|
| 407 | + /* It's fine not to have xattrs when using a modsig. */ |
---|
| 408 | + if (try_modsig) |
---|
| 409 | + break; |
---|
| 410 | + fallthrough; |
---|
250 | 411 | case INTEGRITY_NOLABEL: /* No security.evm xattr. */ |
---|
251 | 412 | cause = "missing-HMAC"; |
---|
252 | 413 | goto out; |
---|
.. | .. |
---|
257 | 418 | WARN_ONCE(true, "Unexpected integrity status %d\n", status); |
---|
258 | 419 | } |
---|
259 | 420 | |
---|
260 | | - switch (xattr_value->type) { |
---|
261 | | - case IMA_XATTR_DIGEST_NG: |
---|
262 | | - /* first byte contains algorithm id */ |
---|
263 | | - hash_start = 1; |
---|
264 | | - /* fall through */ |
---|
265 | | - case IMA_XATTR_DIGEST: |
---|
266 | | - if (iint->flags & IMA_DIGSIG_REQUIRED) { |
---|
267 | | - cause = "IMA-signature-required"; |
---|
268 | | - status = INTEGRITY_FAIL; |
---|
269 | | - break; |
---|
270 | | - } |
---|
271 | | - clear_bit(IMA_DIGSIG, &iint->atomic_flags); |
---|
272 | | - if (xattr_len - sizeof(xattr_value->type) - hash_start >= |
---|
273 | | - iint->ima_hash->length) |
---|
274 | | - /* xattr length may be longer. md5 hash in previous |
---|
275 | | - version occupied 20 bytes in xattr, instead of 16 |
---|
276 | | - */ |
---|
277 | | - rc = memcmp(&xattr_value->digest[hash_start], |
---|
278 | | - iint->ima_hash->digest, |
---|
279 | | - iint->ima_hash->length); |
---|
280 | | - else |
---|
281 | | - rc = -EINVAL; |
---|
282 | | - if (rc) { |
---|
283 | | - cause = "invalid-hash"; |
---|
284 | | - status = INTEGRITY_FAIL; |
---|
285 | | - break; |
---|
286 | | - } |
---|
287 | | - status = INTEGRITY_PASS; |
---|
288 | | - break; |
---|
289 | | - case EVM_IMA_XATTR_DIGSIG: |
---|
290 | | - set_bit(IMA_DIGSIG, &iint->atomic_flags); |
---|
291 | | - rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA, |
---|
292 | | - (const char *)xattr_value, rc, |
---|
293 | | - iint->ima_hash->digest, |
---|
294 | | - iint->ima_hash->length); |
---|
295 | | - if (rc == -EOPNOTSUPP) { |
---|
296 | | - status = INTEGRITY_UNKNOWN; |
---|
297 | | - } else if (rc) { |
---|
298 | | - cause = "invalid-signature"; |
---|
299 | | - status = INTEGRITY_FAIL; |
---|
300 | | - } else { |
---|
301 | | - status = INTEGRITY_PASS; |
---|
302 | | - } |
---|
303 | | - break; |
---|
304 | | - default: |
---|
305 | | - status = INTEGRITY_UNKNOWN; |
---|
306 | | - cause = "unknown-ima-data"; |
---|
307 | | - break; |
---|
308 | | - } |
---|
| 421 | + if (xattr_value) |
---|
| 422 | + rc = xattr_verify(func, iint, xattr_value, xattr_len, &status, |
---|
| 423 | + &cause); |
---|
| 424 | + |
---|
| 425 | + /* |
---|
| 426 | + * If we have a modsig and either no imasig or the imasig's key isn't |
---|
| 427 | + * known, then try verifying the modsig. |
---|
| 428 | + */ |
---|
| 429 | + if (try_modsig && |
---|
| 430 | + (!xattr_value || xattr_value->type == IMA_XATTR_DIGEST_NG || |
---|
| 431 | + rc == -ENOKEY)) |
---|
| 432 | + rc = modsig_verify(func, modsig, &status, &cause); |
---|
309 | 433 | |
---|
310 | 434 | out: |
---|
311 | 435 | /* |
---|
.. | .. |
---|
323 | 447 | op, cause, rc, 0); |
---|
324 | 448 | } else if (status != INTEGRITY_PASS) { |
---|
325 | 449 | /* Fix mode, but don't replace file signatures. */ |
---|
326 | | - if ((ima_appraise & IMA_APPRAISE_FIX) && |
---|
| 450 | + if ((ima_appraise & IMA_APPRAISE_FIX) && !try_modsig && |
---|
327 | 451 | (!xattr_value || |
---|
328 | 452 | xattr_value->type != EVM_IMA_XATTR_DIGSIG)) { |
---|
329 | 453 | if (!ima_fix_xattr(dentry, iint)) |
---|
.. | .. |
---|
362 | 486 | !(iint->flags & IMA_HASH)) |
---|
363 | 487 | return; |
---|
364 | 488 | |
---|
365 | | - rc = ima_collect_measurement(iint, file, NULL, 0, ima_hash_algo); |
---|
| 489 | + rc = ima_collect_measurement(iint, file, NULL, 0, ima_hash_algo, NULL); |
---|
366 | 490 | if (rc < 0) |
---|
367 | 491 | return; |
---|
368 | 492 | |
---|