integrity: EVM as an integrity service provider
Subsystems (2)
RFC PATCH 3/6 integrity: EVM as an integrity service provider
This is a re-release of EVM as an integrity service provider. The initial EVM release was as an LSM module. It has been substantially rewritten to provide support for the new integrity service framework API, which permits applications, such as LSM modules, to verify the integrity of the metadata and data of a file.
EVM maintains an HMAC-sha1 associated with each file across an extensible set of extended attributes, ensuring that the extended attributes are protected against integrity attacks. The HMAC-sha1 is stored as an extended attribute security.evm.hmac. EVM depends on the Kernel Key Retention System to provide it with the kernel master key for the HMAC operation. The kernel master key is loaded onto the root's keyring by 'loadkernkey', which either uses the TPM sealed secrect key, if available, or a password requested from the console.
The integrity measurement of the file data, stored in the extended attribute security.evm.hash (md5) or security.evm.sha1, is protected by the HMAC. EVM maintains the integrity measurement of the file data, unless the file is defined as either FIXED or NOHASH.
The integrity service framework API defines three calls:integrity_verify_metadata(), integrity_verify_data(), and integrity_measure(). For integrity_verify_metadata(), EVM determines whether or not the HMAC calculated for the set of extended attributes matches the HMAC stored as an extended attribute; for integrity_verify_data(), EVM determines whether or not the integrity measurement of the file data matches the value stored as an extended attribute; and for integrity_measure(), if IMA is configured and enabled, EVM passes the integrity measurement to it.
security/evm/evm_config.c new file +129 -0
@@ -0,0 +1,129 @@ +/* +* EVM - Extended Verification Module +* +* Copyright (C) 2005,2006,2007 IBM Corporation +* Author: Mimi Zohar <[email protected]> +* Kylene Hall <[email protected]> +* +* 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. +*/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include "evm.h" + +/* +* Configuration data +*/ +struct evm_xattr_config *evm_config_xattrdata; +int evm_config_xattrnum =0 ;/* number of extended attributes */ + +/* +* inode->i_integrity information +*/ +void display_config (const char *name) +{ +struct evm_xattr_config *config_p; + +for_each_xattr (config_p, evm_config_xattrdata, evm_config_xattrnum) +printk (KERN_INFO "%s: %s\n" , name, config_p->xattr_name); +} + +/* +* Initialize the Extended Verification module +*/ +int evm_init_config (struct evm_xattr_config *evm_data,int evm_datasize) +{ +ssize_t error =0 ; + +if (evm_datasize >0 ) { + evm_config_xattrdata = evm_data; + evm_config_xattrnum = evm_datasize; +display_config (__FUNCTION__); + + }else { +printk (KERN_INFO "%s: config file definition missing\n" , + __FUNCTION__); +return -EINVAL ; + } +return error; +} + +static char *get_tag (char *buf_start,char *buf_end,char delimiter, +int *taglen) +{ +char *bufp = buf_start; +char *tag; + +/* Get start of tag */ +while (bufp < buf_end) { +if (*bufp ==' ' )/* skip blanks */ +while ((*bufp ==' ' ) && (bufp++ < buf_end)) ; +else if (*bufp =='#' ) {/* skip comment */ +while ((*bufp !='\n' ) && (bufp++ < buf_end)) ; + bufp++; + }else if (*bufp =='\n' )/* skip newline */ + bufp++; +else if (*bufp =='\t' )/* skip tabs */ + bufp++; +else +break ; + } +if (bufp < buf_end) + tag = bufp; +else +return NULL ; + +/* Get tag */ + *taglen =0 ; +while ((bufp < buf_end) && (*taglen ==0 )) { +if ((*bufp == delimiter) || (*bufp =='\n' )) + *taglen = bufp - tag; + bufp++; + } +if (*taglen ==0 )/* Didn't find end delimiter */ + *taglen = bufp - tag; +return tag; +} + +struct evm_xattr_config *evm_parse_config (char *data,unsigned long datalen, +int *xattrnum) +{ +char *datap, *dataend, *tag; +int num_xattr =0 ; +struct evm_xattr_config *config_xattrdata =NULL , *config_p; +int taglen; + +/* Get number of extended attribute definitions */ + datap = data; + dataend = data + datalen; + +while ((tag =get_tag (datap, dataend,' ' , &taglen)) !=NULL ) { + datap = tag + taglen; + num_xattr++; + } + *xattrnum = num_xattr; + + datap = data; + config_xattrdata = +kmalloc (num_xattr *sizeof (struct evm_xattr_config ),GFP_KERNEL ); +if (!config_xattrdata) +return NULL ; + +/* Get the list of hmac protected extended attributes */ + config_p = config_xattrdata; +while ((tag =get_tag (datap, dataend,' ' , &taglen)) !=NULL ) { + datap = tag ==NULL ? dataend : tag + taglen; +memset (config_p->xattr_name,0 ,sizeof config_p->xattr_name); +memcpy (config_p->xattr_name, tag, taglen); + config_p++; + } +return config_xattrdata; +} + +inline void evm_cleanup_config (void ) +{ +kfree (evm_config_xattrdata); +}
security/evm/evm_crypto.c new file +350 -0
350 lines not on this page · raw message
security/evm/evm.h new file +85 -0
85 lines not on this page · raw message
security/evm/evm_secfs.c new file +201 -0
201 lines not on this page · raw message
security/evm/Kconfig new file +17 -0
@@ -0,0 +1,17 @@ +config INTEGRITY_EVM + boolean "EVM support" + depends on INTEGRITY && KEYS + select CRYPTO_HMAC + select CRYPTO_MD5 + select CRYPTO_SHA1 + default 0 + help + The Extended Verification Module is an integrity provider. + An extensible set of extended attributes, as defined in + /etc/evm.conf, are HMAC protected against modification + using the TPM's KERNEL ROOT KEY, if configured, or with a + pass-phrase. Possible extended attributes include authenticity, + integrity, and revision level. + + If you are unsure how to answer this question, answer N. +
security/evm/Makefile new file +5 -0
@@ -0,0 +1,5 @@ + +obj-$(CONFIG_INTEGRITY_EVM) += evm.o + +evm-y := evm_main.o evm_config.o evm_crypto.o evm_secfs.o +
security/Makefile +1 -0
@@ -13,6 +13,7 @@ endif # Object file lists obj-$(CONFIG_SECURITY) += security.o dummy.o inode.o obj-$(CONFIG_INTEGRITY) += integrity.o integrity_dummy.o +obj-$(CONFIG_INTEGRITY_EVM) += evm/ # Must precede capability.o in order to stack properly. obj-$(CONFIG_SECURITY_SLIM) += slim/ obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
security/evm/evm_main.c new file +926 -0
926 lines not on this page · raw message
security/Kconfig +1 -0
@@ -46,6 +46,7 @@ config INTEGRITY configured into your kernel. If you are unsure how to answer this question, answer N. +source security/evm/Kconfig config SECURITY bool "Enable different security models"
fs/namei.c +22 -0
@@ -2616,6 +2616,27 @@ int generic_readlink(struct dentry *dentreturn PTR_ERR (cookie); } +int kernel_readlink (struct dentry *dentry,char **buffer,int *buflen) +{ +struct nameidata nd; +void *cookie; + + nd.depth =0 ; + cookie = dentry->d_inode->i_op->follow_link (dentry, &nd); +if (!IS_ERR (cookie)) { +char *link; + + link =nd_get_link (&nd); +if (IS_ERR (link)) +return PTR_ERR (link); + *buffer =kstrdup (link,GFP_KERNEL ); + *buflen = (*buffer ==NULL ) ?0 :strlen (*buffer); +if (dentry->d_inode->i_op->put_link) + dentry->d_inode->i_op->put_link (dentry, &nd, cookie); + } +return PTR_ERR (cookie); +} +int vfs_follow_link (struct nameidata *nd,const char *link) {return __vfs_follow_link (nd, link);
@@ -2758,6 +2779,7 @@ EXPORT_SYMBOL(vfs_mkdir);EXPORT_SYMBOL (vfs_mknod);EXPORT_SYMBOL (generic_permission);EXPORT_SYMBOL (vfs_readlink); +EXPORT_SYMBOL (kernel_readlink);EXPORT_SYMBOL (vfs_rename);EXPORT_SYMBOL (vfs_rmdir);EXPORT_SYMBOL (vfs_symlink);
Quoted 4 lines · Mimi Zohar
security/evm/evm_crypto.c new file +3
-0+int update_file_hash (struct dentry *dentry,struct file *f, +struct hash_desc *desc) +{
...
security/evm/evm_crypto.c line 76
Quoted 10 lines
security/evm/evm_crypto.c new file +10
-0+while (offset < i_size) { + rbuf_len =kernel_read (file, offset, rbuf,PAGE_SIZE ); +if (rbuf_len <=0 ) +break ; + offset += rbuf_len; + sg[0 ].page =virt_to_page (rbuf); + sg[0 ].offset = ((long )rbuf & ~PAGE_MASK ); + sg[0 ].length = rbuf_len; + +crypto_hash_update (desc, sg, rbuf_len);
You should check for errors here and on all calls to crypto_hash_* that return errors.
security/evm/evm_crypto.c line 130
Quoted 12 lines
security/evm/evm_crypto.c new file +12
-0+int evm_calc_hash (struct dentry *dentry,struct file *file,char *digest, +int xattr_type) +{ +struct crypto_hash *tfm; +struct hash_desc desc; +int error =0 ; + +if (!dentry && !file) +return -ENOENT ; + + tfm =crypto_alloc_hash (evm_hash,0 ,CRYPTO_ALG_ASYNC ); +if (!tfm) {
That should be !IS_ERR(tfm).
security/evm/evm_main.c line 889
Quoted 8 lines
security/evm/evm_main.c new file +8
-0+static int __init init_evm (void ) +{ +int error; + +if (strncmp (evm_hash,"sha1" ,4 ) ==0 ) { + evm_hash_type =EVM_TYPE_SHA1 ; + hash_digest_size =SHA1_DIGEST_SIZE ; + hash_str_size =SHA1_STR_SIZE ;
This looks suspect. Can you guarantee that only md5/sha1 are used? If not you should be getting these from the tfm. If yes then you shouldn't allow arbitrary strings to be used.
Cheers,
Signature · 4 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt