cregit-Linux how code gets into the kernel

Release 4.11 security/integrity/ima/ima_api.c

/*
 * Copyright (C) 2008 IBM Corporation
 *
 * Author: Mimi Zohar <zohar@us.ibm.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, version 2 of the
 * License.
 *
 * File: ima_api.c
 *      Implements must_appraise_or_measure, collect_measurement,
 *      appraise_measurement, store_measurement and store_template.
 */
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/xattr.h>
#include <linux/evm.h>

#include "ima.h"

/*
 * 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); }

Contributors

PersonTokensPropCommitsCommitProp
Roberto Sassu47100.00%1100.00%
Total47100.00%1100.00%

/* * 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 *template_desc = ima_template_desc_current(); int i, result = 0; *entry = kzalloc(sizeof(**entry) + template_desc->num_fields * sizeof(struct ima_field_data), GFP_NOFS); if (!*entry) return -ENOMEM; (*entry)->template_desc = template_desc; for (i = 0; i < template_desc->num_fields; i++) { struct ima_template_field *field = template_desc->fields[i]; u32 len; result = field->field_init(event_data, &((*entry)->template_data[i])); if (result != 0) goto out; len = (*entry)->template_data[i].len; (*entry)->template_data_len += sizeof(len); (*entry)->template_data_len += len; } return 0; out: ima_free_template_entry(*entry); *entry = NULL; return result; }

Contributors

PersonTokensPropCommitsCommitProp
Roberto Sassu18998.44%480.00%
Mimi Zohar31.56%120.00%
Total192100.00%5100.00%

/* * 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, const unsigned char *filename, int pcr) { static const char op[] = "add_template_measure"; static const char audit_cause[] = "hashing_error"; char *template_name = entry->template_desc->name; int result; struct { struct ima_digest_data hdr; char digest[TPM_DIGEST_SIZE]; } hash; if (!violation) { int num_fields = entry->template_desc->num_fields; /* this function uses default algo */ hash.hdr.algo = HASH_ALGO_SHA1; result = ima_calc_field_array_hash(&entry->template_data[0], entry->template_desc, num_fields, &hash.hdr); if (result < 0) { integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, template_name, op, audit_cause, result, 0); return result; } memcpy(entry->digest, hash.hdr.digest, hash.hdr.length); } entry->pcr = pcr; result = ima_add_template_entry(entry, violation, op, inode, filename); return result; }

Contributors

PersonTokensPropCommitsCommitProp
Mimi Zohar9851.31%327.27%
Dmitry Kasatkin4724.61%436.36%
Roberto Sassu3719.37%327.27%
Eric Richter94.71%19.09%
Total191100.00%11100.00%

/* * 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, const unsigned char *filename, struct integrity_iint_cache *iint, const char *op, const char *cause) { struct ima_template_entry *entry; struct inode *inode = file_inode(file); struct ima_event_data event_data = {iint, file, filename, NULL, 0, cause}; int violation = 1; int result; /* can overflow, only indicator */ atomic_long_inc(&ima_htable.violations); result = ima_alloc_init_template(&event_data, &entry); 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); }

Contributors

PersonTokensPropCommitsCommitProp
Mimi Zohar10467.97%220.00%
Roberto Sassu4428.76%660.00%
Libo Chen31.96%110.00%
Eric Richter21.31%110.00%
Total153100.00%10100.00%

/** * ima_get_action - appraise & measure decision based on policy. * @inode: pointer to inode to measure * @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= * * 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 | MMAP_CHECK | MODULE_CHECK * mask: contains the permission mask * fsmagic: hex value * * Returns IMA_MEASURE, IMA_APPRAISE mask. * */
int ima_get_action(struct inode *inode, int mask, enum ima_hooks func, int *pcr) { int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE; flags &= ima_policy_flag; return ima_match_policy(inode, func, mask, flags, pcr); }

Contributors

PersonTokensPropCommitsCommitProp
Mimi Zohar3879.17%342.86%
Eric Richter612.50%114.29%
Dmitry Kasatkin24.17%228.57%
Peter Moody24.17%114.29%
Total48100.00%7100.00%

