| .. | .. |
|---|
| 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 | |
|---|