18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2011 IBM Corporation 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author: 68c2ecf20Sopenharmony_ci * Mimi Zohar <zohar@us.ibm.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#include <linux/init.h> 98c2ecf20Sopenharmony_ci#include <linux/file.h> 108c2ecf20Sopenharmony_ci#include <linux/fs.h> 118c2ecf20Sopenharmony_ci#include <linux/xattr.h> 128c2ecf20Sopenharmony_ci#include <linux/magic.h> 138c2ecf20Sopenharmony_ci#include <linux/ima.h> 148c2ecf20Sopenharmony_ci#include <linux/evm.h> 158c2ecf20Sopenharmony_ci#include <keys/system_keyring.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "ima.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic int __init default_appraise_setup(char *str) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci#ifdef CONFIG_IMA_APPRAISE_BOOTPARAM 228c2ecf20Sopenharmony_ci bool sb_state = arch_ima_get_secureboot(); 238c2ecf20Sopenharmony_ci int appraisal_state = ima_appraise; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci if (strncmp(str, "off", 3) == 0) 268c2ecf20Sopenharmony_ci appraisal_state = 0; 278c2ecf20Sopenharmony_ci else if (strncmp(str, "log", 3) == 0) 288c2ecf20Sopenharmony_ci appraisal_state = IMA_APPRAISE_LOG; 298c2ecf20Sopenharmony_ci else if (strncmp(str, "fix", 3) == 0) 308c2ecf20Sopenharmony_ci appraisal_state = IMA_APPRAISE_FIX; 318c2ecf20Sopenharmony_ci else if (strncmp(str, "enforce", 7) == 0) 328c2ecf20Sopenharmony_ci appraisal_state = IMA_APPRAISE_ENFORCE; 338c2ecf20Sopenharmony_ci else 348c2ecf20Sopenharmony_ci pr_err("invalid \"%s\" appraise option", str); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci /* If appraisal state was changed, but secure boot is enabled, 378c2ecf20Sopenharmony_ci * keep its default */ 388c2ecf20Sopenharmony_ci if (sb_state) { 398c2ecf20Sopenharmony_ci if (!(appraisal_state & IMA_APPRAISE_ENFORCE)) 408c2ecf20Sopenharmony_ci pr_info("Secure boot enabled: ignoring ima_appraise=%s option", 418c2ecf20Sopenharmony_ci str); 428c2ecf20Sopenharmony_ci } else { 438c2ecf20Sopenharmony_ci ima_appraise = appraisal_state; 448c2ecf20Sopenharmony_ci } 458c2ecf20Sopenharmony_ci#endif 468c2ecf20Sopenharmony_ci return 1; 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci__setup("ima_appraise=", default_appraise_setup); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/* 528c2ecf20Sopenharmony_ci * is_ima_appraise_enabled - return appraise status 538c2ecf20Sopenharmony_ci * 548c2ecf20Sopenharmony_ci * Only return enabled, if not in ima_appraise="fix" or "log" modes. 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_cibool is_ima_appraise_enabled(void) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci return ima_appraise & IMA_APPRAISE_ENFORCE; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* 628c2ecf20Sopenharmony_ci * ima_must_appraise - set appraise flag 638c2ecf20Sopenharmony_ci * 648c2ecf20Sopenharmony_ci * Return 1 to appraise or hash 658c2ecf20Sopenharmony_ci */ 668c2ecf20Sopenharmony_ciint ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci u32 secid; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci if (!ima_appraise) 718c2ecf20Sopenharmony_ci return 0; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci security_task_getsecid(current, &secid); 748c2ecf20Sopenharmony_ci return ima_match_policy(inode, current_cred(), secid, func, mask, 758c2ecf20Sopenharmony_ci IMA_APPRAISE | IMA_HASH, NULL, NULL, NULL); 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic int ima_fix_xattr(struct dentry *dentry, 798c2ecf20Sopenharmony_ci struct integrity_iint_cache *iint) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci int rc, offset; 828c2ecf20Sopenharmony_ci u8 algo = iint->ima_hash->algo; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci if (algo <= HASH_ALGO_SHA1) { 858c2ecf20Sopenharmony_ci offset = 1; 868c2ecf20Sopenharmony_ci iint->ima_hash->xattr.sha1.type = IMA_XATTR_DIGEST; 878c2ecf20Sopenharmony_ci } else { 888c2ecf20Sopenharmony_ci offset = 0; 898c2ecf20Sopenharmony_ci iint->ima_hash->xattr.ng.type = IMA_XATTR_DIGEST_NG; 908c2ecf20Sopenharmony_ci iint->ima_hash->xattr.ng.algo = algo; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA, 938c2ecf20Sopenharmony_ci &iint->ima_hash->xattr.data[offset], 948c2ecf20Sopenharmony_ci (sizeof(iint->ima_hash->xattr) - offset) + 958c2ecf20Sopenharmony_ci iint->ima_hash->length, 0); 968c2ecf20Sopenharmony_ci return rc; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/* Return specific func appraised cached result */ 1008c2ecf20Sopenharmony_cienum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, 1018c2ecf20Sopenharmony_ci enum ima_hooks func) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci switch (func) { 1048c2ecf20Sopenharmony_ci case MMAP_CHECK: 1058c2ecf20Sopenharmony_ci return iint->ima_mmap_status; 1068c2ecf20Sopenharmony_ci case BPRM_CHECK: 1078c2ecf20Sopenharmony_ci return iint->ima_bprm_status; 1088c2ecf20Sopenharmony_ci case CREDS_CHECK: 1098c2ecf20Sopenharmony_ci return iint->ima_creds_status; 1108c2ecf20Sopenharmony_ci case FILE_CHECK: 1118c2ecf20Sopenharmony_ci case POST_SETATTR: 1128c2ecf20Sopenharmony_ci return iint->ima_file_status; 1138c2ecf20Sopenharmony_ci case MODULE_CHECK ... MAX_CHECK - 1: 1148c2ecf20Sopenharmony_ci default: 1158c2ecf20Sopenharmony_ci return iint->ima_read_status; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic void ima_set_cache_status(struct integrity_iint_cache *iint, 1208c2ecf20Sopenharmony_ci enum ima_hooks func, 1218c2ecf20Sopenharmony_ci enum integrity_status status) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci switch (func) { 1248c2ecf20Sopenharmony_ci case MMAP_CHECK: 1258c2ecf20Sopenharmony_ci iint->ima_mmap_status = status; 1268c2ecf20Sopenharmony_ci break; 1278c2ecf20Sopenharmony_ci case BPRM_CHECK: 1288c2ecf20Sopenharmony_ci iint->ima_bprm_status = status; 1298c2ecf20Sopenharmony_ci break; 1308c2ecf20Sopenharmony_ci case CREDS_CHECK: 1318c2ecf20Sopenharmony_ci iint->ima_creds_status = status; 1328c2ecf20Sopenharmony_ci break; 1338c2ecf20Sopenharmony_ci case FILE_CHECK: 1348c2ecf20Sopenharmony_ci case POST_SETATTR: 1358c2ecf20Sopenharmony_ci iint->ima_file_status = status; 1368c2ecf20Sopenharmony_ci break; 1378c2ecf20Sopenharmony_ci case MODULE_CHECK ... MAX_CHECK - 1: 1388c2ecf20Sopenharmony_ci default: 1398c2ecf20Sopenharmony_ci iint->ima_read_status = status; 1408c2ecf20Sopenharmony_ci break; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic void ima_cache_flags(struct integrity_iint_cache *iint, 1458c2ecf20Sopenharmony_ci enum ima_hooks func) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci switch (func) { 1488c2ecf20Sopenharmony_ci case MMAP_CHECK: 1498c2ecf20Sopenharmony_ci iint->flags |= (IMA_MMAP_APPRAISED | IMA_APPRAISED); 1508c2ecf20Sopenharmony_ci break; 1518c2ecf20Sopenharmony_ci case BPRM_CHECK: 1528c2ecf20Sopenharmony_ci iint->flags |= (IMA_BPRM_APPRAISED | IMA_APPRAISED); 1538c2ecf20Sopenharmony_ci break; 1548c2ecf20Sopenharmony_ci case CREDS_CHECK: 1558c2ecf20Sopenharmony_ci iint->flags |= (IMA_CREDS_APPRAISED | IMA_APPRAISED); 1568c2ecf20Sopenharmony_ci break; 1578c2ecf20Sopenharmony_ci case FILE_CHECK: 1588c2ecf20Sopenharmony_ci case POST_SETATTR: 1598c2ecf20Sopenharmony_ci iint->flags |= (IMA_FILE_APPRAISED | IMA_APPRAISED); 1608c2ecf20Sopenharmony_ci break; 1618c2ecf20Sopenharmony_ci case MODULE_CHECK ... MAX_CHECK - 1: 1628c2ecf20Sopenharmony_ci default: 1638c2ecf20Sopenharmony_ci iint->flags |= (IMA_READ_APPRAISED | IMA_APPRAISED); 1648c2ecf20Sopenharmony_ci break; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cienum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, 1698c2ecf20Sopenharmony_ci int xattr_len) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci struct signature_v2_hdr *sig; 1728c2ecf20Sopenharmony_ci enum hash_algo ret; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (!xattr_value || xattr_len < 2) 1758c2ecf20Sopenharmony_ci /* return default hash algo */ 1768c2ecf20Sopenharmony_ci return ima_hash_algo; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci switch (xattr_value->type) { 1798c2ecf20Sopenharmony_ci case EVM_IMA_XATTR_DIGSIG: 1808c2ecf20Sopenharmony_ci sig = (typeof(sig))xattr_value; 1818c2ecf20Sopenharmony_ci if (sig->version != 2 || xattr_len <= sizeof(*sig)) 1828c2ecf20Sopenharmony_ci return ima_hash_algo; 1838c2ecf20Sopenharmony_ci return sig->hash_algo; 1848c2ecf20Sopenharmony_ci break; 1858c2ecf20Sopenharmony_ci case IMA_XATTR_DIGEST_NG: 1868c2ecf20Sopenharmony_ci /* first byte contains algorithm id */ 1878c2ecf20Sopenharmony_ci ret = xattr_value->data[0]; 1888c2ecf20Sopenharmony_ci if (ret < HASH_ALGO__LAST) 1898c2ecf20Sopenharmony_ci return ret; 1908c2ecf20Sopenharmony_ci break; 1918c2ecf20Sopenharmony_ci case IMA_XATTR_DIGEST: 1928c2ecf20Sopenharmony_ci /* this is for backward compatibility */ 1938c2ecf20Sopenharmony_ci if (xattr_len == 21) { 1948c2ecf20Sopenharmony_ci unsigned int zero = 0; 1958c2ecf20Sopenharmony_ci if (!memcmp(&xattr_value->data[16], &zero, 4)) 1968c2ecf20Sopenharmony_ci return HASH_ALGO_MD5; 1978c2ecf20Sopenharmony_ci else 1988c2ecf20Sopenharmony_ci return HASH_ALGO_SHA1; 1998c2ecf20Sopenharmony_ci } else if (xattr_len == 17) 2008c2ecf20Sopenharmony_ci return HASH_ALGO_MD5; 2018c2ecf20Sopenharmony_ci break; 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci /* return default hash algo */ 2058c2ecf20Sopenharmony_ci return ima_hash_algo; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ciint ima_read_xattr(struct dentry *dentry, 2098c2ecf20Sopenharmony_ci struct evm_ima_xattr_data **xattr_value) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci ssize_t ret; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci ret = vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)xattr_value, 2148c2ecf20Sopenharmony_ci 0, GFP_NOFS); 2158c2ecf20Sopenharmony_ci if (ret == -EOPNOTSUPP) 2168c2ecf20Sopenharmony_ci ret = 0; 2178c2ecf20Sopenharmony_ci return ret; 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci/* 2218c2ecf20Sopenharmony_ci * xattr_verify - verify xattr digest or signature 2228c2ecf20Sopenharmony_ci * 2238c2ecf20Sopenharmony_ci * Verify whether the hash or signature matches the file contents. 2248c2ecf20Sopenharmony_ci * 2258c2ecf20Sopenharmony_ci * Return 0 on success, error code otherwise. 2268c2ecf20Sopenharmony_ci */ 2278c2ecf20Sopenharmony_cistatic int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint, 2288c2ecf20Sopenharmony_ci struct evm_ima_xattr_data *xattr_value, int xattr_len, 2298c2ecf20Sopenharmony_ci enum integrity_status *status, const char **cause) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci int rc = -EINVAL, hash_start = 0; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci switch (xattr_value->type) { 2348c2ecf20Sopenharmony_ci case IMA_XATTR_DIGEST_NG: 2358c2ecf20Sopenharmony_ci /* first byte contains algorithm id */ 2368c2ecf20Sopenharmony_ci hash_start = 1; 2378c2ecf20Sopenharmony_ci fallthrough; 2388c2ecf20Sopenharmony_ci case IMA_XATTR_DIGEST: 2398c2ecf20Sopenharmony_ci if (iint->flags & IMA_DIGSIG_REQUIRED) { 2408c2ecf20Sopenharmony_ci *cause = "IMA-signature-required"; 2418c2ecf20Sopenharmony_ci *status = INTEGRITY_FAIL; 2428c2ecf20Sopenharmony_ci break; 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci clear_bit(IMA_DIGSIG, &iint->atomic_flags); 2458c2ecf20Sopenharmony_ci if (xattr_len - sizeof(xattr_value->type) - hash_start >= 2468c2ecf20Sopenharmony_ci iint->ima_hash->length) 2478c2ecf20Sopenharmony_ci /* 2488c2ecf20Sopenharmony_ci * xattr length may be longer. md5 hash in previous 2498c2ecf20Sopenharmony_ci * version occupied 20 bytes in xattr, instead of 16 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_ci rc = memcmp(&xattr_value->data[hash_start], 2528c2ecf20Sopenharmony_ci iint->ima_hash->digest, 2538c2ecf20Sopenharmony_ci iint->ima_hash->length); 2548c2ecf20Sopenharmony_ci else 2558c2ecf20Sopenharmony_ci rc = -EINVAL; 2568c2ecf20Sopenharmony_ci if (rc) { 2578c2ecf20Sopenharmony_ci *cause = "invalid-hash"; 2588c2ecf20Sopenharmony_ci *status = INTEGRITY_FAIL; 2598c2ecf20Sopenharmony_ci break; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci *status = INTEGRITY_PASS; 2628c2ecf20Sopenharmony_ci break; 2638c2ecf20Sopenharmony_ci case EVM_IMA_XATTR_DIGSIG: 2648c2ecf20Sopenharmony_ci set_bit(IMA_DIGSIG, &iint->atomic_flags); 2658c2ecf20Sopenharmony_ci rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA, 2668c2ecf20Sopenharmony_ci (const char *)xattr_value, 2678c2ecf20Sopenharmony_ci xattr_len, 2688c2ecf20Sopenharmony_ci iint->ima_hash->digest, 2698c2ecf20Sopenharmony_ci iint->ima_hash->length); 2708c2ecf20Sopenharmony_ci if (rc == -EOPNOTSUPP) { 2718c2ecf20Sopenharmony_ci *status = INTEGRITY_UNKNOWN; 2728c2ecf20Sopenharmony_ci break; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING) && rc && 2758c2ecf20Sopenharmony_ci func == KEXEC_KERNEL_CHECK) 2768c2ecf20Sopenharmony_ci rc = integrity_digsig_verify(INTEGRITY_KEYRING_PLATFORM, 2778c2ecf20Sopenharmony_ci (const char *)xattr_value, 2788c2ecf20Sopenharmony_ci xattr_len, 2798c2ecf20Sopenharmony_ci iint->ima_hash->digest, 2808c2ecf20Sopenharmony_ci iint->ima_hash->length); 2818c2ecf20Sopenharmony_ci if (rc) { 2828c2ecf20Sopenharmony_ci *cause = "invalid-signature"; 2838c2ecf20Sopenharmony_ci *status = INTEGRITY_FAIL; 2848c2ecf20Sopenharmony_ci } else { 2858c2ecf20Sopenharmony_ci *status = INTEGRITY_PASS; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci break; 2888c2ecf20Sopenharmony_ci default: 2898c2ecf20Sopenharmony_ci *status = INTEGRITY_UNKNOWN; 2908c2ecf20Sopenharmony_ci *cause = "unknown-ima-data"; 2918c2ecf20Sopenharmony_ci break; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci return rc; 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci/* 2988c2ecf20Sopenharmony_ci * modsig_verify - verify modsig signature 2998c2ecf20Sopenharmony_ci * 3008c2ecf20Sopenharmony_ci * Verify whether the signature matches the file contents. 3018c2ecf20Sopenharmony_ci * 3028c2ecf20Sopenharmony_ci * Return 0 on success, error code otherwise. 3038c2ecf20Sopenharmony_ci */ 3048c2ecf20Sopenharmony_cistatic int modsig_verify(enum ima_hooks func, const struct modsig *modsig, 3058c2ecf20Sopenharmony_ci enum integrity_status *status, const char **cause) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci int rc; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci rc = integrity_modsig_verify(INTEGRITY_KEYRING_IMA, modsig); 3108c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING) && rc && 3118c2ecf20Sopenharmony_ci func == KEXEC_KERNEL_CHECK) 3128c2ecf20Sopenharmony_ci rc = integrity_modsig_verify(INTEGRITY_KEYRING_PLATFORM, 3138c2ecf20Sopenharmony_ci modsig); 3148c2ecf20Sopenharmony_ci if (rc) { 3158c2ecf20Sopenharmony_ci *cause = "invalid-signature"; 3168c2ecf20Sopenharmony_ci *status = INTEGRITY_FAIL; 3178c2ecf20Sopenharmony_ci } else { 3188c2ecf20Sopenharmony_ci *status = INTEGRITY_PASS; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci return rc; 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci/* 3258c2ecf20Sopenharmony_ci * ima_check_blacklist - determine if the binary is blacklisted. 3268c2ecf20Sopenharmony_ci * 3278c2ecf20Sopenharmony_ci * Add the hash of the blacklisted binary to the measurement list, based 3288c2ecf20Sopenharmony_ci * on policy. 3298c2ecf20Sopenharmony_ci * 3308c2ecf20Sopenharmony_ci * Returns -EPERM if the hash is blacklisted. 3318c2ecf20Sopenharmony_ci */ 3328c2ecf20Sopenharmony_ciint ima_check_blacklist(struct integrity_iint_cache *iint, 3338c2ecf20Sopenharmony_ci const struct modsig *modsig, int pcr) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci enum hash_algo hash_algo; 3368c2ecf20Sopenharmony_ci const u8 *digest = NULL; 3378c2ecf20Sopenharmony_ci u32 digestsize = 0; 3388c2ecf20Sopenharmony_ci int rc = 0; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci if (!(iint->flags & IMA_CHECK_BLACKLIST)) 3418c2ecf20Sopenharmony_ci return 0; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci if (iint->flags & IMA_MODSIG_ALLOWED && modsig) { 3448c2ecf20Sopenharmony_ci ima_get_modsig_digest(modsig, &hash_algo, &digest, &digestsize); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci rc = is_binary_blacklisted(digest, digestsize); 3478c2ecf20Sopenharmony_ci if ((rc == -EPERM) && (iint->flags & IMA_MEASURE)) 3488c2ecf20Sopenharmony_ci process_buffer_measurement(NULL, digest, digestsize, 3498c2ecf20Sopenharmony_ci "blacklisted-hash", NONE, 3508c2ecf20Sopenharmony_ci pcr, NULL); 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci return rc; 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci/* 3578c2ecf20Sopenharmony_ci * ima_appraise_measurement - appraise file measurement 3588c2ecf20Sopenharmony_ci * 3598c2ecf20Sopenharmony_ci * Call evm_verifyxattr() to verify the integrity of 'security.ima'. 3608c2ecf20Sopenharmony_ci * Assuming success, compare the xattr hash with the collected measurement. 3618c2ecf20Sopenharmony_ci * 3628c2ecf20Sopenharmony_ci * Return 0 on success, error code otherwise 3638c2ecf20Sopenharmony_ci */ 3648c2ecf20Sopenharmony_ciint ima_appraise_measurement(enum ima_hooks func, 3658c2ecf20Sopenharmony_ci struct integrity_iint_cache *iint, 3668c2ecf20Sopenharmony_ci struct file *file, const unsigned char *filename, 3678c2ecf20Sopenharmony_ci struct evm_ima_xattr_data *xattr_value, 3688c2ecf20Sopenharmony_ci int xattr_len, const struct modsig *modsig) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci static const char op[] = "appraise_data"; 3718c2ecf20Sopenharmony_ci const char *cause = "unknown"; 3728c2ecf20Sopenharmony_ci struct dentry *dentry = file_dentry(file); 3738c2ecf20Sopenharmony_ci struct inode *inode = d_backing_inode(dentry); 3748c2ecf20Sopenharmony_ci enum integrity_status status = INTEGRITY_UNKNOWN; 3758c2ecf20Sopenharmony_ci int rc = xattr_len; 3768c2ecf20Sopenharmony_ci bool try_modsig = iint->flags & IMA_MODSIG_ALLOWED && modsig; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci /* If not appraising a modsig, we need an xattr. */ 3798c2ecf20Sopenharmony_ci if (!(inode->i_opflags & IOP_XATTR) && !try_modsig) 3808c2ecf20Sopenharmony_ci return INTEGRITY_UNKNOWN; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci /* If reading the xattr failed and there's no modsig, error out. */ 3838c2ecf20Sopenharmony_ci if (rc <= 0 && !try_modsig) { 3848c2ecf20Sopenharmony_ci if (rc && rc != -ENODATA) 3858c2ecf20Sopenharmony_ci goto out; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci cause = iint->flags & IMA_DIGSIG_REQUIRED ? 3888c2ecf20Sopenharmony_ci "IMA-signature-required" : "missing-hash"; 3898c2ecf20Sopenharmony_ci status = INTEGRITY_NOLABEL; 3908c2ecf20Sopenharmony_ci if (file->f_mode & FMODE_CREATED) 3918c2ecf20Sopenharmony_ci iint->flags |= IMA_NEW_FILE; 3928c2ecf20Sopenharmony_ci if ((iint->flags & IMA_NEW_FILE) && 3938c2ecf20Sopenharmony_ci (!(iint->flags & IMA_DIGSIG_REQUIRED) || 3948c2ecf20Sopenharmony_ci (inode->i_size == 0))) 3958c2ecf20Sopenharmony_ci status = INTEGRITY_PASS; 3968c2ecf20Sopenharmony_ci goto out; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value, 4008c2ecf20Sopenharmony_ci rc < 0 ? 0 : rc, iint); 4018c2ecf20Sopenharmony_ci switch (status) { 4028c2ecf20Sopenharmony_ci case INTEGRITY_PASS: 4038c2ecf20Sopenharmony_ci case INTEGRITY_PASS_IMMUTABLE: 4048c2ecf20Sopenharmony_ci case INTEGRITY_UNKNOWN: 4058c2ecf20Sopenharmony_ci break; 4068c2ecf20Sopenharmony_ci case INTEGRITY_NOXATTRS: /* No EVM protected xattrs. */ 4078c2ecf20Sopenharmony_ci /* It's fine not to have xattrs when using a modsig. */ 4088c2ecf20Sopenharmony_ci if (try_modsig) 4098c2ecf20Sopenharmony_ci break; 4108c2ecf20Sopenharmony_ci fallthrough; 4118c2ecf20Sopenharmony_ci case INTEGRITY_NOLABEL: /* No security.evm xattr. */ 4128c2ecf20Sopenharmony_ci cause = "missing-HMAC"; 4138c2ecf20Sopenharmony_ci goto out; 4148c2ecf20Sopenharmony_ci case INTEGRITY_FAIL: /* Invalid HMAC/signature. */ 4158c2ecf20Sopenharmony_ci cause = "invalid-HMAC"; 4168c2ecf20Sopenharmony_ci goto out; 4178c2ecf20Sopenharmony_ci default: 4188c2ecf20Sopenharmony_ci WARN_ONCE(true, "Unexpected integrity status %d\n", status); 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci if (xattr_value) 4228c2ecf20Sopenharmony_ci rc = xattr_verify(func, iint, xattr_value, xattr_len, &status, 4238c2ecf20Sopenharmony_ci &cause); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci /* 4268c2ecf20Sopenharmony_ci * If we have a modsig and either no imasig or the imasig's key isn't 4278c2ecf20Sopenharmony_ci * known, then try verifying the modsig. 4288c2ecf20Sopenharmony_ci */ 4298c2ecf20Sopenharmony_ci if (try_modsig && 4308c2ecf20Sopenharmony_ci (!xattr_value || xattr_value->type == IMA_XATTR_DIGEST_NG || 4318c2ecf20Sopenharmony_ci rc == -ENOKEY)) 4328c2ecf20Sopenharmony_ci rc = modsig_verify(func, modsig, &status, &cause); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ciout: 4358c2ecf20Sopenharmony_ci /* 4368c2ecf20Sopenharmony_ci * File signatures on some filesystems can not be properly verified. 4378c2ecf20Sopenharmony_ci * When such filesystems are mounted by an untrusted mounter or on a 4388c2ecf20Sopenharmony_ci * system not willing to accept such a risk, fail the file signature 4398c2ecf20Sopenharmony_ci * verification. 4408c2ecf20Sopenharmony_ci */ 4418c2ecf20Sopenharmony_ci if ((inode->i_sb->s_iflags & SB_I_IMA_UNVERIFIABLE_SIGNATURE) && 4428c2ecf20Sopenharmony_ci ((inode->i_sb->s_iflags & SB_I_UNTRUSTED_MOUNTER) || 4438c2ecf20Sopenharmony_ci (iint->flags & IMA_FAIL_UNVERIFIABLE_SIGS))) { 4448c2ecf20Sopenharmony_ci status = INTEGRITY_FAIL; 4458c2ecf20Sopenharmony_ci cause = "unverifiable-signature"; 4468c2ecf20Sopenharmony_ci integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename, 4478c2ecf20Sopenharmony_ci op, cause, rc, 0); 4488c2ecf20Sopenharmony_ci } else if (status != INTEGRITY_PASS) { 4498c2ecf20Sopenharmony_ci /* Fix mode, but don't replace file signatures. */ 4508c2ecf20Sopenharmony_ci if ((ima_appraise & IMA_APPRAISE_FIX) && !try_modsig && 4518c2ecf20Sopenharmony_ci (!xattr_value || 4528c2ecf20Sopenharmony_ci xattr_value->type != EVM_IMA_XATTR_DIGSIG)) { 4538c2ecf20Sopenharmony_ci if (!ima_fix_xattr(dentry, iint)) 4548c2ecf20Sopenharmony_ci status = INTEGRITY_PASS; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci /* Permit new files with file signatures, but without data. */ 4588c2ecf20Sopenharmony_ci if (inode->i_size == 0 && iint->flags & IMA_NEW_FILE && 4598c2ecf20Sopenharmony_ci xattr_value && xattr_value->type == EVM_IMA_XATTR_DIGSIG) { 4608c2ecf20Sopenharmony_ci status = INTEGRITY_PASS; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename, 4648c2ecf20Sopenharmony_ci op, cause, rc, 0); 4658c2ecf20Sopenharmony_ci } else { 4668c2ecf20Sopenharmony_ci ima_cache_flags(iint, func); 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci ima_set_cache_status(iint, func, status); 4708c2ecf20Sopenharmony_ci return status; 4718c2ecf20Sopenharmony_ci} 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci/* 4748c2ecf20Sopenharmony_ci * ima_update_xattr - update 'security.ima' hash value 4758c2ecf20Sopenharmony_ci */ 4768c2ecf20Sopenharmony_civoid ima_update_xattr(struct integrity_iint_cache *iint, struct file *file) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci struct dentry *dentry = file_dentry(file); 4798c2ecf20Sopenharmony_ci int rc = 0; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci /* do not collect and update hash for digital signatures */ 4828c2ecf20Sopenharmony_ci if (test_bit(IMA_DIGSIG, &iint->atomic_flags)) 4838c2ecf20Sopenharmony_ci return; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci if ((iint->ima_file_status != INTEGRITY_PASS) && 4868c2ecf20Sopenharmony_ci !(iint->flags & IMA_HASH)) 4878c2ecf20Sopenharmony_ci return; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci rc = ima_collect_measurement(iint, file, NULL, 0, ima_hash_algo, NULL); 4908c2ecf20Sopenharmony_ci if (rc < 0) 4918c2ecf20Sopenharmony_ci return; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci inode_lock(file_inode(file)); 4948c2ecf20Sopenharmony_ci ima_fix_xattr(dentry, iint); 4958c2ecf20Sopenharmony_ci inode_unlock(file_inode(file)); 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci/** 4998c2ecf20Sopenharmony_ci * ima_inode_post_setattr - reflect file metadata changes 5008c2ecf20Sopenharmony_ci * @dentry: pointer to the affected dentry 5018c2ecf20Sopenharmony_ci * 5028c2ecf20Sopenharmony_ci * Changes to a dentry's metadata might result in needing to appraise. 5038c2ecf20Sopenharmony_ci * 5048c2ecf20Sopenharmony_ci * This function is called from notify_change(), which expects the caller 5058c2ecf20Sopenharmony_ci * to lock the inode's i_mutex. 5068c2ecf20Sopenharmony_ci */ 5078c2ecf20Sopenharmony_civoid ima_inode_post_setattr(struct dentry *dentry) 5088c2ecf20Sopenharmony_ci{ 5098c2ecf20Sopenharmony_ci struct inode *inode = d_backing_inode(dentry); 5108c2ecf20Sopenharmony_ci struct integrity_iint_cache *iint; 5118c2ecf20Sopenharmony_ci int action; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode) 5148c2ecf20Sopenharmony_ci || !(inode->i_opflags & IOP_XATTR)) 5158c2ecf20Sopenharmony_ci return; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci action = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR); 5188c2ecf20Sopenharmony_ci if (!action) 5198c2ecf20Sopenharmony_ci __vfs_removexattr(dentry, XATTR_NAME_IMA); 5208c2ecf20Sopenharmony_ci iint = integrity_iint_find(inode); 5218c2ecf20Sopenharmony_ci if (iint) { 5228c2ecf20Sopenharmony_ci set_bit(IMA_CHANGE_ATTR, &iint->atomic_flags); 5238c2ecf20Sopenharmony_ci if (!action) 5248c2ecf20Sopenharmony_ci clear_bit(IMA_UPDATE_XATTR, &iint->atomic_flags); 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci/* 5298c2ecf20Sopenharmony_ci * ima_protect_xattr - protect 'security.ima' 5308c2ecf20Sopenharmony_ci * 5318c2ecf20Sopenharmony_ci * Ensure that not just anyone can modify or remove 'security.ima'. 5328c2ecf20Sopenharmony_ci */ 5338c2ecf20Sopenharmony_cistatic int ima_protect_xattr(struct dentry *dentry, const char *xattr_name, 5348c2ecf20Sopenharmony_ci const void *xattr_value, size_t xattr_value_len) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci if (strcmp(xattr_name, XATTR_NAME_IMA) == 0) { 5378c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 5388c2ecf20Sopenharmony_ci return -EPERM; 5398c2ecf20Sopenharmony_ci return 1; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci return 0; 5428c2ecf20Sopenharmony_ci} 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_cistatic void ima_reset_appraise_flags(struct inode *inode, int digsig) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci struct integrity_iint_cache *iint; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)) 5498c2ecf20Sopenharmony_ci return; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci iint = integrity_iint_find(inode); 5528c2ecf20Sopenharmony_ci if (!iint) 5538c2ecf20Sopenharmony_ci return; 5548c2ecf20Sopenharmony_ci iint->measured_pcrs = 0; 5558c2ecf20Sopenharmony_ci set_bit(IMA_CHANGE_XATTR, &iint->atomic_flags); 5568c2ecf20Sopenharmony_ci if (digsig) 5578c2ecf20Sopenharmony_ci set_bit(IMA_DIGSIG, &iint->atomic_flags); 5588c2ecf20Sopenharmony_ci else 5598c2ecf20Sopenharmony_ci clear_bit(IMA_DIGSIG, &iint->atomic_flags); 5608c2ecf20Sopenharmony_ci} 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ciint ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, 5638c2ecf20Sopenharmony_ci const void *xattr_value, size_t xattr_value_len) 5648c2ecf20Sopenharmony_ci{ 5658c2ecf20Sopenharmony_ci const struct evm_ima_xattr_data *xvalue = xattr_value; 5668c2ecf20Sopenharmony_ci int result; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci result = ima_protect_xattr(dentry, xattr_name, xattr_value, 5698c2ecf20Sopenharmony_ci xattr_value_len); 5708c2ecf20Sopenharmony_ci if (result == 1) { 5718c2ecf20Sopenharmony_ci if (!xattr_value_len || (xvalue->type >= IMA_XATTR_LAST)) 5728c2ecf20Sopenharmony_ci return -EINVAL; 5738c2ecf20Sopenharmony_ci ima_reset_appraise_flags(d_backing_inode(dentry), 5748c2ecf20Sopenharmony_ci xvalue->type == EVM_IMA_XATTR_DIGSIG); 5758c2ecf20Sopenharmony_ci result = 0; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci return result; 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ciint ima_inode_removexattr(struct dentry *dentry, const char *xattr_name) 5818c2ecf20Sopenharmony_ci{ 5828c2ecf20Sopenharmony_ci int result; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci result = ima_protect_xattr(dentry, xattr_name, NULL, 0); 5858c2ecf20Sopenharmony_ci if (result == 1) { 5868c2ecf20Sopenharmony_ci ima_reset_appraise_flags(d_backing_inode(dentry), 0); 5878c2ecf20Sopenharmony_ci result = 0; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci return result; 5908c2ecf20Sopenharmony_ci} 591