/* * 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 integrity_iint_cache *iint, struct file *file, void *buf, loff_t size, enum hash_algo algo) { const char *audit_cause = "failed"; struct inode *inode = file_inode(file); const char *filename = file->f_path.dentry->d_name.name; int result = 0; struct { struct ima_digest_data hdr; char digest[IMA_MAX_DIGEST_SIZE]; } hash; if (!(iint->flags & IMA_COLLECTED)) { u64 i_version = file_inode(file)->i_version; if (file->f_flags & O_DIRECT) { audit_cause = "failed(directio)"; result = -EACCES; goto out; } hash.hdr.algo = algo; result = (!buf) ? ima_calc_file_hash(file, &hash.hdr) : ima_calc_buffer_hash(buf, size, &hash.hdr); if (!result) { int length = sizeof(hash.hdr) + hash.hdr.length; void *tmpbuf = krealloc(iint->ima_hash, length, GFP_NOFS); if (tmpbuf) { iint->ima_hash = tmpbuf; memcpy(iint->ima_hash, &hash, length); iint->version = i_version; iint->flags |= IMA_COLLECTED; } else result = -ENOMEM; } } out: if (result) integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename, "collect_data", audit_cause, result, 0); return result; }

Contributors

PersonTokensPropCommitsCommitProp
Mimi Zohar16662.41%646.15%
Dmitry Kasatkin9134.21%538.46%
Al Viro93.38%215.38%
Total266100.00%13100.00%

/* * 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 integrity_iint_cache *iint, struct file *file, const unsigned char *filename, struct evm_ima_xattr_data *xattr_value, int xattr_len, int pcr) { static const char op[] = "add_template_measure"; static const char audit_cause[] = "ENOMEM"; int result = -ENOMEM; struct inode *inode = file_inode(file); struct ima_template_entry *entry; struct ima_event_data event_data = {iint, file, filename, xattr_value, xattr_len, NULL}; int violation = 0; if (iint->measured_pcrs & (0x1 << pcr)) return; result = ima_alloc_init_template(&event_data, &entry); 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) { iint->flags |= IMA_MEASURED; iint->measured_pcrs |= (0x1 << pcr); } if (result < 0) ima_free_template_entry(entry); }

Contributors

PersonTokensPropCommitsCommitProp
Mimi Zohar10654.08%533.33%
Roberto Sassu4321.94%640.00%
Eric Richter2311.73%213.33%
Dmitry Kasatkin2110.71%16.67%
Al Viro31.53%16.67%
Total196100.00%15100.00%


void ima_audit_measurement(struct integrity_iint_cache *iint, const unsigned char *filename) { struct audit_buffer *ab; char hash[(iint->ima_hash->length * 2) + 1]; const char *algo_name = hash_algo_name[iint->ima_hash->algo]; char algo_hash[sizeof(hash) + strlen(algo_name) + 2]; int i; if (iint->flags & IMA_AUDITED) return; for (i = 0; i < iint->ima_hash->length; i++) hex_byte_pack(hash + (i * 2), iint->ima_hash->digest[i]); hash[i * 2] = '\0'; ab = audit_log_start(current->audit_context, GFP_KERNEL, AUDIT_INTEGRITY_RULE); if (!ab) return; audit_log_format(ab, "file="); audit_log_untrustedstring(ab, filename); audit_log_format(ab, " hash="); snprintf(algo_hash, sizeof(algo_hash), "%s:%s", algo_name, hash); audit_log_untrustedstring(ab, algo_hash); audit_log_task_info(ab, current); audit_log_end(ab); iint->flags |= IMA_AUDITED; }

Contributors

PersonTokensPropCommitsCommitProp
Peter Moody14771.36%125.00%
Mimi Zohar4722.82%125.00%
Dmitry Kasatkin125.83%250.00%
Total206100.00%4100.00%

/* * 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. */
const char *ima_d_path(const struct path *path, char **pathbuf, char *namebuf) { char *pathname = NULL; *pathbuf = __getname(); if (*pathbuf) { pathname = d_absolute_path(path, *pathbuf, PATH_MAX); if (IS_ERR(pathname)) { __putname(*pathbuf); *pathbuf = NULL; pathname = NULL; } } if (!pathname) { strlcpy(namebuf, path->dentry->d_name.name, NAME_MAX); pathname = namebuf; } return pathname; }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Kasatkin8176.42%466.67%
Mimi Zohar2422.64%116.67%
Al Viro10.94%116.67%
Total106100.00%6100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Mimi Zohar60942.44%1227.27%
Roberto Sassu36225.23%920.45%
Dmitry Kasatkin25517.77%1329.55%
Peter Moody14910.38%12.27%
Eric Richter402.79%36.82%
Al Viro130.91%36.82%
Tejun Heo30.21%12.27%
Libo Chen30.21%12.27%
Lans Zhang10.07%12.27%
Total1435100.00%44100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.