aboutsummaryrefslogtreecommitdiffstats
path: root/security/integrity
diff options
context:
space:
mode:
authorDmitry Kasatkin <d.kasatkin@samsung.com>2013-04-25 03:43:56 -0400
committerMimi Zohar <zohar@linux.vnet.ibm.com>2013-10-25 17:16:58 -0400
commitc7c8bb237fdbff932b5e431aebee5ce862ea07d1 (patch)
tree4cdbc7c250dd4418b47ab45dd1108848b50f8cff /security/integrity
parent3fe78ca2fb1d61ea598e63fcbf38aec76b36b3a8 (diff)
ima: provide support for arbitrary hash algorithms
In preparation of supporting more hash algorithms with larger hash sizes needed for signature verification, this patch replaces the 20 byte sized digest, with a more flexible structure. The new structure includes the hash algorithm, digest size, and digest. Changelog: - recalculate filedata hash for the measurement list, if the signature hash digest size is greater than 20 bytes. - use generic HASH_ALGO_ - make ima_calc_file_hash static - scripts lindent and checkpatch fixes Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com> Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
Diffstat (limited to 'security/integrity')
-rw-r--r--security/integrity/ima/Kconfig1
-rw-r--r--security/integrity/ima/ima.h7
-rw-r--r--security/integrity/ima/ima_api.c32
-rw-r--r--security/integrity/ima/ima_appraise.c20
-rw-r--r--security/integrity/ima/ima_crypto.c49
-rw-r--r--security/integrity/ima/ima_main.c6
-rw-r--r--security/integrity/integrity.h15
7 files changed, 98 insertions, 32 deletions
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
index 39196abaff0d..e6628e783df1 100644
--- a/security/integrity/ima/Kconfig
+++ b/security/integrity/ima/Kconfig
@@ -9,6 +9,7 @@ config IMA
9 select CRYPTO_HMAC 9 select CRYPTO_HMAC
10 select CRYPTO_MD5 10 select CRYPTO_MD5
11 select CRYPTO_SHA1 11 select CRYPTO_SHA1
12 select CRYPTO_HASH_INFO
12 select TCG_TPM if HAS_IOMEM && !UML 13 select TCG_TPM if HAS_IOMEM && !UML
13 select TCG_TIS if TCG_TPM && X86 14 select TCG_TIS if TCG_TPM && X86
14 select TCG_IBMVTPM if TCG_TPM && PPC64 15 select TCG_IBMVTPM if TCG_TPM && PPC64
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index b3dd616560f7..eb86032f4f1e 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -39,7 +39,7 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
39/* set during initialization */ 39/* set during initialization */
40extern int ima_initialized; 40extern int ima_initialized;
41extern int ima_used_chip; 41extern int ima_used_chip;
42extern char *ima_hash; 42extern int ima_hash_algo;
43extern int ima_appraise; 43extern int ima_appraise;
44 44
45/* IMA inode template definition */ 45/* IMA inode template definition */
@@ -70,8 +70,9 @@ void ima_fs_cleanup(void);
70int ima_inode_alloc(struct inode *inode); 70int ima_inode_alloc(struct inode *inode);
71int ima_add_template_entry(struct ima_template_entry *entry, int violation, 71int ima_add_template_entry(struct ima_template_entry *entry, int violation,
72 const char *op, struct inode *inode); 72 const char *op, struct inode *inode);
73int ima_calc_file_hash(struct file *file, char *digest); 73int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash);
74int ima_calc_buffer_hash(const void *data, int len, char *digest); 74int ima_calc_buffer_hash(const void *data, int len,
75 struct ima_digest_data *hash);
75int ima_calc_boot_aggregate(char *digest); 76int ima_calc_boot_aggregate(char *digest);
76void ima_add_violation(struct inode *inode, const unsigned char *filename, 77void ima_add_violation(struct inode *inode, const unsigned char *filename,
77 const char *op, const char *cause); 78 const char *op, const char *cause);
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index 1c03e8f1e0e1..e531fe22e582 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -44,6 +44,7 @@ int ima_store_template(struct ima_template_entry *entry,
44 const char *op = "add_template_measure"; 44 const char *op = "add_template_measure";
45 const char *audit_cause = "hashing_error"; 45 const char *audit_cause = "hashing_error";
46 int result; 46 int result;
47 struct ima_digest_data hash;
47 48
48 memset(entry->digest, 0, sizeof(entry->digest)); 49 memset(entry->digest, 0, sizeof(entry->digest));
49 entry->template_name = IMA_TEMPLATE_NAME; 50 entry->template_name = IMA_TEMPLATE_NAME;
@@ -51,14 +52,14 @@ int ima_store_template(struct ima_template_entry *entry,
51 52
52 if (!violation) { 53 if (!violation) {
53 result = ima_calc_buffer_hash(&entry->template, 54 result = ima_calc_buffer_hash(&entry->template,
54 entry->template_len, 55 entry->template_len, &hash);
55 entry->digest);
56 if (result < 0) { 56 if (result < 0) {
57 integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, 57 integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
58 entry->template_name, op, 58 entry->template_name, op,
59 audit_cause, result, 0); 59 audit_cause, result, 0);
60 return result; 60 return result;
61 } 61 }
62 memcpy(entry->digest, hash.digest, hash.length);
62 } 63 }
63 result = ima_add_template_entry(entry, violation, op, inode); 64 result = ima_add_template_entry(entry, violation, op, inode);
64 return result; 65 return result;
@@ -147,8 +148,9 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
147 if (!(iint->flags & IMA_COLLECTED)) { 148 if (!(iint->flags & IMA_COLLECTED)) {
148 u64 i_version = file_inode(file)->i_version; 149 u64 i_version = file_inode(file)->i_version;
149 150
150 iint->ima_xattr.type = IMA_XATTR_DIGEST; 151 /* use default hash algorithm */
151 result = ima_calc_file_hash(file, iint->ima_xattr.digest); 152 iint->ima_hash.algo = ima_hash_algo;
153 result = ima_calc_file_hash(file, &iint->ima_hash);
152 if (!result) { 154 if (!result) {
153 iint->version = i_version; 155 iint->version = i_version;
154 iint->flags |= IMA_COLLECTED; 156 iint->flags |= IMA_COLLECTED;
@@ -196,7 +198,21 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
196 return; 198 return;
197 } 199 }
198 memset(&entry->template, 0, sizeof(entry->template)); 200 memset(&entry->template, 0, sizeof(entry->template));
199 memcpy(entry->template.digest, iint->ima_xattr.digest, IMA_DIGEST_SIZE); 201 if (iint->ima_hash.algo != ima_hash_algo) {
202 struct ima_digest_data hash;
203
204 hash.algo = ima_hash_algo;
205 result = ima_calc_file_hash(file, &hash);
206 if (result)
207 integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
208 filename, "collect_data", "failed",
209 result, 0);
210 else
211 memcpy(entry->template.digest, hash.digest,
212 hash.length);
213 } else
214 memcpy(entry->template.digest, iint->ima_hash.digest,
215 iint->ima_hash.length);
200 strcpy(entry->template.file_name, 216 strcpy(entry->template.file_name,
201 (strlen(filename) > IMA_EVENT_NAME_LEN_MAX) ? 217 (strlen(filename) > IMA_EVENT_NAME_LEN_MAX) ?
202 file->f_dentry->d_name.name : filename); 218 file->f_dentry->d_name.name : filename);
@@ -212,14 +228,14 @@ void ima_audit_measurement(struct integrity_iint_cache *iint,
212 const unsigned char *filename) 228 const unsigned char *filename)
213{ 229{
214 struct audit_buffer *ab; 230 struct audit_buffer *ab;
215 char hash[(IMA_DIGEST_SIZE * 2) + 1]; 231 char hash[(iint->ima_hash.length * 2) + 1];
216 int i; 232 int i;
217 233
218 if (iint->flags & IMA_AUDITED) 234 if (iint->flags & IMA_AUDITED)
219 return; 235 return;
220 236
221 for (i = 0; i < IMA_DIGEST_SIZE; i++) 237 for (i = 0; i < iint->ima_hash.length; i++)
222 hex_byte_pack(hash + (i * 2), iint->ima_xattr.digest[i]); 238 hex_byte_pack(hash + (i * 2), iint->ima_hash.digest[i]);
223 hash[i * 2] = '\0'; 239 hash[i * 2] = '\0';
224 240
225 ab = audit_log_start(current->audit_context, GFP_KERNEL, 241 ab = audit_log_start(current->audit_context, GFP_KERNEL,
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index e3230d6a8d96..3833b0fa7108 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -43,12 +43,12 @@ int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func)
43} 43}
44 44
45static int ima_fix_xattr(struct dentry *dentry, 45static int ima_fix_xattr(struct dentry *dentry,
46 struct integrity_iint_cache *iint) 46 struct integrity_iint_cache *iint)
47{ 47{
48 iint->ima_xattr.type = IMA_XATTR_DIGEST; 48 iint->ima_hash.type = IMA_XATTR_DIGEST;
49 return __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA, 49 return __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA,
50 (u8 *)&iint->ima_xattr, 50 &iint->ima_hash.type,
51 sizeof(iint->ima_xattr), 0); 51 1 + iint->ima_hash.length, 0);
52} 52}
53 53
54/* Return specific func appraised cached result */ 54/* Return specific func appraised cached result */
@@ -159,8 +159,12 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
159 status = INTEGRITY_FAIL; 159 status = INTEGRITY_FAIL;
160 break; 160 break;
161 } 161 }
162 rc = memcmp(xattr_value->digest, iint->ima_xattr.digest, 162 if (rc - 1 == iint->ima_hash.length)
163 IMA_DIGEST_SIZE); 163 rc = memcmp(xattr_value->digest,
164 iint->ima_hash.digest,
165 iint->ima_hash.length);
166 else
167 rc = -EINVAL;
164 if (rc) { 168 if (rc) {
165 cause = "invalid-hash"; 169 cause = "invalid-hash";
166 status = INTEGRITY_FAIL; 170 status = INTEGRITY_FAIL;
@@ -172,8 +176,8 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
172 iint->flags |= IMA_DIGSIG; 176 iint->flags |= IMA_DIGSIG;
173 rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA, 177 rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA,
174 xattr_value->digest, rc - 1, 178 xattr_value->digest, rc - 1,
175 iint->ima_xattr.digest, 179 iint->ima_hash.digest,
176 IMA_DIGEST_SIZE); 180 iint->ima_hash.length);
177 if (rc == -EOPNOTSUPP) { 181 if (rc == -EOPNOTSUPP) {
178 status = INTEGRITY_UNKNOWN; 182 status = INTEGRITY_UNKNOWN;
179 } else if (rc) { 183 } else if (rc) {
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
index a02e0791cf15..2fd178651467 100644
--- a/security/integrity/ima/ima_crypto.c
+++ b/security/integrity/ima/ima_crypto.c
@@ -20,6 +20,7 @@
20#include <linux/err.h> 20#include <linux/err.h>
21#include <linux/slab.h> 21#include <linux/slab.h>
22#include <crypto/hash.h> 22#include <crypto/hash.h>
23#include <crypto/hash_info.h>
23#include "ima.h" 24#include "ima.h"
24 25
25static struct crypto_shash *ima_shash_tfm; 26static struct crypto_shash *ima_shash_tfm;
@@ -28,10 +29,11 @@ int ima_init_crypto(void)
28{ 29{
29 long rc; 30 long rc;
30 31
31 ima_shash_tfm = crypto_alloc_shash(ima_hash, 0, 0); 32 ima_shash_tfm = crypto_alloc_shash(hash_algo_name[ima_hash_algo], 0, 0);
32 if (IS_ERR(ima_shash_tfm)) { 33 if (IS_ERR(ima_shash_tfm)) {
33 rc = PTR_ERR(ima_shash_tfm); 34 rc = PTR_ERR(ima_shash_tfm);
34 pr_err("Can not allocate %s (reason: %ld)\n", ima_hash, rc); 35 pr_err("Can not allocate %s (reason: %ld)\n",
36 hash_algo_name[ima_hash_algo], rc);
35 return rc; 37 return rc;
36 } 38 }
37 return 0; 39 return 0;
@@ -40,17 +42,19 @@ int ima_init_crypto(void)
40/* 42/*
41 * Calculate the MD5/SHA1 file digest 43 * Calculate the MD5/SHA1 file digest
42 */ 44 */
43int ima_calc_file_hash(struct file *file, char *digest) 45static int ima_calc_file_hash_tfm(struct file *file,
46 struct ima_digest_data *hash,
47 struct crypto_shash *tfm)
44{ 48{
45 loff_t i_size, offset = 0; 49 loff_t i_size, offset = 0;
46 char *rbuf; 50 char *rbuf;
47 int rc, read = 0; 51 int rc, read = 0;
48 struct { 52 struct {
49 struct shash_desc shash; 53 struct shash_desc shash;
50 char ctx[crypto_shash_descsize(ima_shash_tfm)]; 54 char ctx[crypto_shash_descsize(tfm)];
51 } desc; 55 } desc;
52 56
53 desc.shash.tfm = ima_shash_tfm; 57 desc.shash.tfm = tfm;
54 desc.shash.flags = 0; 58 desc.shash.flags = 0;
55 59
56 rc = crypto_shash_init(&desc.shash); 60 rc = crypto_shash_init(&desc.shash);
@@ -85,17 +89,42 @@ int ima_calc_file_hash(struct file *file, char *digest)
85 } 89 }
86 kfree(rbuf); 90 kfree(rbuf);
87 if (!rc) 91 if (!rc)
88 rc = crypto_shash_final(&desc.shash, digest); 92 rc = crypto_shash_final(&desc.shash, hash->digest);
89 if (read) 93 if (read)
90 file->f_mode &= ~FMODE_READ; 94 file->f_mode &= ~FMODE_READ;
91out: 95out:
92 return rc; 96 return rc;
93} 97}
94 98
99int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash)
100{
101 struct crypto_shash *tfm = ima_shash_tfm;
102 int rc;
103
104 if (hash->algo != ima_hash_algo && hash->algo < HASH_ALGO__LAST) {
105 tfm = crypto_alloc_shash(hash_algo_name[hash->algo], 0, 0);
106 if (IS_ERR(tfm)) {
107 rc = PTR_ERR(tfm);
108 pr_err("Can not allocate %s (reason: %d)\n",
109 hash_algo_name[hash->algo], rc);
110 return rc;
111 }
112 }
113
114 hash->length = crypto_shash_digestsize(tfm);
115
116 rc = ima_calc_file_hash_tfm(file, hash, tfm);
117
118 if (tfm != ima_shash_tfm)
119 crypto_free_shash(tfm);
120
121 return rc;
122}
123
95/* 124/*
96 * Calculate the hash of a given buffer 125 * Calculate the hash of a given buffer
97 */ 126 */
98int ima_calc_buffer_hash(const void *data, int len, char *digest) 127int ima_calc_buffer_hash(const void *buf, int len, struct ima_digest_data *hash)
99{ 128{
100 struct { 129 struct {
101 struct shash_desc shash; 130 struct shash_desc shash;
@@ -105,7 +134,11 @@ int ima_calc_buffer_hash(const void *data, int len, char *digest)
105 desc.shash.tfm = ima_shash_tfm; 134 desc.shash.tfm = ima_shash_tfm;
106 desc.shash.flags = 0; 135 desc.shash.flags = 0;
107 136
108 return crypto_shash_digest(&desc.shash, data, len, digest); 137 /* this function uses default algo */
138 hash->algo = ima_hash_algo;
139 hash->length = crypto_shash_digestsize(ima_shash_tfm);
140
141 return crypto_shash_digest(&desc.shash, buf, len, hash->digest);
109} 142}
110 143
111static void __init ima_pcrread(int idx, u8 *pcr) 144static void __init ima_pcrread(int idx, u8 *pcr)
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 0f359df6344c..7708c2120d9c 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -24,6 +24,7 @@
24#include <linux/slab.h> 24#include <linux/slab.h>
25#include <linux/xattr.h> 25#include <linux/xattr.h>
26#include <linux/ima.h> 26#include <linux/ima.h>
27#include <crypto/hash_info.h>
27 28
28#include "ima.h" 29#include "ima.h"
29 30
@@ -35,11 +36,12 @@ int ima_appraise = IMA_APPRAISE_ENFORCE;
35int ima_appraise; 36int ima_appraise;
36#endif 37#endif
37 38
38char *ima_hash = "sha1"; 39int ima_hash_algo = HASH_ALGO_SHA1;
40
39static int __init hash_setup(char *str) 41static int __init hash_setup(char *str)
40{ 42{
41 if (strncmp(str, "md5", 3) == 0) 43 if (strncmp(str, "md5", 3) == 0)
42 ima_hash = "md5"; 44 ima_hash_algo = HASH_ALGO_MD5;
43 return 1; 45 return 1;
44} 46}
45__setup("ima_hash=", hash_setup); 47__setup("ima_hash=", hash_setup);
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index f86731649f54..0b02ea868e30 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -59,20 +59,29 @@ enum evm_ima_xattr_type {
59struct evm_ima_xattr_data { 59struct evm_ima_xattr_data {
60 u8 type; 60 u8 type;
61 u8 digest[SHA1_DIGEST_SIZE]; 61 u8 digest[SHA1_DIGEST_SIZE];
62} __attribute__((packed)); 62} __packed;
63
64#define IMA_MAX_DIGEST_SIZE 64
65
66struct ima_digest_data {
67 u8 algo;
68 u8 length;
69 u8 type;
70 u8 digest[IMA_MAX_DIGEST_SIZE];
71} __packed;
63 72
64/* integrity data associated with an inode */ 73/* integrity data associated with an inode */
65struct integrity_iint_cache { 74struct integrity_iint_cache {
66 struct rb_node rb_node; /* rooted in integrity_iint_tree */ 75 struct rb_node rb_node; /* rooted in integrity_iint_tree */
67 struct inode *inode; /* back pointer to inode in question */ 76 struct inode *inode; /* back pointer to inode in question */
68 u64 version; /* track inode changes */ 77 u64 version; /* track inode changes */
69 unsigned long flags; 78 unsigned long flags;
70 struct evm_ima_xattr_data ima_xattr;
71 enum integrity_status ima_file_status:4; 79 enum integrity_status ima_file_status:4;
72 enum integrity_status ima_mmap_status:4; 80 enum integrity_status ima_mmap_status:4;
73 enum integrity_status ima_bprm_status:4; 81 enum integrity_status ima_bprm_status:4;
74 enum integrity_status ima_module_status:4; 82 enum integrity_status ima_module_status:4;
75 enum integrity_status evm_status:4; 83 enum integrity_status evm_status:4;
84 struct ima_digest_data ima_hash;
76}; 85};
77 86
78/* rbtree tree calls to lookup, insert, delete 87/* rbtree tree calls to lookup, insert, delete