diff options
author | Dmitry Kasatkin <d.kasatkin@samsung.com> | 2013-04-25 03:43:56 -0400 |
---|---|---|
committer | Mimi Zohar <zohar@linux.vnet.ibm.com> | 2013-10-25 17:16:58 -0400 |
commit | c7c8bb237fdbff932b5e431aebee5ce862ea07d1 (patch) | |
tree | 4cdbc7c250dd4418b47ab45dd1108848b50f8cff /security/integrity | |
parent | 3fe78ca2fb1d61ea598e63fcbf38aec76b36b3a8 (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/Kconfig | 1 | ||||
-rw-r--r-- | security/integrity/ima/ima.h | 7 | ||||
-rw-r--r-- | security/integrity/ima/ima_api.c | 32 | ||||
-rw-r--r-- | security/integrity/ima/ima_appraise.c | 20 | ||||
-rw-r--r-- | security/integrity/ima/ima_crypto.c | 49 | ||||
-rw-r--r-- | security/integrity/ima/ima_main.c | 6 | ||||
-rw-r--r-- | security/integrity/integrity.h | 15 |
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 */ |
40 | extern int ima_initialized; | 40 | extern int ima_initialized; |
41 | extern int ima_used_chip; | 41 | extern int ima_used_chip; |
42 | extern char *ima_hash; | 42 | extern int ima_hash_algo; |
43 | extern int ima_appraise; | 43 | extern int ima_appraise; |
44 | 44 | ||
45 | /* IMA inode template definition */ | 45 | /* IMA inode template definition */ |
@@ -70,8 +70,9 @@ void ima_fs_cleanup(void); | |||
70 | int ima_inode_alloc(struct inode *inode); | 70 | int ima_inode_alloc(struct inode *inode); |
71 | int ima_add_template_entry(struct ima_template_entry *entry, int violation, | 71 | int 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); |
73 | int ima_calc_file_hash(struct file *file, char *digest); | 73 | int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash); |
74 | int ima_calc_buffer_hash(const void *data, int len, char *digest); | 74 | int ima_calc_buffer_hash(const void *data, int len, |
75 | struct ima_digest_data *hash); | ||
75 | int ima_calc_boot_aggregate(char *digest); | 76 | int ima_calc_boot_aggregate(char *digest); |
76 | void ima_add_violation(struct inode *inode, const unsigned char *filename, | 77 | void 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 | ||
45 | static int ima_fix_xattr(struct dentry *dentry, | 45 | static 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 | ||
25 | static struct crypto_shash *ima_shash_tfm; | 26 | static 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 | */ |
43 | int ima_calc_file_hash(struct file *file, char *digest) | 45 | static 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; |
91 | out: | 95 | out: |
92 | return rc; | 96 | return rc; |
93 | } | 97 | } |
94 | 98 | ||
99 | int 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 | */ |
98 | int ima_calc_buffer_hash(const void *data, int len, char *digest) | 127 | int 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 | ||
111 | static void __init ima_pcrread(int idx, u8 *pcr) | 144 | static 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; | |||
35 | int ima_appraise; | 36 | int ima_appraise; |
36 | #endif | 37 | #endif |
37 | 38 | ||
38 | char *ima_hash = "sha1"; | 39 | int ima_hash_algo = HASH_ALGO_SHA1; |
40 | |||
39 | static int __init hash_setup(char *str) | 41 | static 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 { | |||
59 | struct evm_ima_xattr_data { | 59 | struct 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 | |||
66 | struct 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 */ |
65 | struct integrity_iint_cache { | 74 | struct 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 |