/* * ima_free_template_entry - free an existing template entry
*/ void ima_free_template_entry(struct ima_template_entry *entry)
{ int i;
for (i = 0; i < entry->template_desc->num_fields; i++)
kfree(entry->template_data[i].data);
kfree(entry->digests);
kfree(entry);
}
/* * ima_alloc_init_template - create and initialize a new template entry
*/ int ima_alloc_init_template(struct ima_event_data *event_data, struct ima_template_entry **entry, struct ima_template_desc *desc)
{ struct ima_template_desc *template_desc; struct tpm_digest *digests; int i, result = 0;
if (desc)
template_desc = desc; else
template_desc = ima_template_desc_current();
*entry = kzalloc(struct_size(*entry, template_data,
template_desc->num_fields), GFP_NOFS); if (!*entry) return -ENOMEM;
/* * ima_store_template - store ima template measurements * * Calculate the hash of a template entry, add the template entry * to an ordered list of measurement entries maintained inside the kernel, * and also update the aggregate integrity value (maintained inside the * configured TPM PCR) over the hashes of the current list of measurement * entries. * * Applications retrieve the current kernel-held measurement list through * the securityfs entries in /sys/kernel/security/ima. The signed aggregate * TPM PCR (called quote) can be retrieved using a TPM user space library * and is used to validate the measurement list. * * Returns 0 on success, error code otherwise
*/ int ima_store_template(struct ima_template_entry *entry, int violation, struct inode *inode, constunsignedchar *filename, int pcr)
{ staticconstchar op[] = "add_template_measure"; staticconstchar audit_cause[] = "hashing_error"; char *template_name = entry->template_desc->name; int result;
if (!violation) {
result = ima_calc_field_array_hash(&entry->template_data[0],
entry); if (result < 0) {
integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
template_name, op,
audit_cause, result, 0); return result;
}
}
entry->pcr = pcr;
result = ima_add_template_entry(entry, violation, op, inode, filename); return result;
}
/* * ima_add_violation - add violation to measurement list. * * Violations are flagged in the measurement list with zero hash values. * By extending the PCR with 0xFF's instead of with zeroes, the PCR * value is invalidated.
*/ void ima_add_violation(struct file *file, constunsignedchar *filename, struct ima_iint_cache *iint, constchar *op, constchar *cause)
{ struct ima_template_entry *entry; struct inode *inode = file_inode(file); struct ima_event_data event_data = { .iint = iint,
.file = file,
.filename = filename,
.violation = cause }; int violation = 1; int result;
/* can overflow, only indicator */
atomic_long_inc(&ima_htable.violations);
result = ima_alloc_init_template(&event_data, &entry, NULL); if (result < 0) {
result = -ENOMEM; goto err_out;
}
result = ima_store_template(entry, violation, inode,
filename, CONFIG_IMA_MEASURE_PCR_IDX); if (result < 0)
ima_free_template_entry(entry);
err_out:
integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
op, cause, result, 0);
}
/** * ima_get_action - appraise & measure decision based on policy. * @idmap: idmap of the mount the inode was found from * @inode: pointer to the inode associated with the object being validated * @cred: pointer to credentials structure to validate * @prop: properties of the task being validated * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXEC, * MAY_APPEND) * @func: caller identifier * @pcr: pointer filled in if matched measure policy sets pcr= * @template_desc: pointer filled in if matched measure policy sets template= * @func_data: func specific data, may be NULL * @allowed_algos: allowlist of hash algorithms for the IMA xattr * * The policy is defined in terms of keypairs: * subj=, obj=, type=, func=, mask=, fsmagic= * subj,obj, and type: are LSM specific. * func: FILE_CHECK | BPRM_CHECK | CREDS_CHECK | MMAP_CHECK | MODULE_CHECK * | KEXEC_CMDLINE | KEY_CHECK | CRITICAL_DATA | SETXATTR_CHECK * | MMAP_CHECK_REQPROT * mask: contains the permission mask * fsmagic: hex value * * Returns IMA_MEASURE, IMA_APPRAISE mask. *
*/ int ima_get_action(struct mnt_idmap *idmap, struct inode *inode, conststruct cred *cred, struct lsm_prop *prop, int mask, enum ima_hooks func, int *pcr, struct ima_template_desc **template_desc, constchar *func_data, unsignedint *allowed_algos)
{ int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE | IMA_HASH;
/* * On failure, 'measure' policy rules will result in a file data * hash containing 0's.
*/
digest_len = fsverity_get_digest(inode, hash->digest, NULL, &alg); if (digest_len == 0) returnfalse;
/* * Unlike in the case of actually calculating the file hash, in * the fsverity case regardless of the hash algorithm, return * the verity digest to be included in the measurement list. A * mismatch between the verity algorithm and the xattr signature * algorithm, if one exists, will be detected later.
*/
hash->hdr.algo = alg;
hash->hdr.length = digest_len; returntrue;
}
/* * ima_collect_measurement - collect file measurement * * Calculate the file hash, if it doesn't already exist, * storing the measurement and i_version in the iint. * * Must be called with iint->mutex held. * * Return 0 on success, error code otherwise
*/ int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file, void *buf, loff_t size, enum hash_algo algo, struct modsig *modsig)
{ constchar *audit_cause = "failed"; struct inode *inode = file_inode(file); struct inode *real_inode = d_real_inode(file_dentry(file)); struct ima_max_digest_data hash; struct ima_digest_data *hash_hdr = container_of(&hash.hdr, struct ima_digest_data, hdr); struct name_snapshot filename; struct kstat stat; int result = 0; int length; void *tmpbuf;
u64 i_version = 0;
/* * Always collect the modsig, because IMA might have already collected * the file digest without collecting the modsig in a previous * measurement rule.
*/ if (modsig)
ima_collect_modsig(modsig, buf, size);
if (iint->flags & IMA_COLLECTED) goto out;
/* * Detecting file change is based on i_version. On filesystems * which do not support i_version, support was originally limited * to an initial measurement/appraisal/audit, but was modified to * assume the file changed.
*/
result = vfs_getattr_nosec(&file->f_path, &stat, STATX_CHANGE_COOKIE,
AT_STATX_SYNC_AS_STAT); if (!result && (stat.result_mask & STATX_CHANGE_COOKIE))
i_version = stat.change_cookie;
hash.hdr.algo = algo;
hash.hdr.length = hash_digest_size[algo];
/* Initialize hash digest to 0's in case of failure */
memset(&hash.digest, 0, sizeof(hash.digest));
if (iint->flags & IMA_VERITY_REQUIRED) { if (!ima_get_verity_digest(iint, inode, &hash)) {
audit_cause = "no-verity-digest";
result = -ENODATA;
}
} elseif (buf) {
result = ima_calc_buffer_hash(buf, size, hash_hdr);
} else {
result = ima_calc_file_hash(file, hash_hdr);
}
if (result && result != -EBADF && result != -EINVAL) goto out;
length = sizeof(hash.hdr) + hash.hdr.length;
tmpbuf = krealloc(iint->ima_hash, length, GFP_NOFS); if (!tmpbuf) {
result = -ENOMEM; goto out;
}
/* Possibly temporary failure due to type of read (eg. O_DIRECT) */ if (!result)
iint->flags |= IMA_COLLECTED;
out: if (result) { if (file->f_flags & O_DIRECT)
audit_cause = "failed(directio)";
/* * ima_store_measurement - store file measurement * * Create an "ima" template and then store the template by calling * ima_store_template. * * We only get here if the inode has not already been measured, * but the measurement could already exist: * - multiple copies of the same file on either the same or * different filesystems. * - the inode was previously flushed as well as the iint info, * containing the hashing info. * * Must be called with iint->mutex held.
*/ void ima_store_measurement(struct ima_iint_cache *iint, struct file *file, constunsignedchar *filename, struct evm_ima_xattr_data *xattr_value, int xattr_len, conststruct modsig *modsig, int pcr, struct ima_template_desc *template_desc)
{ staticconstchar op[] = "add_template_measure"; staticconstchar audit_cause[] = "ENOMEM"; int result = -ENOMEM; struct inode *inode = file_inode(file); struct ima_template_entry *entry; struct ima_event_data event_data = { .iint = iint,
.file = file,
.filename = filename,
.xattr_value = xattr_value,
.xattr_len = xattr_len,
.modsig = modsig }; int violation = 0;
/* * We still need to store the measurement in the case of MODSIG because * we only have its contents to put in the list at the time of * appraisal, but a file measurement from earlier might already exist in * the measurement list.
*/ if (iint->measured_pcrs & (0x1 << pcr) && !modsig) return;
result = ima_alloc_init_template(&event_data, &entry, template_desc); if (result < 0) {
integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
op, audit_cause, result, 0); return;
}
result = ima_store_template(entry, violation, inode, filename, pcr); if ((!result || result == -EEXIST) && !(file->f_flags & O_DIRECT)) {
iint->flags |= IMA_MEASURED;
iint->measured_pcrs |= (0x1 << pcr);
} if (result < 0)
ima_free_template_entry(entry);
}
/* * ima_d_path - return a pointer to the full pathname * * Attempt to return a pointer to the full pathname for use in the * IMA measurement list, IMA audit records, and auditing logs. * * On failure, return a pointer to a copy of the filename, not dname. * Returning a pointer to dname, could result in using the pointer * after the memory has been freed.
*/ constchar *ima_d_path(conststruct path *path, char **pathbuf, char *namebuf)
{ struct name_snapshot filename; char *pathname = NULL;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.