diff options
Diffstat (limited to 'security')
| -rw-r--r-- | security/integrity/digsig.c | 1 | ||||
| -rw-r--r-- | security/keys/big_key.c | 110 |
2 files changed, 88 insertions, 23 deletions
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index 6f9e4ce568cd..9bb0a7f2863e 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include <linux/cred.h> | 18 | #include <linux/cred.h> |
| 19 | #include <linux/key-type.h> | 19 | #include <linux/key-type.h> |
| 20 | #include <linux/digsig.h> | 20 | #include <linux/digsig.h> |
| 21 | #include <linux/vmalloc.h> | ||
| 21 | #include <crypto/public_key.h> | 22 | #include <crypto/public_key.h> |
| 22 | #include <keys/system_keyring.h> | 23 | #include <keys/system_keyring.h> |
| 23 | 24 | ||
diff --git a/security/keys/big_key.c b/security/keys/big_key.c index 929e14978c42..fa728f662a6f 100644 --- a/security/keys/big_key.c +++ b/security/keys/big_key.c | |||
| @@ -22,6 +22,13 @@ | |||
| 22 | #include <keys/big_key-type.h> | 22 | #include <keys/big_key-type.h> |
| 23 | #include <crypto/aead.h> | 23 | #include <crypto/aead.h> |
| 24 | 24 | ||
| 25 | struct big_key_buf { | ||
| 26 | unsigned int nr_pages; | ||
| 27 | void *virt; | ||
| 28 | struct scatterlist *sg; | ||
| 29 | struct page *pages[]; | ||
| 30 | }; | ||
| 31 | |||
| 25 | /* | 32 | /* |
| 26 | * Layout of key payload words. | 33 | * Layout of key payload words. |
| 27 | */ | 34 | */ |
| @@ -91,10 +98,9 @@ static DEFINE_MUTEX(big_key_aead_lock); | |||
| 91 | /* | 98 | /* |
| 92 | * Encrypt/decrypt big_key data | 99 | * Encrypt/decrypt big_key data |
| 93 | */ | 100 | */ |
| 94 | static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key) | 101 | static int big_key_crypt(enum big_key_op op, struct big_key_buf *buf, size_t datalen, u8 *key) |
| 95 | { | 102 | { |
| 96 | int ret; | 103 | int ret; |
| 97 | struct scatterlist sgio; | ||
| 98 | struct aead_request *aead_req; | 104 | struct aead_request *aead_req; |
| 99 | /* We always use a zero nonce. The reason we can get away with this is | 105 | /* We always use a zero nonce. The reason we can get away with this is |
| 100 | * because we're using a different randomly generated key for every | 106 | * because we're using a different randomly generated key for every |
| @@ -109,8 +115,7 @@ static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key) | |||
| 109 | return -ENOMEM; | 115 | return -ENOMEM; |
| 110 | 116 | ||
| 111 | memset(zero_nonce, 0, sizeof(zero_nonce)); | 117 | memset(zero_nonce, 0, sizeof(zero_nonce)); |
| 112 | sg_init_one(&sgio, data, datalen + (op == BIG_KEY_ENC ? ENC_AUTHTAG_SIZE : 0)); | 118 | aead_request_set_crypt(aead_req, buf->sg, buf->sg, datalen, zero_nonce); |
| 113 | aead_request_set_crypt(aead_req, &sgio, &sgio, datalen, zero_nonce); | ||
| 114 | aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); | 119 | aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); |
| 115 | aead_request_set_ad(aead_req, 0); | 120 | aead_request_set_ad(aead_req, 0); |
| 116 | 121 | ||
| @@ -130,21 +135,81 @@ error: | |||
| 130 | } | 135 | } |
| 131 | 136 | ||
| 132 | /* | 137 | /* |
| 138 | * Free up the buffer. | ||
| 139 | */ | ||
| 140 | static void big_key_free_buffer(struct big_key_buf *buf) | ||
| 141 | { | ||
| 142 | unsigned int i; | ||
| 143 | |||
| 144 | if (buf->virt) { | ||
| 145 | memset(buf->virt, 0, buf->nr_pages * PAGE_SIZE); | ||
| 146 | vunmap(buf->virt); | ||
| 147 | } | ||
| 148 | |||
| 149 | for (i = 0; i < buf->nr_pages; i++) | ||
| 150 | if (buf->pages[i]) | ||
| 151 | __free_page(buf->pages[i]); | ||
| 152 | |||
| 153 | kfree(buf); | ||
| 154 | } | ||
| 155 | |||
| 156 | /* | ||
| 157 | * Allocate a buffer consisting of a set of pages with a virtual mapping | ||
| 158 | * applied over them. | ||
| 159 | */ | ||
| 160 | static void *big_key_alloc_buffer(size_t len) | ||
| 161 | { | ||
| 162 | struct big_key_buf *buf; | ||
| 163 | unsigned int npg = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
| 164 | unsigned int i, l; | ||
| 165 | |||
| 166 | buf = kzalloc(sizeof(struct big_key_buf) + | ||
| 167 | sizeof(struct page) * npg + | ||
| 168 | sizeof(struct scatterlist) * npg, | ||
| 169 | GFP_KERNEL); | ||
| 170 | if (!buf) | ||
| 171 | return NULL; | ||
| 172 | |||
| 173 | buf->nr_pages = npg; | ||
| 174 | buf->sg = (void *)(buf->pages + npg); | ||
| 175 | sg_init_table(buf->sg, npg); | ||
| 176 | |||
| 177 | for (i = 0; i < buf->nr_pages; i++) { | ||
| 178 | buf->pages[i] = alloc_page(GFP_KERNEL); | ||
| 179 | if (!buf->pages[i]) | ||
| 180 | goto nomem; | ||
| 181 | |||
| 182 | l = min_t(size_t, len, PAGE_SIZE); | ||
| 183 | sg_set_page(&buf->sg[i], buf->pages[i], l, 0); | ||
| 184 | len -= l; | ||
| 185 | } | ||
| 186 | |||
| 187 | buf->virt = vmap(buf->pages, buf->nr_pages, VM_MAP, PAGE_KERNEL); | ||
| 188 | if (!buf->virt) | ||
| 189 | goto nomem; | ||
| 190 | |||
| 191 | return buf; | ||
| 192 | |||
| 193 | nomem: | ||
| 194 | big_key_free_buffer(buf); | ||
| 195 | return NULL; | ||
| 196 | } | ||
| 197 | |||
| 198 | /* | ||
| 133 | * Preparse a big key | 199 | * Preparse a big key |
| 134 | */ | 200 | */ |
| 135 | int big_key_preparse(struct key_preparsed_payload *prep) | 201 | int big_key_preparse(struct key_preparsed_payload *prep) |
| 136 | { | 202 | { |
| 203 | struct big_key_buf *buf; | ||
| 137 | struct path *path = (struct path *)&prep->payload.data[big_key_path]; | 204 | struct path *path = (struct path *)&prep->payload.data[big_key_path]; |
| 138 | struct file *file; | 205 | struct file *file; |
| 139 | u8 *enckey; | 206 | u8 *enckey; |
| 140 | u8 *data = NULL; | ||
| 141 | ssize_t written; | 207 | ssize_t written; |
| 142 | size_t datalen = prep->datalen; | 208 | size_t datalen = prep->datalen, enclen = datalen + ENC_AUTHTAG_SIZE; |
| 143 | int ret; | 209 | int ret; |
| 144 | 210 | ||
| 145 | ret = -EINVAL; | ||
| 146 | if (datalen <= 0 || datalen > 1024 * 1024 || !prep->data) | 211 | if (datalen <= 0 || datalen > 1024 * 1024 || !prep->data) |
| 147 | goto error; | 212 | return -EINVAL; |
| 148 | 213 | ||
| 149 | /* Set an arbitrary quota */ | 214 | /* Set an arbitrary quota */ |
| 150 | prep->quotalen = 16; | 215 | prep->quotalen = 16; |
| @@ -157,13 +222,12 @@ int big_key_preparse(struct key_preparsed_payload *prep) | |||
| 157 | * | 222 | * |
| 158 | * File content is stored encrypted with randomly generated key. | 223 | * File content is stored encrypted with randomly generated key. |
| 159 | */ | 224 | */ |
| 160 | size_t enclen = datalen + ENC_AUTHTAG_SIZE; | ||
| 161 | loff_t pos = 0; | 225 | loff_t pos = 0; |
| 162 | 226 | ||
| 163 | data = kmalloc(enclen, GFP_KERNEL); | 227 | buf = big_key_alloc_buffer(enclen); |
| 164 | if (!data) | 228 | if (!buf) |
| 165 | return -ENOMEM; | 229 | return -ENOMEM; |
| 166 | memcpy(data, prep->data, datalen); | 230 | memcpy(buf->virt, prep->data, datalen); |
| 167 | 231 | ||
| 168 | /* generate random key */ | 232 | /* generate random key */ |
| 169 | enckey = kmalloc(ENC_KEY_SIZE, GFP_KERNEL); | 233 | enckey = kmalloc(ENC_KEY_SIZE, GFP_KERNEL); |
| @@ -176,7 +240,7 @@ int big_key_preparse(struct key_preparsed_payload *prep) | |||
| 176 | goto err_enckey; | 240 | goto err_enckey; |
| 177 | 241 | ||
| 178 | /* encrypt aligned data */ | 242 | /* encrypt aligned data */ |
| 179 | ret = big_key_crypt(BIG_KEY_ENC, data, datalen, enckey); | 243 | ret = big_key_crypt(BIG_KEY_ENC, buf, datalen, enckey); |
| 180 | if (ret) | 244 | if (ret) |
| 181 | goto err_enckey; | 245 | goto err_enckey; |
| 182 | 246 | ||
| @@ -187,7 +251,7 @@ int big_key_preparse(struct key_preparsed_payload *prep) | |||
| 187 | goto err_enckey; | 251 | goto err_enckey; |
| 188 | } | 252 | } |
| 189 | 253 | ||
| 190 | written = kernel_write(file, data, enclen, &pos); | 254 | written = kernel_write(file, buf->virt, enclen, &pos); |
| 191 | if (written != enclen) { | 255 | if (written != enclen) { |
| 192 | ret = written; | 256 | ret = written; |
| 193 | if (written >= 0) | 257 | if (written >= 0) |
| @@ -202,7 +266,7 @@ int big_key_preparse(struct key_preparsed_payload *prep) | |||
| 202 | *path = file->f_path; | 266 | *path = file->f_path; |
| 203 | path_get(path); | 267 | path_get(path); |
| 204 | fput(file); | 268 | fput(file); |
| 205 | kzfree(data); | 269 | big_key_free_buffer(buf); |
| 206 | } else { | 270 | } else { |
| 207 | /* Just store the data in a buffer */ | 271 | /* Just store the data in a buffer */ |
| 208 | void *data = kmalloc(datalen, GFP_KERNEL); | 272 | void *data = kmalloc(datalen, GFP_KERNEL); |
| @@ -220,7 +284,7 @@ err_fput: | |||
| 220 | err_enckey: | 284 | err_enckey: |
| 221 | kzfree(enckey); | 285 | kzfree(enckey); |
| 222 | error: | 286 | error: |
| 223 | kzfree(data); | 287 | big_key_free_buffer(buf); |
| 224 | return ret; | 288 | return ret; |
| 225 | } | 289 | } |
| 226 | 290 | ||
| @@ -298,15 +362,15 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen) | |||
| 298 | return datalen; | 362 | return datalen; |
| 299 | 363 | ||
| 300 | if (datalen > BIG_KEY_FILE_THRESHOLD) { | 364 | if (datalen > BIG_KEY_FILE_THRESHOLD) { |
| 365 | struct big_key_buf *buf; | ||
| 301 | struct path *path = (struct path *)&key->payload.data[big_key_path]; | 366 | struct path *path = (struct path *)&key->payload.data[big_key_path]; |
| 302 | struct file *file; | 367 | struct file *file; |
| 303 | u8 *data; | ||
| 304 | u8 *enckey = (u8 *)key->payload.data[big_key_data]; | 368 | u8 *enckey = (u8 *)key->payload.data[big_key_data]; |
| 305 | size_t enclen = datalen + ENC_AUTHTAG_SIZE; | 369 | size_t enclen = datalen + ENC_AUTHTAG_SIZE; |
| 306 | loff_t pos = 0; | 370 | loff_t pos = 0; |
| 307 | 371 | ||
| 308 | data = kmalloc(enclen, GFP_KERNEL); | 372 | buf = big_key_alloc_buffer(enclen); |
| 309 | if (!data) | 373 | if (!buf) |
| 310 | return -ENOMEM; | 374 | return -ENOMEM; |
| 311 | 375 | ||
| 312 | file = dentry_open(path, O_RDONLY, current_cred()); | 376 | file = dentry_open(path, O_RDONLY, current_cred()); |
| @@ -316,26 +380,26 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen) | |||
| 316 | } | 380 | } |
| 317 | 381 | ||
| 318 | /* read file to kernel and decrypt */ | 382 | /* read file to kernel and decrypt */ |
| 319 | ret = kernel_read(file, data, enclen, &pos); | 383 | ret = kernel_read(file, buf->virt, enclen, &pos); |
| 320 | if (ret >= 0 && ret != enclen) { | 384 | if (ret >= 0 && ret != enclen) { |
| 321 | ret = -EIO; | 385 | ret = -EIO; |
| 322 | goto err_fput; | 386 | goto err_fput; |
| 323 | } | 387 | } |
| 324 | 388 | ||
| 325 | ret = big_key_crypt(BIG_KEY_DEC, data, enclen, enckey); | 389 | ret = big_key_crypt(BIG_KEY_DEC, buf, enclen, enckey); |
| 326 | if (ret) | 390 | if (ret) |
| 327 | goto err_fput; | 391 | goto err_fput; |
| 328 | 392 | ||
| 329 | ret = datalen; | 393 | ret = datalen; |
| 330 | 394 | ||
| 331 | /* copy decrypted data to user */ | 395 | /* copy decrypted data to user */ |
| 332 | if (copy_to_user(buffer, data, datalen) != 0) | 396 | if (copy_to_user(buffer, buf->virt, datalen) != 0) |
| 333 | ret = -EFAULT; | 397 | ret = -EFAULT; |
| 334 | 398 | ||
| 335 | err_fput: | 399 | err_fput: |
| 336 | fput(file); | 400 | fput(file); |
| 337 | error: | 401 | error: |
| 338 | kzfree(data); | 402 | big_key_free_buffer(buf); |
| 339 | } else { | 403 | } else { |
| 340 | ret = datalen; | 404 | ret = datalen; |
| 341 | if (copy_to_user(buffer, key->payload.data[big_key_data], | 405 | if (copy_to_user(buffer, key->payload.data[big_key_data], |
