diff options
Diffstat (limited to 'security')
| -rw-r--r-- | security/integrity/ima/ima_crypto.c | 187 |
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 | ||
| 30 | struct ahash_completion { | ||
| 31 | struct completion completion; | ||
| 32 | int err; | ||
| 33 | }; | ||
| 34 | |||
| 35 | /* minimum file size for ahash use */ | ||
| 36 | static unsigned long ima_ahash_minsize; | ||
| 37 | module_param_named(ahash_minsize, ima_ahash_minsize, ulong, 0644); | ||
| 38 | MODULE_PARM_DESC(ahash_minsize, "Minimum file size for ahash use"); | ||
| 39 | |||
| 28 | static struct crypto_shash *ima_shash_tfm; | 40 | static struct crypto_shash *ima_shash_tfm; |
| 41 | static 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 | /* | 109 | static 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 | |||
| 128 | static void ima_free_atfm(struct crypto_ahash *tfm) | ||
| 129 | { | ||
| 130 | if (tfm != ima_ahash_tfm) | ||
| 131 | crypto_free_ahash(tfm); | ||
| 132 | } | ||
| 133 | |||
| 134 | static 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 | |||
| 144 | static 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 | |||
| 162 | static 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); | ||
| 223 | out2: | ||
| 224 | if (!rc) { | ||
| 225 | ahash_request_set_crypt(req, NULL, hash->digest, 0); | ||
| 226 | rc = ahash_wait(crypto_ahash_final(req), &res); | ||
| 227 | } | ||
| 228 | out1: | ||
| 229 | ahash_request_free(req); | ||
| 230 | return rc; | ||
| 231 | } | ||
| 232 | |||
| 233 | static 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 | |||
| 99 | static int ima_calc_file_hash_tfm(struct file *file, | 249 | static 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 | ||
| 159 | int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash) | 309 | static 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 | */ | ||
| 338 | int 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 | */ |
| 178 | static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data, | 357 | static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data, |
