18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2008 IBM Corporation 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author: Mimi Zohar <zohar@us.ibm.com> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * File: ima_api.c 88c2ecf20Sopenharmony_ci * Implements must_appraise_or_measure, collect_measurement, 98c2ecf20Sopenharmony_ci * appraise_measurement, store_measurement and store_template. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/file.h> 138c2ecf20Sopenharmony_ci#include <linux/fs.h> 148c2ecf20Sopenharmony_ci#include <linux/xattr.h> 158c2ecf20Sopenharmony_ci#include <linux/evm.h> 168c2ecf20Sopenharmony_ci#include <linux/iversion.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "ima.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* 218c2ecf20Sopenharmony_ci * ima_free_template_entry - free an existing template entry 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_civoid ima_free_template_entry(struct ima_template_entry *entry) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci int i; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci for (i = 0; i < entry->template_desc->num_fields; i++) 288c2ecf20Sopenharmony_ci kfree(entry->template_data[i].data); 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci kfree(entry->digests); 318c2ecf20Sopenharmony_ci kfree(entry); 328c2ecf20Sopenharmony_ci} 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* 358c2ecf20Sopenharmony_ci * ima_alloc_init_template - create and initialize a new template entry 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_ciint ima_alloc_init_template(struct ima_event_data *event_data, 388c2ecf20Sopenharmony_ci struct ima_template_entry **entry, 398c2ecf20Sopenharmony_ci struct ima_template_desc *desc) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci struct ima_template_desc *template_desc; 428c2ecf20Sopenharmony_ci struct tpm_digest *digests; 438c2ecf20Sopenharmony_ci int i, result = 0; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci if (desc) 468c2ecf20Sopenharmony_ci template_desc = desc; 478c2ecf20Sopenharmony_ci else 488c2ecf20Sopenharmony_ci template_desc = ima_template_desc_current(); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci *entry = kzalloc(struct_size(*entry, template_data, 518c2ecf20Sopenharmony_ci template_desc->num_fields), GFP_NOFS); 528c2ecf20Sopenharmony_ci if (!*entry) 538c2ecf20Sopenharmony_ci return -ENOMEM; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci digests = kcalloc(NR_BANKS(ima_tpm_chip) + ima_extra_slots, 568c2ecf20Sopenharmony_ci sizeof(*digests), GFP_NOFS); 578c2ecf20Sopenharmony_ci if (!digests) { 588c2ecf20Sopenharmony_ci kfree(*entry); 598c2ecf20Sopenharmony_ci *entry = NULL; 608c2ecf20Sopenharmony_ci return -ENOMEM; 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci (*entry)->digests = digests; 648c2ecf20Sopenharmony_ci (*entry)->template_desc = template_desc; 658c2ecf20Sopenharmony_ci for (i = 0; i < template_desc->num_fields; i++) { 668c2ecf20Sopenharmony_ci const struct ima_template_field *field = 678c2ecf20Sopenharmony_ci template_desc->fields[i]; 688c2ecf20Sopenharmony_ci u32 len; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci result = field->field_init(event_data, 718c2ecf20Sopenharmony_ci &((*entry)->template_data[i])); 728c2ecf20Sopenharmony_ci if (result != 0) 738c2ecf20Sopenharmony_ci goto out; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci len = (*entry)->template_data[i].len; 768c2ecf20Sopenharmony_ci (*entry)->template_data_len += sizeof(len); 778c2ecf20Sopenharmony_ci (*entry)->template_data_len += len; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci return 0; 808c2ecf20Sopenharmony_ciout: 818c2ecf20Sopenharmony_ci ima_free_template_entry(*entry); 828c2ecf20Sopenharmony_ci *entry = NULL; 838c2ecf20Sopenharmony_ci return result; 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci/* 878c2ecf20Sopenharmony_ci * ima_store_template - store ima template measurements 888c2ecf20Sopenharmony_ci * 898c2ecf20Sopenharmony_ci * Calculate the hash of a template entry, add the template entry 908c2ecf20Sopenharmony_ci * to an ordered list of measurement entries maintained inside the kernel, 918c2ecf20Sopenharmony_ci * and also update the aggregate integrity value (maintained inside the 928c2ecf20Sopenharmony_ci * configured TPM PCR) over the hashes of the current list of measurement 938c2ecf20Sopenharmony_ci * entries. 948c2ecf20Sopenharmony_ci * 958c2ecf20Sopenharmony_ci * Applications retrieve the current kernel-held measurement list through 968c2ecf20Sopenharmony_ci * the securityfs entries in /sys/kernel/security/ima. The signed aggregate 978c2ecf20Sopenharmony_ci * TPM PCR (called quote) can be retrieved using a TPM user space library 988c2ecf20Sopenharmony_ci * and is used to validate the measurement list. 998c2ecf20Sopenharmony_ci * 1008c2ecf20Sopenharmony_ci * Returns 0 on success, error code otherwise 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_ciint ima_store_template(struct ima_template_entry *entry, 1038c2ecf20Sopenharmony_ci int violation, struct inode *inode, 1048c2ecf20Sopenharmony_ci const unsigned char *filename, int pcr) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci static const char op[] = "add_template_measure"; 1078c2ecf20Sopenharmony_ci static const char audit_cause[] = "hashing_error"; 1088c2ecf20Sopenharmony_ci char *template_name = entry->template_desc->name; 1098c2ecf20Sopenharmony_ci int result; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (!violation) { 1128c2ecf20Sopenharmony_ci result = ima_calc_field_array_hash(&entry->template_data[0], 1138c2ecf20Sopenharmony_ci entry); 1148c2ecf20Sopenharmony_ci if (result < 0) { 1158c2ecf20Sopenharmony_ci integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, 1168c2ecf20Sopenharmony_ci template_name, op, 1178c2ecf20Sopenharmony_ci audit_cause, result, 0); 1188c2ecf20Sopenharmony_ci return result; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci entry->pcr = pcr; 1228c2ecf20Sopenharmony_ci result = ima_add_template_entry(entry, violation, op, inode, filename); 1238c2ecf20Sopenharmony_ci return result; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci/* 1278c2ecf20Sopenharmony_ci * ima_add_violation - add violation to measurement list. 1288c2ecf20Sopenharmony_ci * 1298c2ecf20Sopenharmony_ci * Violations are flagged in the measurement list with zero hash values. 1308c2ecf20Sopenharmony_ci * By extending the PCR with 0xFF's instead of with zeroes, the PCR 1318c2ecf20Sopenharmony_ci * value is invalidated. 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_civoid ima_add_violation(struct file *file, const unsigned char *filename, 1348c2ecf20Sopenharmony_ci struct integrity_iint_cache *iint, 1358c2ecf20Sopenharmony_ci const char *op, const char *cause) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct ima_template_entry *entry; 1388c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 1398c2ecf20Sopenharmony_ci struct ima_event_data event_data = { .iint = iint, 1408c2ecf20Sopenharmony_ci .file = file, 1418c2ecf20Sopenharmony_ci .filename = filename, 1428c2ecf20Sopenharmony_ci .violation = cause }; 1438c2ecf20Sopenharmony_ci int violation = 1; 1448c2ecf20Sopenharmony_ci int result; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci /* can overflow, only indicator */ 1478c2ecf20Sopenharmony_ci atomic_long_inc(&ima_htable.violations); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci result = ima_alloc_init_template(&event_data, &entry, NULL); 1508c2ecf20Sopenharmony_ci if (result < 0) { 1518c2ecf20Sopenharmony_ci result = -ENOMEM; 1528c2ecf20Sopenharmony_ci goto err_out; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci result = ima_store_template(entry, violation, inode, 1558c2ecf20Sopenharmony_ci filename, CONFIG_IMA_MEASURE_PCR_IDX); 1568c2ecf20Sopenharmony_ci if (result < 0) 1578c2ecf20Sopenharmony_ci ima_free_template_entry(entry); 1588c2ecf20Sopenharmony_cierr_out: 1598c2ecf20Sopenharmony_ci integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename, 1608c2ecf20Sopenharmony_ci op, cause, result, 0); 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci/** 1648c2ecf20Sopenharmony_ci * ima_get_action - appraise & measure decision based on policy. 1658c2ecf20Sopenharmony_ci * @inode: pointer to the inode associated with the object being validated 1668c2ecf20Sopenharmony_ci * @cred: pointer to credentials structure to validate 1678c2ecf20Sopenharmony_ci * @secid: secid of the task being validated 1688c2ecf20Sopenharmony_ci * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXEC, 1698c2ecf20Sopenharmony_ci * MAY_APPEND) 1708c2ecf20Sopenharmony_ci * @func: caller identifier 1718c2ecf20Sopenharmony_ci * @pcr: pointer filled in if matched measure policy sets pcr= 1728c2ecf20Sopenharmony_ci * @template_desc: pointer filled in if matched measure policy sets template= 1738c2ecf20Sopenharmony_ci * @keyring: keyring name used to determine the action 1748c2ecf20Sopenharmony_ci * 1758c2ecf20Sopenharmony_ci * The policy is defined in terms of keypairs: 1768c2ecf20Sopenharmony_ci * subj=, obj=, type=, func=, mask=, fsmagic= 1778c2ecf20Sopenharmony_ci * subj,obj, and type: are LSM specific. 1788c2ecf20Sopenharmony_ci * func: FILE_CHECK | BPRM_CHECK | CREDS_CHECK | MMAP_CHECK | MODULE_CHECK 1798c2ecf20Sopenharmony_ci * | KEXEC_CMDLINE | KEY_CHECK 1808c2ecf20Sopenharmony_ci * mask: contains the permission mask 1818c2ecf20Sopenharmony_ci * fsmagic: hex value 1828c2ecf20Sopenharmony_ci * 1838c2ecf20Sopenharmony_ci * Returns IMA_MEASURE, IMA_APPRAISE mask. 1848c2ecf20Sopenharmony_ci * 1858c2ecf20Sopenharmony_ci */ 1868c2ecf20Sopenharmony_ciint ima_get_action(struct inode *inode, const struct cred *cred, u32 secid, 1878c2ecf20Sopenharmony_ci int mask, enum ima_hooks func, int *pcr, 1888c2ecf20Sopenharmony_ci struct ima_template_desc **template_desc, 1898c2ecf20Sopenharmony_ci const char *keyring) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE | IMA_HASH; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci flags &= ima_policy_flag; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci return ima_match_policy(inode, cred, secid, func, mask, flags, pcr, 1968c2ecf20Sopenharmony_ci template_desc, keyring); 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci/* 2008c2ecf20Sopenharmony_ci * ima_collect_measurement - collect file measurement 2018c2ecf20Sopenharmony_ci * 2028c2ecf20Sopenharmony_ci * Calculate the file hash, if it doesn't already exist, 2038c2ecf20Sopenharmony_ci * storing the measurement and i_version in the iint. 2048c2ecf20Sopenharmony_ci * 2058c2ecf20Sopenharmony_ci * Must be called with iint->mutex held. 2068c2ecf20Sopenharmony_ci * 2078c2ecf20Sopenharmony_ci * Return 0 on success, error code otherwise 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_ciint ima_collect_measurement(struct integrity_iint_cache *iint, 2108c2ecf20Sopenharmony_ci struct file *file, void *buf, loff_t size, 2118c2ecf20Sopenharmony_ci enum hash_algo algo, struct modsig *modsig) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci const char *audit_cause = "failed"; 2148c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 2158c2ecf20Sopenharmony_ci struct inode *real_inode = d_real_inode(file_dentry(file)); 2168c2ecf20Sopenharmony_ci const char *filename = file->f_path.dentry->d_name.name; 2178c2ecf20Sopenharmony_ci int result = 0; 2188c2ecf20Sopenharmony_ci int length; 2198c2ecf20Sopenharmony_ci void *tmpbuf; 2208c2ecf20Sopenharmony_ci u64 i_version; 2218c2ecf20Sopenharmony_ci struct { 2228c2ecf20Sopenharmony_ci struct ima_digest_data hdr; 2238c2ecf20Sopenharmony_ci char digest[IMA_MAX_DIGEST_SIZE]; 2248c2ecf20Sopenharmony_ci } hash; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* 2278c2ecf20Sopenharmony_ci * Always collect the modsig, because IMA might have already collected 2288c2ecf20Sopenharmony_ci * the file digest without collecting the modsig in a previous 2298c2ecf20Sopenharmony_ci * measurement rule. 2308c2ecf20Sopenharmony_ci */ 2318c2ecf20Sopenharmony_ci if (modsig) 2328c2ecf20Sopenharmony_ci ima_collect_modsig(modsig, buf, size); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci if (iint->flags & IMA_COLLECTED) 2358c2ecf20Sopenharmony_ci goto out; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci /* 2388c2ecf20Sopenharmony_ci * Dectecting file change is based on i_version. On filesystems 2398c2ecf20Sopenharmony_ci * which do not support i_version, support is limited to an initial 2408c2ecf20Sopenharmony_ci * measurement/appraisal/audit. 2418c2ecf20Sopenharmony_ci */ 2428c2ecf20Sopenharmony_ci i_version = inode_query_iversion(inode); 2438c2ecf20Sopenharmony_ci hash.hdr.algo = algo; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci /* Initialize hash digest to 0's in case of failure */ 2468c2ecf20Sopenharmony_ci memset(&hash.digest, 0, sizeof(hash.digest)); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (buf) 2498c2ecf20Sopenharmony_ci result = ima_calc_buffer_hash(buf, size, &hash.hdr); 2508c2ecf20Sopenharmony_ci else 2518c2ecf20Sopenharmony_ci result = ima_calc_file_hash(file, &hash.hdr); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (result && result != -EBADF && result != -EINVAL) 2548c2ecf20Sopenharmony_ci goto out; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci length = sizeof(hash.hdr) + hash.hdr.length; 2578c2ecf20Sopenharmony_ci tmpbuf = krealloc(iint->ima_hash, length, GFP_NOFS); 2588c2ecf20Sopenharmony_ci if (!tmpbuf) { 2598c2ecf20Sopenharmony_ci result = -ENOMEM; 2608c2ecf20Sopenharmony_ci goto out; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci iint->ima_hash = tmpbuf; 2648c2ecf20Sopenharmony_ci memcpy(iint->ima_hash, &hash, length); 2658c2ecf20Sopenharmony_ci iint->version = i_version; 2668c2ecf20Sopenharmony_ci if (real_inode != inode) { 2678c2ecf20Sopenharmony_ci iint->real_ino = real_inode->i_ino; 2688c2ecf20Sopenharmony_ci iint->real_dev = real_inode->i_sb->s_dev; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci /* Possibly temporary failure due to type of read (eg. O_DIRECT) */ 2728c2ecf20Sopenharmony_ci if (!result) 2738c2ecf20Sopenharmony_ci iint->flags |= IMA_COLLECTED; 2748c2ecf20Sopenharmony_ciout: 2758c2ecf20Sopenharmony_ci if (result) { 2768c2ecf20Sopenharmony_ci if (file->f_flags & O_DIRECT) 2778c2ecf20Sopenharmony_ci audit_cause = "failed(directio)"; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, 2808c2ecf20Sopenharmony_ci filename, "collect_data", audit_cause, 2818c2ecf20Sopenharmony_ci result, 0); 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci return result; 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci/* 2878c2ecf20Sopenharmony_ci * ima_store_measurement - store file measurement 2888c2ecf20Sopenharmony_ci * 2898c2ecf20Sopenharmony_ci * Create an "ima" template and then store the template by calling 2908c2ecf20Sopenharmony_ci * ima_store_template. 2918c2ecf20Sopenharmony_ci * 2928c2ecf20Sopenharmony_ci * We only get here if the inode has not already been measured, 2938c2ecf20Sopenharmony_ci * but the measurement could already exist: 2948c2ecf20Sopenharmony_ci * - multiple copies of the same file on either the same or 2958c2ecf20Sopenharmony_ci * different filesystems. 2968c2ecf20Sopenharmony_ci * - the inode was previously flushed as well as the iint info, 2978c2ecf20Sopenharmony_ci * containing the hashing info. 2988c2ecf20Sopenharmony_ci * 2998c2ecf20Sopenharmony_ci * Must be called with iint->mutex held. 3008c2ecf20Sopenharmony_ci */ 3018c2ecf20Sopenharmony_civoid ima_store_measurement(struct integrity_iint_cache *iint, 3028c2ecf20Sopenharmony_ci struct file *file, const unsigned char *filename, 3038c2ecf20Sopenharmony_ci struct evm_ima_xattr_data *xattr_value, 3048c2ecf20Sopenharmony_ci int xattr_len, const struct modsig *modsig, int pcr, 3058c2ecf20Sopenharmony_ci struct ima_template_desc *template_desc) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci static const char op[] = "add_template_measure"; 3088c2ecf20Sopenharmony_ci static const char audit_cause[] = "ENOMEM"; 3098c2ecf20Sopenharmony_ci int result = -ENOMEM; 3108c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 3118c2ecf20Sopenharmony_ci struct ima_template_entry *entry; 3128c2ecf20Sopenharmony_ci struct ima_event_data event_data = { .iint = iint, 3138c2ecf20Sopenharmony_ci .file = file, 3148c2ecf20Sopenharmony_ci .filename = filename, 3158c2ecf20Sopenharmony_ci .xattr_value = xattr_value, 3168c2ecf20Sopenharmony_ci .xattr_len = xattr_len, 3178c2ecf20Sopenharmony_ci .modsig = modsig }; 3188c2ecf20Sopenharmony_ci int violation = 0; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* 3218c2ecf20Sopenharmony_ci * We still need to store the measurement in the case of MODSIG because 3228c2ecf20Sopenharmony_ci * we only have its contents to put in the list at the time of 3238c2ecf20Sopenharmony_ci * appraisal, but a file measurement from earlier might already exist in 3248c2ecf20Sopenharmony_ci * the measurement list. 3258c2ecf20Sopenharmony_ci */ 3268c2ecf20Sopenharmony_ci if (iint->measured_pcrs & (0x1 << pcr) && !modsig) 3278c2ecf20Sopenharmony_ci return; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci result = ima_alloc_init_template(&event_data, &entry, template_desc); 3308c2ecf20Sopenharmony_ci if (result < 0) { 3318c2ecf20Sopenharmony_ci integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename, 3328c2ecf20Sopenharmony_ci op, audit_cause, result, 0); 3338c2ecf20Sopenharmony_ci return; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci result = ima_store_template(entry, violation, inode, filename, pcr); 3378c2ecf20Sopenharmony_ci if ((!result || result == -EEXIST) && !(file->f_flags & O_DIRECT)) { 3388c2ecf20Sopenharmony_ci iint->flags |= IMA_MEASURED; 3398c2ecf20Sopenharmony_ci iint->measured_pcrs |= (0x1 << pcr); 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci if (result < 0) 3428c2ecf20Sopenharmony_ci ima_free_template_entry(entry); 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_civoid ima_audit_measurement(struct integrity_iint_cache *iint, 3468c2ecf20Sopenharmony_ci const unsigned char *filename) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci struct audit_buffer *ab; 3498c2ecf20Sopenharmony_ci char *hash; 3508c2ecf20Sopenharmony_ci const char *algo_name = hash_algo_name[iint->ima_hash->algo]; 3518c2ecf20Sopenharmony_ci int i; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci if (iint->flags & IMA_AUDITED) 3548c2ecf20Sopenharmony_ci return; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci hash = kzalloc((iint->ima_hash->length * 2) + 1, GFP_KERNEL); 3578c2ecf20Sopenharmony_ci if (!hash) 3588c2ecf20Sopenharmony_ci return; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci for (i = 0; i < iint->ima_hash->length; i++) 3618c2ecf20Sopenharmony_ci hex_byte_pack(hash + (i * 2), iint->ima_hash->digest[i]); 3628c2ecf20Sopenharmony_ci hash[i * 2] = '\0'; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci ab = audit_log_start(audit_context(), GFP_KERNEL, 3658c2ecf20Sopenharmony_ci AUDIT_INTEGRITY_RULE); 3668c2ecf20Sopenharmony_ci if (!ab) 3678c2ecf20Sopenharmony_ci goto out; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci audit_log_format(ab, "file="); 3708c2ecf20Sopenharmony_ci audit_log_untrustedstring(ab, filename); 3718c2ecf20Sopenharmony_ci audit_log_format(ab, " hash=\"%s:%s\"", algo_name, hash); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci audit_log_task_info(ab); 3748c2ecf20Sopenharmony_ci audit_log_end(ab); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci iint->flags |= IMA_AUDITED; 3778c2ecf20Sopenharmony_ciout: 3788c2ecf20Sopenharmony_ci kfree(hash); 3798c2ecf20Sopenharmony_ci return; 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci/* 3838c2ecf20Sopenharmony_ci * ima_d_path - return a pointer to the full pathname 3848c2ecf20Sopenharmony_ci * 3858c2ecf20Sopenharmony_ci * Attempt to return a pointer to the full pathname for use in the 3868c2ecf20Sopenharmony_ci * IMA measurement list, IMA audit records, and auditing logs. 3878c2ecf20Sopenharmony_ci * 3888c2ecf20Sopenharmony_ci * On failure, return a pointer to a copy of the filename, not dname. 3898c2ecf20Sopenharmony_ci * Returning a pointer to dname, could result in using the pointer 3908c2ecf20Sopenharmony_ci * after the memory has been freed. 3918c2ecf20Sopenharmony_ci */ 3928c2ecf20Sopenharmony_ciconst char *ima_d_path(const struct path *path, char **pathbuf, char *namebuf) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci char *pathname = NULL; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci *pathbuf = __getname(); 3978c2ecf20Sopenharmony_ci if (*pathbuf) { 3988c2ecf20Sopenharmony_ci pathname = d_absolute_path(path, *pathbuf, PATH_MAX); 3998c2ecf20Sopenharmony_ci if (IS_ERR(pathname)) { 4008c2ecf20Sopenharmony_ci __putname(*pathbuf); 4018c2ecf20Sopenharmony_ci *pathbuf = NULL; 4028c2ecf20Sopenharmony_ci pathname = NULL; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci if (!pathname) { 4078c2ecf20Sopenharmony_ci strlcpy(namebuf, path->dentry->d_name.name, NAME_MAX); 4088c2ecf20Sopenharmony_ci pathname = namebuf; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci return pathname; 4128c2ecf20Sopenharmony_ci} 413