lkml.org 
[lkml]   [2008]   [Oct]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    Date
    From
    SubjectRe: [PATCH 3/3] integrity: IMA as an integrity service provider
    Quoting Mimi Zohar (zohar@linux.vnet.ibm.com):
    > This is a re-release of Integrity Measurement Architecture(IMA) as an
    > independent Linunx Integrity Module(LIM) service provider.
    >
    > This version addresses the merge issues resulting from the removal of
    > the nameidata parameter to inode_permission().
    > - The parameter changes to integrity_inode_permission() are reflected
    > here in this patch.
    >
    > As a LIM integrity provider, IMA implements the new LIM must_measure(),
    > collect_measurement(), store_measurement(), and display_template() API
    > calls. The store_measurement() call supports two types of data, IMA
    > (i.e. file data) and generic template data.
    >
    > IMA provides hardware (TPM) based measurement and attestation for both
    > files and other types of template measurements. As the Trusted Computing
    > (TPM) model requires, IMA measures all files before they are accessed
    > in any way (on the bprm_check_integrity, file_mmap and inode_permission
    > hooks), and commits the measurements to the TPM. In addition, IMA
    > maintains a list of these hash values, which can be used to validate
    > the aggregate PCR value. The TPM can sign these measurements, and thus
    > the system can prove to itself and to a third party these measurements
    > in a way that cannot be circumvented by malicious or compromised software.
    >
    > When store_measurement() is called for the IMA type of data, the file
    > measurement and the file name hint are used to form an IMA template.
    > IMA then calculates the IMA template measurement(hash) and submits it
    > to the TPM chip for inclusion in one of the chip's Platform Configuration
    > Registers (PCR).
    >
    > When store_measurement() is called for generic template data, IMA
    > calculates the measurement(hash) of the template data, and submits
    > the template measurement to the TPM chip for inclusion in one of the
    > chip's Platform Configuration Registers(PCR).
    >
    > In order to view the contents of template data through securityfs, the
    > template_display() function must be defined in the registered
    > template_operations. In the case of the IMA template, the list of
    > file names and files hashes submitted can be viewed through securityfs.
    >
    > As mentioned above, IMA maintains a list of hash values of executables
    > and other sensitive system files loaded into the run-time of the system.
    > Our work has shown that requests for integrity appraisal and measurement
    > need to be based on knowledge of the filesystem, requiring the system
    > to either be labeled with integrity data or depend on the existent LSM
    > security labels. The previous set of integrity patches modified the LSM
    > modules to be integrity context aware, meaning that the LSM modules made
    > integrity data/metadata appraisal and measurement API calls based on
    > an understanding of the LSM security labels. Both of the LSM maintainers
    > felt that the changes were too intrusive and that integrity enforcement
    > should be made by the integrity provider, not the LSM module.
    >
    > To address these concerns, Stephen Smalley suggested using the
    > security_audit_rule_match(), renamed to security_filter_rule_match(), to
    > define LSM specific integrity measurement policy rules, in lieu of
    > modifying the LSM modules. In the current set of patches, the integrity
    > API calls can be made either by IMA, based on an LSM specific integrity
    > policy, or by an integrity context aware LSM.
    >
    > Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
    > ---
    > Documentation/ABI/testing/ima_policy | 60 +++++
    > Documentation/kernel-parameters.txt | 5 +
    > include/linux/ima.h | 46 ++++
    > security/integrity/Kconfig | 5 +-
    > security/integrity/Makefile | 2 +
    > security/integrity/ima/Kconfig | 48 ++++
    > security/integrity/ima/Makefile | 9 +
    > security/integrity/ima/ima.h | 170 ++++++++++++
    > security/integrity/ima/ima_api.c | 348 +++++++++++++++++++++++++
    > security/integrity/ima/ima_crypto.c | 153 +++++++++++
    > security/integrity/ima/ima_fs.c | 473 ++++++++++++++++++++++++++++++++++
    > security/integrity/ima/ima_init.c | 105 ++++++++
    > security/integrity/ima/ima_main.c | 354 +++++++++++++++++++++++++
    > security/integrity/ima/ima_policy.c | 334 ++++++++++++++++++++++++
    > security/integrity/ima/ima_queue.c | 124 +++++++++
    > 15 files changed, 2233 insertions(+), 3 deletions(-)
    > create mode 100644 Documentation/ABI/testing/ima_policy
    > create mode 100644 include/linux/ima.h
    > create mode 100644 security/integrity/ima/Kconfig
    > create mode 100644 security/integrity/ima/Makefile
    > create mode 100644 security/integrity/ima/ima.h
    > create mode 100644 security/integrity/ima/ima_api.c
    > create mode 100644 security/integrity/ima/ima_crypto.c
    > create mode 100644 security/integrity/ima/ima_fs.c
    > create mode 100644 security/integrity/ima/ima_init.c
    > create mode 100644 security/integrity/ima/ima_main.c
    > create mode 100644 security/integrity/ima/ima_policy.c
    > create mode 100644 security/integrity/ima/ima_queue.c
    >
    > diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
    > new file mode 100644
    > index 0000000..c9ab220
    > --- /dev/null
    > +++ b/Documentation/ABI/testing/ima_policy
    > @@ -0,0 +1,60 @@
    > +What: security/ima/policy
    > +Date: May 2008
    > +Contact: Mimi Zohar <zohar@us.ibm.com>
    > +Description:
    > + The Trusted Computing Group(TCG) runtime Integrity
    > + Measurement Architecture(IMA) maintains a list of hash
    > + values of executables and other sensitive system files
    > + loaded into the run-time of this system. At runtime,
    > + the policy can be constrained based on LSM specific data.
    > + Policies are loaded into security/ima/policy by opening
    > + the file, writing the rules one at a time and then
    > + closing the file. The new policy takes effect after
    > + the security/ima/policy is closed.
    > +
    > + rule format: action [condition ...]
    > +
    > + action: measure | dont_measure
    > + condition:= base | lsm
    > + base: [[func=] [mask=] [fsmagic=] [uid=]]
    > + lsm: [[subj_user=] [subj_role=] [subj_type=]
    > + [obj_user=] [obj_role=] [obj_type=]]
    > +
    > + base: func:= [BPRM_CHECK][FILE_MMAP][INODE_PERMISSION]
    > + mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC]
    > + fsmagic:= hex value
    > + uid:= decimal value
    > + lsm: are LSM specific
    > +
    > + default policy:
    > + # PROC_SUPER_MAGIC
    > + dont_measure fsmagic=0x9fa0
    > + # SYSFS_MAGIC
    > + dont_measure fsmagic=0x62656572
    > + # DEBUGFS_MAGIC
    > + dont_measure fsmagic=0x64626720
    > + # TMPFS_MAGIC
    > + dont_measure fsmagic=0x01021994
    > + # SECURITYFS_MAGIC
    > + dont_measure fsmagic=0x73636673
    > + # SELINUX_MAGIC
    > + dont_measure fsmagic=0xF97CFF8C
    > +
    > + measure func=BPRM_CHECK
    > + measure func=FILE_MMAP mask=MAY_EXEC
    > + measure func=INODE_PERM mask=MAY_READ uid=0
    > +
    > + The default policy measures all executables in bprm_check,
    > + all files mmapped executable in file_mmap, and all files
    > + open for read by root in inode_permission.
    > +
    > + Examples of LSM specific definitions:
    > +
    > + SELinux:
    > + dont_measure obj_type=var_log_t
    > + dont_measure obj_type=auditd_log_t
    > + measure subj_user=system_u func=INODE_PERM mask=MAY_READ
    > + measure subj_role=system_r func=INODE_PERM mask=MAY_READ
    > +
    > + Smack:
    > + measure subj_user=_ func=INODE_PERM mask=MAY_READ
    > diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
    > index 772d19a..982556d 100644
    > --- a/Documentation/kernel-parameters.txt
    > +++ b/Documentation/kernel-parameters.txt
    > @@ -44,6 +44,7 @@ parameter is applicable:
    > FB The frame buffer device is enabled.
    > HW Appropriate hardware is enabled.
    > IA-64 IA-64 architecture is enabled.
    > + IMA Integrity measurement architecture is enabled.
    > INTEGRITY Integrity support is enabled.
    > IOSCHED More than one I/O scheduler is enabled.
    > IP_PNP IP DHCP, BOOTP, or RARP is enabled.
    > @@ -858,6 +859,10 @@ and is between 256 and 4096 characters. It is defined in the file
    > ihash_entries= [KNL]
    > Set number of hash buckets for inode cache.
    >
    > + ima_hash= [IMA] runtime ability to define hash crypto algorithm.
    > + Format: { "MD5" | "SHA1" }
    > + Default is "SHA1".
    > +
    > in2000= [HW,SCSI]
    > See header of drivers/scsi/in2000.c.
    >
    > diff --git a/include/linux/ima.h b/include/linux/ima.h
    > new file mode 100644
    > index 0000000..c777b71
    > --- /dev/null
    > +++ b/include/linux/ima.h
    > @@ -0,0 +1,46 @@
    > +/*
    > + * ima.h
    > + *
    > + * 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.
    > + */
    > +
    > +#ifndef _LINUX_IMA_H
    > +#define _LINUX_IMA_H
    > +
    > +/* IMA LIM Data */
    > +enum ima_type { IMA_DATA, IMA_METADATA, IMA_TEMPLATE };
    > +
    > +struct ima_args_data {
    > + const char *filename;
    > + struct file *file;
    > + struct path *path;
    > + struct dentry *dentry;
    > + struct inode *inode;
    > + enum lim_hooks function;
    > + u32 osid;
    > + int mask;
    > +};
    > +
    > +struct ima_store_data {
    > + char *name;
    > + int len;
    > + char *data;
    > + int violation;
    > +};
    > +
    > +struct ima_data {
    > + enum ima_type type;
    > + union {
    > + struct ima_args_data args;
    > + struct ima_store_data template;
    > + } data;
    > +};
    > +
    > +void ima_fixup_argsdata(struct ima_args_data *data, struct file *file,
    > + struct path *path, int mask, int function);
    > +#endif
    > diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig
    > index 3c29050..28b44e3 100644
    > --- a/security/integrity/Kconfig
    > +++ b/security/integrity/Kconfig
    > @@ -2,8 +2,6 @@
    > # Integrity configuration
    > #
    >
    > -menu "Integrity options"
    > -
    > config INTEGRITY
    > bool "Enable different integrity models"
    > help
    > @@ -21,4 +19,5 @@ config INTEGRITY_AUDIT
    > allows integrity auditing to be disabled at boot. If this
    > option is selected, integrity auditing can be disabled with
    > 'integrity_audit=0' on the kernel command line.
    > -endmenu
    > +
    > +source security/integrity/ima/Kconfig
    > diff --git a/security/integrity/Makefile b/security/integrity/Makefile
    > index c9fb803..8eb7a4a 100644
    > --- a/security/integrity/Makefile
    > +++ b/security/integrity/Makefile
    > @@ -4,3 +4,5 @@
    >
    > # Object file lists
    > obj-$(CONFIG_INTEGRITY) += integrity.o integrity_audit.o
    > +
    > +obj-$(CONFIG_IMA) += ima/
    > diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
    > new file mode 100644
    > index 0000000..ca25b0b
    > --- /dev/null
    > +++ b/security/integrity/ima/Kconfig
    > @@ -0,0 +1,48 @@
    > +#
    > +# IBM Integrity Measurement Architecture
    > +#
    > +
    > +config IMA
    > + bool "Integrity Measurement Architecture(IMA)"
    > + depends on INTEGRITY
    > + depends on ACPI
    > + select CRYPTO
    > + select CRYPTO_HMAC
    > + select CRYPTO_MD5
    > + select CRYPTO_SHA1
    > + select TCG_TPM
    > + select TCG_TIS
    > + help
    > + The Trusted Computing Group(TCG) runtime Integrity
    > + Measurement Architecture(IMA) maintains a list of hash
    > + values of executables and other sensitive system files
    > + loaded into the run-time of this system. If your system
    > + has a TPM chip, then IMA also maintains an aggregate
    > + integrity value over this list inside the TPM hardware.
    > + These measurements and the aggregate (signed inside the
    > + TPM) can be retrieved and presented to remote parties to
    > + establish system properties. If unsure, say N.
    > +
    > +config IMA_MEASURE_PCR_IDX
    > + int "PCR for Aggregate (8 <= Index <= 14)"
    > + depends on IMA
    > + range 8 14
    > + default 10
    > + help
    > + IMA_MEASURE_PCR_IDX determines the TPM PCR register index
    > + that IMA uses to maintain the integrity aggregate of the
    > + measurement list. If unsure, use the default 10.
    > +
    > +config IMA_BASE_HOOKS
    > + bool "IMA base hooks"
    > + depends on IMA
    > + default n
    > + help
    > + Enable this option to allow the LSM module to enforce integrity.
    > +
    > +config IMA_LSM_RULES
    > + bool "Enable LSM measurement policy rules"
    > + depends on IMA && (SECURITY_SELINUX || SECURITY_SMACK)
    > + default y
    > + help
    > + Disabling this option will not enforce LSM based policy rules.
    > diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile
    > new file mode 100644
    > index 0000000..f3aced4
    > --- /dev/null
    > +++ b/security/integrity/ima/Makefile
    > @@ -0,0 +1,9 @@
    > +#
    > +# Makefile for building Trusted Computing Group's(TCG) runtime Integrity
    > +# Measurement Architecture(IMA).
    > +#
    > +
    > +obj-$(CONFIG_IMA) += ima.o
    > +
    > +ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
    > + ima_policy.o
    > diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
    > new file mode 100644
    > index 0000000..aed5f9f
    > --- /dev/null
    > +++ b/security/integrity/ima/ima.h
    > @@ -0,0 +1,170 @@
    > +/*
    > + * Copyright (C) 2005,2006,2007,2008 IBM Corporation
    > + *
    > + * Authors:
    > + * Reiner Sailer <sailer@watson.ibm.com>
    > + * 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.h
    > + * internal ima definitions
    > + */
    > +
    > +#ifndef __LINUX_IMA_H
    > +#define __LINUX_IMA_H
    > +
    > +#include <linux/types.h>
    > +#include <linux/crypto.h>
    > +#include <linux/security.h>
    > +#include <linux/integrity.h>
    > +#include <linux/hash.h>
    > +#include <linux/tpm.h>
    > +
    > +#define ima_printk(level, format, arg...) \
    > + printk(level "ima (%s): " format, __func__, ## arg)
    > +
    > +#define ima_error(format, arg...) \
    > + ima_printk(KERN_ERR, format, ## arg)
    > +
    > +#define ima_info(format, arg...) \
    > + ima_printk(KERN_INFO, format, ## arg)
    > +
    > +/* digest size for IMA, fits SHA1 or MD5 */
    > +#define IMA_DIGEST_SIZE 20
    > +#define IMA_EVENT_NAME_LEN_MAX 255
    > +
    > +#define IMA_HASH_BITS 9
    > +#define IMA_MEASURE_HTABLE_SIZE (1 << IMA_HASH_BITS)
    > +
    > +/* set during initialization */
    > +extern int ima_used_chip;
    > +extern char *ima_hash;
    > +
    > +struct ima_measure_entry {
    > + u8 digest[IMA_DIGEST_SIZE]; /* sha1 or md5 measurement hash */
    > + char template_name[IMA_EVENT_NAME_LEN_MAX + 1]; /* name + \0 */
    > + int template_len;
    > + char *template;
    > +};
    > +
    > +struct ima_queue_entry {
    > + struct hlist_node hnext; /* place in hash collision list */
    > + struct list_head later; /* place in ima_measurements list */
    > + struct ima_measure_entry *entry;
    > +};
    > +extern struct list_head ima_measurements; /* list of all measurements */
    > +
    > +/* declarations */
    > +extern int ima_template_mode;
    > +extern const struct template_operations ima_template_ops;
    > +
    > +/* Internal IMA function definitions */
    > +int ima_init(void);
    > +void ima_cleanup(void);
    > +int ima_fs_init(void);
    > +void ima_fs_cleanup(void);
    > +void ima_create_htable(void);
    > +int ima_add_measure_entry(struct ima_measure_entry *entry, int violation);
    > +struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest);
    > +int ima_calc_hash(struct file *file, struct path *path, char *digest);
    > +int ima_calc_template_hash(int template_len, char *template, char *digest);
    > +void ima_add_violation(struct inode *inode, const unsigned char *fname,
    > + char *op, char *cause);
    > +
    > +enum ima_action {DONT_MEASURE, MEASURE};
    > +int ima_match_policy(struct inode *inode, enum lim_hooks func, int mask);
    > +int ima_add_rule(int, char *subj_user, char *subj_role, char *subj_type,
    > + char *obj_user, char *obj_role, char *obj_type,
    > + char *func, char *mask, char *fsmagic, char *uid);
    > +void ima_init_policy(void);
    > +void ima_update_policy(void);
    > +
    > +
    > +/* LIM API function definitions */
    > +int ima_must_measure(void *d);
    > +int ima_collect_measurement(void *d);
    > +int ima_appraise_measurement(void *d);
    > +void ima_store_measurement(void *d);
    > +void ima_template_show(struct seq_file *m, void *e,
    > + enum integrity_show_type show);
    > +
    > +
    > +/*
    > + * used to protect h_table and sha_table
    > + */
    > +extern spinlock_t ima_queue_lock;
    > +
    > +struct ima_h_table {
    > + atomic_long_t len; /* number of stored measurements in the list */
    > + atomic_long_t violations;
    > + unsigned int max_htable_size;
    > + struct hlist_head queue[IMA_MEASURE_HTABLE_SIZE];
    > + atomic_t queue_len[IMA_MEASURE_HTABLE_SIZE];
    > +};
    > +extern struct ima_h_table ima_htable;
    > +
    > +static inline unsigned long IMA_HASH_KEY(u8 *digest)
    > +{
    > + return(hash_ptr(digest, IMA_HASH_BITS));
    > +}
    > +
    > +/* TPM "Glue" definitions */
    > +
    > +#define IMA_TPM ((((u32)TPM_ANY_TYPE)<<16) | (u32)TPM_ANY_NUM)
    > +static inline void ima_extend(const u8 *hash)
    > +{
    > + if (!ima_used_chip)
    > + return;
    > +
    > + if (tpm_pcr_extend(IMA_TPM, CONFIG_IMA_MEASURE_PCR_IDX, hash) != 0)
    > + ima_error("Error Communicating to TPM chip\n");
    > +}
    > +
    > +static inline void ima_pcrread(int idx, u8 *pcr, int pcr_size)
    > +{
    > + if (!ima_used_chip)
    > + return;
    > +
    > + if (tpm_pcr_read(IMA_TPM, idx, pcr) != 0)
    > + ima_error("Error Communicating to TPM chip\n");
    > +}
    > +
    > +struct ima_inode_measure_entry {
    > + u8 digest[IMA_DIGEST_SIZE]; /* sha1/md5 measurement hash */
    > + char file_name[IMA_EVENT_NAME_LEN_MAX + 1]; /* name + \0 */
    > +};
    > +
    > +/* inode integrity data */
    > +struct ima_iint_cache {
    > + u64 version;
    > + int measured;
    > + u8 hmac[IMA_DIGEST_SIZE];
    > + u8 digest[IMA_DIGEST_SIZE];
    > + struct mutex mutex;
    > +};
    > +
    > +/* LSM based policy rules require audit */
    > +#ifdef CONFIG_IMA_LSM_RULES
    > +
    > +#define security_filter_rule_init security_audit_rule_init
    > +#define security_filter_rule_match security_audit_rule_match
    > +
    > +#else
    > +
    > +static inline int security_filter_rule_init(u32 field, u32 op, char *rulestr,
    > + void **lsmrule)
    > +{
    > + return -EINVAL;
    > +}
    > +
    > +static inline int security_filter_rule_match(u32 secid, u32 field, u32 op,
    > + void *lsmrule, struct audit_context *actx)
    > +{
    > + return -EINVAL;
    > +}
    > +#endif
    > +#endif
    > diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
    > new file mode 100644
    > index 0000000..c6d93bc
    > --- /dev/null
    > +++ b/security/integrity/ima/ima_api.c
    > @@ -0,0 +1,348 @@
    > +/*
    > + * 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 the LIM API
    > + */
    > +#include <linux/module.h>
    > +#include <linux/integrity.h>
    > +#include <linux/magic.h>
    > +#include <linux/writeback.h>
    > +#include <linux/string.h>
    > +#include <linux/list.h>
    > +#include <linux/audit.h>
    > +#include <linux/ima.h>
    > +
    > +#include "ima.h"
    > +
    > +const struct template_operations ima_template_ops = {
    > + .must_measure = ima_must_measure,
    > + .collect_measurement = ima_collect_measurement,
    > + .store_measurement = ima_store_measurement,
    > + .display_template = ima_template_show
    > +};
    > +
    > +/**
    > + * mode_setup - for compatability with non-template IMA versions
    > + * @str: is pointer to a string
    > + */
    > +int ima_template_mode = 1;
    > +static int __init mode_setup(char *str)
    > +{
    > + if (strncmp(str, "ima", 3) == 0)
    > + ima_template_mode = 0;
    > + if (strncmp(str, "template", 7) == 0)
    > + ima_template_mode = 1;
    > + ima_info("template_mode %s \n",
    > + ima_template_mode ? "template" : "ima");
    > + return 1;
    > +}
    > +
    > +__setup("ima_mode=", mode_setup);
    > +
    > +/**
    > + * ima_digest_cpy - copy the hash in the IMA template structure to a digest
    > + * @template_name: string containing the name of the template (i.e. "ima")
    > + * @template: pointer to template structure
    > + * @digest: pointer to the digest
    > + *
    > + * Returns 0 on success, error code otherwise
    > + */
    > +static int ima_digest_cpy(char *template_name, void *template, u8 *digest)
    > +{
    > + int rc, result = 0;
    > + struct ima_inode_measure_entry *inode_template =
    > + (struct ima_inode_measure_entry *)template;
    > +
    > + rc = strcmp(template_name, "ima");
    > + if (rc == 0)
    > + memcpy(digest, inode_template->digest,
    > + sizeof inode_template->digest);
    > + else
    > + result = -ENODATA;
    > + return result;
    > +}
    > +
    > +/**
    > + * ima_store_template_measure - collect and protect template measurements
    > + * @template_name: string containing the name of the template (i.e. "ima")
    > + * @template_len: length of the template data
    > + * @template: actual template data
    > + * @violation: invalidate pcr measurement indication
    > + * @audit_cause: string containing the audit failure cause
    > + *
    > + * 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
    > + */
    > +static int ima_store_template_measure(char *template_name, int template_len,
    > + char *template, int violation,
    > + char **audit_cause)
    > +{
    > + struct ima_measure_entry *entry;
    > + u8 digest[IMA_DIGEST_SIZE];
    > + struct ima_queue_entry *qe;
    > + int count, result = 0;
    > +
    > + memset(digest, 0, IMA_DIGEST_SIZE);
    > + if (!violation) {
    > + int rc = -ENODATA;
    > +
    > + if (!ima_template_mode)
    > + rc = ima_digest_cpy(template_name, template, digest);
    > + if (rc < 0)
    > + result = ima_calc_template_hash(template_len, template,
    > + digest);
    > +
    > + /* hash exists already? */
    > + qe = ima_lookup_digest_entry(digest);
    > + if (qe) {
    > + *audit_cause = "hash_exists";
    > + result = -EEXIST;
    > + goto out;
    > + }
    > + }
    > +
    > + /* create new entry and add to measurement list */
    > + entry = kzalloc(sizeof(*entry), GFP_KERNEL);
    > + if (!entry) {
    > + *audit_cause = "ENOMEM";
    > + result = -ENOMEM;
    > + goto out;
    > + }
    > +
    > + entry->template = kzalloc(template_len, GFP_KERNEL);
    > + if (!entry->template) {
    > + *audit_cause = "ENOMEM";
    > + result = -ENOMEM;
    > + goto out;
    > + }
    > + if (!template_name) {
    > + *audit_cause = "null_template_name";
    > + count = 1;
    > + } else {
    > + count = strlen(template_name);
    > + if (count > IMA_EVENT_NAME_LEN_MAX)
    > + count = IMA_EVENT_NAME_LEN_MAX;
    > + memcpy(entry->template_name, template_name, count);
    > + }
    > + entry->template_name[count] = '\0';
    > + entry->template_len = template_len;
    > + memcpy(entry->template, template, template_len);
    > + memcpy(entry->digest, digest, IMA_DIGEST_SIZE);
    > +
    > + result = ima_add_measure_entry(entry, violation);
    > + if (result < 0)
    > + kfree(entry);
    > +out:
    > + return result;
    > +}
    > +
    > +/**
    > + * ima_store_inode_measure - create and store an inode template measurement
    > + * @name: ascii file name associated with the measurement hash
    > + * @hash_len: length of hash value in bytes (16 for MD5, 20 for SHA1)
    > + * @hash: actual hash value pre-calculated
    > + *
    > + * Returns 0 on success, error code otherwise
    > + */
    > +static int ima_store_inode_measure(struct inode *inode,
    > + const unsigned char *name,
    > + int hash_len, char *hash, int violation)
    > +{
    > + struct ima_inode_measure_entry measure_entry, *entry = &measure_entry;
    > + int result;
    > + int namelen;
    > + char *op = "add_measure";
    > + char *cause = " ";
    > +
    > + memset(entry, 0, sizeof *entry);
    > + if (!violation)
    > + memcpy(entry->digest, hash, hash_len > IMA_DIGEST_SIZE ?
    > + IMA_DIGEST_SIZE : hash_len);
    > + if (name) {
    > + namelen = strlen(name);
    > + memcpy(entry->file_name, name, namelen > IMA_EVENT_NAME_LEN_MAX
    > + ? IMA_EVENT_NAME_LEN_MAX : namelen);
    > + entry->file_name[namelen] = '\0';
    > + }
    > + result = ima_store_template_measure("ima", sizeof *entry, (char *)entry,
    > + violation, &cause);
    > + if (result < 0)
    > + integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
    > + name, op, cause, result);
    > + return result;
    > +}
    > +
    > +/**
    > + * ima_add_violation - add violation to measurement list.
    > + * @inode: inode associated with the violation
    > + * @fname: name associated with the inode
    > + * @op: string pointer to audit operation (i.e. "invalid_pcr", "add_measure")
    > + * @cause: string pointer to reason for violation (i.e. "ToMToU")
    > + *
    > + * 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 inode *inode, const unsigned char *fname,
    > + char *op, char *cause)
    > +{
    > + int result;
    > +
    > + /* can overflow, only indicator */
    > + atomic_long_inc(&ima_htable.violations);
    > +
    > + result = ima_store_inode_measure(inode, fname, 0, NULL, 1);
    > + integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, fname, op,
    > + cause, result);
    > +}
    > +
    > +/**
    > + * skip_measurement - measure only regular files, skip everything else.
    > + * @inode: inode being measured
    > + * @mask: contains the permission mask
    > + *
    > + * Quick sanity check to make sure that only regular files opened
    > + * for read-only or execute are measured.
    > + *
    > + * Return 1 to skip measure, 0 to measure
    > + */
    > +static int skip_measurement(struct inode *inode, int mask)
    > +{
    > + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
    > + return 1; /* can't measure */
    > +
    > + if (special_file(inode->i_mode) || S_ISLNK(inode->i_mode))
    > + return 1; /* don't measure */
    > +
    > + if (S_ISREG(inode->i_mode))
    > + return 0; /* measure */
    > + return 1; /* don't measure */
    > +}
    > +
    > +/**
    > + * ima_must_measure - measure decision based on policy.
    > + * @template_data: pointer to struct ima_data containing ima_args_data
    > + *
    > + * The policy is defined in terms of keypairs:
    > + * subj=, obj=, type=, func=, mask=, fsmagic=
    > + * subj,obj, and type: are LSM specific.
    > + * func: INODE_PERMISSION | BPRM_CHECK | FILE_MMAP
    > + * mask: contains the permission mask
    > + * fsmagic: hex value
    > + *
    > + * Return 0 to measure. For matching a DONT_MEASURE policy, no policy,
    > + * or other error, return an error code.
    > +*/
    > +int ima_must_measure(void *template_data)
    > +{
    > + struct ima_data *idata = (struct ima_data *)template_data;
    > + struct ima_args_data *data = &idata->data.args;
    > + int rc;
    > +
    > + if ((data->mask & MAY_WRITE) || (data->mask & MAY_APPEND))
    > + return -EPERM;
    > +
    > + if (skip_measurement(data->inode, data->mask))
    > + return -EPERM;
    > +
    > + rc = ima_match_policy(data->inode, data->function, data->mask);
    > + if (rc)
    > + return 0;
    > + return -EACCES;
    > +}
    > +
    > +/**
    > + * ima_collect_measurement - collect file measurements and store in the inode
    > + * @template_data: pointer to struct ima_data containing ima_args_data
    > + *
    > + * Return 0 on success, error code otherwise
    > + */
    > +int ima_collect_measurement(void *template_data)
    > +{
    > + struct ima_iint_cache *iint;
    > + struct ima_data *idata = (struct ima_data *)template_data;
    > + struct ima_args_data *data = &idata->data.args;
    > + struct dentry *dentry = data->dentry;
    > + struct inode *inode = data->inode;
    > + int result = 0;
    > +
    > + if (idata->type != IMA_DATA)
    > + return -EPERM;
    > +
    > + if (!inode || !dentry)
    > + return -EINVAL;
    > +
    > + iint = inode->i_integrity;
    > + mutex_lock(&iint->mutex);

    ima_collect_measurement will be called under rcu_read_lock(),
    won't it? So you can't take a mutex, bc that could sleep.

    > + if (!iint->measured) {
    > + memset(iint->digest, 0, IMA_DIGEST_SIZE);
    > + result = ima_calc_hash(data->file, data->path, iint->digest);
    > + } else
    > + result = -EEXIST;
    > + mutex_unlock(&iint->mutex);
    > + return result;
    > +}
    > +
    > +/**
    > + * ima_store_measurement - store file and template measurements
    > + * @template_data: pointer to struct ima_data containing ima_args_data,
    > + * used to create an IMA template, or a template.
    > + *
    > + * For file measurements, first create an IMA template and then store it.
    > + * For all other types of template measurements, just store it.
    > + */
    > +void ima_store_measurement(void *template_data)
    > +{
    > + struct ima_data *idata = (struct ima_data *)template_data;
    > + int result;
    > + char *op = "add_template_measure";
    > + char *cause = "";
    > +
    > + if (idata->type == IMA_DATA) {
    > + struct ima_args_data *data = &idata->data.args;
    > + struct ima_iint_cache *iint;
    > +
    > + iint = data->inode->i_integrity;
    > + mutex_lock(&iint->mutex);

    Same here.

    -serge


    \
     
     \ /
      Last update: 2008-10-15 05:35    [W:0.092 / U:148.008 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site