lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20081015033201.GA19409@hallyn.com>
Date:	Tue, 14 Oct 2008 22:32:01 -0500
From:	"Serge E. Hallyn" <serge@...lyn.com>
To:	Mimi Zohar <zohar@...ux.vnet.ibm.com>
Cc:	linux-kernel@...r.kernel.org, Mimi Zohar <zohar@...ibm.com>
Subject: Re: [PATCH 3/3] integrity: IMA as an integrity service provider

Quoting Mimi Zohar (zohar@...ux.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@...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@...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@...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@...son.ibm.com>
> + * Mimi Zohar <zohar@...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@...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
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