aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorDmitry Kasatkin <d.kasatkin@samsung.com>2014-02-26 10:05:20 -0500
committerMimi Zohar <zohar@linux.vnet.ibm.com>2014-07-17 09:35:10 -0400
commit3bcced39ea7d1b0da0a991e221f53de480c6b60b (patch)
treea45834814cd073987f9605b616e7b8dd094d94fd /security
parent7e9001f663636116fdc2ea7978f0350849ced624 (diff)
ima: use ahash API for file hash calculation
Async hash API allows the use of HW acceleration for hash calculation. It may give significant performance gain and/or reduce power consumption, which might be very beneficial for battery powered devices. This patch introduces hash calculation using ahash API. ahash performance depends on the data size and the particular HW. Depending on the specific system, shash performance may be better. This patch defines 'ahash_minsize' module parameter, which is used to define the minimal file size to use with ahash. If this minimum file size is not set or the file is smaller than defined by the parameter, shash will be used. Changes in v3: - kernel parameter replaced with module parameter - pr_crit replaced with pr_crit_ratelimited - more comment changes - Mimi Changes in v2: - ima_ahash_size became as ima_ahash - ahash pre-allocation moved out from __init code to be able to use ahash crypto modules. Ahash allocated once on the first use. - hash calculation falls back to shash if ahash allocation/calculation fails - complex initialization separated from variable declaration - improved comments Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com> Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
Diffstat (limited to 'security')
-rw-r--r--security/integrity/ima/ima_crypto.c187
1 files changed, 183 insertions, 4 deletions
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
index ccd0ac8fa9a0..b9e5120559d4 100644
--- a/security/integrity/ima/ima_crypto.c
+++ b/security/integrity/ima/ima_crypto.c
@@ -16,6 +16,8 @@
16#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 16#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
17 17
18#include <linux/kernel.h> 18#include <linux/kernel.h>
19#include <linux/moduleparam.h>
20#include <linux/ratelimit.h>
19#include <linux/file.h> 21#include <linux/file.h>
20#include <linux/crypto.h> 22#include <linux/crypto.h>
21#include <linux/scatterlist.h> 23#include <linux/scatterlist.h>
@@ -25,7 +27,18 @@
25#include <crypto/hash_info.h> 27#include <crypto/hash_info.h>
26#include "ima.h" 28#include "ima.h"
27 29
30struct ahash_completion {
31 struct completion completion;
32 int err;
33};
34
35/* minimum file size for ahash use */
36static unsigned long ima_ahash_minsize;
37module_param_named(ahash_minsize, ima_ahash_minsize, ulong, 0644);
38MODULE_PARM_DESC(ahash_minsize, "Minimum file size for ahash use");
39
28static struct crypto_shash *ima_shash_tfm; 40static struct crypto_shash *ima_shash_tfm;
41static struct crypto_ahash *ima_ahash_tfm;
29 42
30/** 43/**
31 * ima_kernel_read - read file content 44 * ima_kernel_read - read file content
@@ -93,9 +106,146 @@ static void ima_free_tfm(struct crypto_shash *tfm)
93 crypto_free_shash(tfm); 106 crypto_free_shash(tfm);
94} 107}
95 108
96/* 109static struct crypto_ahash *ima_alloc_atfm(enum hash_algo algo)
97 * Calculate the MD5/SHA1 file digest 110{
98 */ 111 struct crypto_ahash *tfm = ima_ahash_tfm;
112 int rc;
113
114 if ((algo != ima_hash_algo && algo < HASH_ALGO__LAST) || !tfm) {
115 tfm = crypto_alloc_ahash(hash_algo_name[algo], 0, 0);
116 if (!IS_ERR(tfm)) {
117 if (algo == ima_hash_algo)
118 ima_ahash_tfm = tfm;
119 } else {
120 rc = PTR_ERR(tfm);
121 pr_err("Can not allocate %s (reason: %d)\n",
122 hash_algo_name[algo], rc);
123 }
124 }
125 return tfm;
126}
127
128static void ima_free_atfm(struct crypto_ahash *tfm)
129{
130 if (tfm != ima_ahash_tfm)
131 crypto_free_ahash(tfm);
132}
133
134static void ahash_complete(struct crypto_async_request *req, int err)
135{
136 struct ahash_completion *res = req->data;
137
138 if (err == -EINPROGRESS)
139 return;
140 res->err = err;
141 complete(&res->completion);
142}
143
144static int ahash_wait(int err, struct ahash_completion *res)
145{
146 switch (err) {
147 case 0:
148 break;
149 case -EINPROGRESS:
150 case -EBUSY:
151 wait_for_completion(&res->completion);
152 reinit_completion(&res->completion);
153 err = res->err;
154 /* fall through */
155 default:
156 pr_crit_ratelimited("ahash calculation failed: err: %d\n", err);
157 }
158
159 return err;
160}
161
162static int ima_calc_file_hash_atfm(struct file *file,
163 struct ima_digest_data *hash,
164 struct crypto_ahash *tfm)
165{
166 loff_t i_size, offset;
167 char *rbuf;
168 int rc, read = 0, rbuf_len;
169 struct ahash_request *req;
170 struct scatterlist sg[1];
171 struct ahash_completion res;
172
173 hash->length = crypto_ahash_digestsize(tfm);
174
175 req = ahash_request_alloc(tfm, GFP_KERNEL);
176 if (!req)
177 return -ENOMEM;
178
179 init_completion(&res.completion);
180 ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
181 CRYPTO_TFM_REQ_MAY_SLEEP,
182 ahash_complete, &res);
183
184 rc = ahash_wait(crypto_ahash_init(req), &res);
185 if (rc)
186 goto out1;
187
188 i_size = i_size_read(file_inode(file));
189
190 if (i_size == 0)
191 goto out2;
192
193 rbuf = kzalloc(PAGE_SIZE, GFP_KERNEL);
194 if (!rbuf) {
195 rc = -ENOMEM;
196 goto out1;
197 }
198
199 if (!(file->f_mode & FMODE_READ)) {
200 file->f_mode |= FMODE_READ;
201 read = 1;
202 }
203
204 for (offset = 0; offset < i_size; offset += rbuf_len) {
205 rbuf_len = ima_kernel_read(file, offset, rbuf, PAGE_SIZE);
206 if (rbuf_len < 0) {
207 rc = rbuf_len;
208 break;
209 }
210 if (rbuf_len == 0)
211 break;
212
213 sg_init_one(&sg[0], rbuf, rbuf_len);
214 ahash_request_set_crypt(req, sg, NULL, rbuf_len);
215
216 rc = ahash_wait(crypto_ahash_update(req), &res);
217 if (rc)
218 break;
219 }
220 if (read)
221 file->f_mode &= ~FMODE_READ;
222 kfree(rbuf);
223out2:
224 if (!rc) {
225 ahash_request_set_crypt(req, NULL, hash->digest, 0);
226 rc = ahash_wait(crypto_ahash_final(req), &res);
227 }
228out1:
229 ahash_request_free(req);
230 return rc;
231}
232
233static int ima_calc_file_ahash(struct file *file, struct ima_digest_data *hash)
234{
235 struct crypto_ahash *tfm;
236 int rc;
237
238 tfm = ima_alloc_atfm(hash->algo);
239 if (IS_ERR(tfm))
240 return PTR_ERR(tfm);
241
242 rc = ima_calc_file_hash_atfm(file, hash, tfm);
243
244 ima_free_atfm(tfm);
245
246 return rc;
247}
248
99static int ima_calc_file_hash_tfm(struct file *file, 249static int ima_calc_file_hash_tfm(struct file *file,
100 struct ima_digest_data *hash, 250 struct ima_digest_data *hash,
101 struct crypto_shash *tfm) 251 struct crypto_shash *tfm)
@@ -156,7 +306,7 @@ out:
156 return rc; 306 return rc;
157} 307}
158 308
159int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash) 309static int ima_calc_file_shash(struct file *file, struct ima_digest_data *hash)
160{ 310{
161 struct crypto_shash *tfm; 311 struct crypto_shash *tfm;
162 int rc; 312 int rc;
@@ -173,6 +323,35 @@ int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash)
173} 323}
174 324
175/* 325/*
326 * ima_calc_file_hash - calculate file hash
327 *
328 * Asynchronous hash (ahash) allows using HW acceleration for calculating
329 * a hash. ahash performance varies for different data sizes on different
330 * crypto accelerators. shash performance might be better for smaller files.
331 * The 'ima.ahash_minsize' module parameter allows specifying the best
332 * minimum file size for using ahash on the system.
333 *
334 * If the ima.ahash_minsize parameter is not specified, this function uses
335 * shash for the hash calculation. If ahash fails, it falls back to using
336 * shash.
337 */
338int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash)
339{
340 loff_t i_size;
341 int rc;
342
343 i_size = i_size_read(file_inode(file));
344
345 if (ima_ahash_minsize && i_size >= ima_ahash_minsize) {
346 rc = ima_calc_file_ahash(file, hash);
347 if (!rc)
348 return 0;
349 }
350
351 return ima_calc_file_shash(file, hash);
352}
353
354/*
176 * Calculate the hash of template data 355 * Calculate the hash of template data
177 */ 356 */
178static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data, 357static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data,