diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-02 10:43:40 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-02 10:43:40 -0400 |
commit | 6965f1aa7142a2989733c6ec53cc42ae97fd7f9d (patch) | |
tree | fbd13ab1bc848d3f44b821df307c8538ab965972 | |
parent | e78c38f6bdd900b2ad9ac9df8eff58b745dc5b3c (diff) | |
parent | 2eb9eabf1e868fda15808954fb29b0f105ed65f1 (diff) |
Merge branch 'fixes-v4.14-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull key handling fixes from James Morris:
"Fixes for the Keys subsystem by Eric Biggers"
* 'fixes-v4.14-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security:
KEYS: fix out-of-bounds read during ASN.1 parsing
KEYS: trusted: fix writing past end of buffer in trusted_read()
KEYS: return full count in keyring_read() if buffer is too small
-rw-r--r-- | lib/asn1_decoder.c | 3 | ||||
-rw-r--r-- | security/keys/keyring.c | 39 | ||||
-rw-r--r-- | security/keys/trusted.c | 23 |
3 files changed, 34 insertions, 31 deletions
diff --git a/lib/asn1_decoder.c b/lib/asn1_decoder.c index 0bd8a611eb83..fef5d2e114be 100644 --- a/lib/asn1_decoder.c +++ b/lib/asn1_decoder.c | |||
@@ -284,6 +284,9 @@ next_op: | |||
284 | if (unlikely(len > datalen - dp)) | 284 | if (unlikely(len > datalen - dp)) |
285 | goto data_overrun_error; | 285 | goto data_overrun_error; |
286 | } | 286 | } |
287 | } else { | ||
288 | if (unlikely(len > datalen - dp)) | ||
289 | goto data_overrun_error; | ||
287 | } | 290 | } |
288 | 291 | ||
289 | if (flags & FLAG_CONS) { | 292 | if (flags & FLAG_CONS) { |
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index a7e51f793867..36f842ec87f0 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
@@ -459,34 +459,33 @@ static long keyring_read(const struct key *keyring, | |||
459 | char __user *buffer, size_t buflen) | 459 | char __user *buffer, size_t buflen) |
460 | { | 460 | { |
461 | struct keyring_read_iterator_context ctx; | 461 | struct keyring_read_iterator_context ctx; |
462 | unsigned long nr_keys; | 462 | long ret; |
463 | int ret; | ||
464 | 463 | ||
465 | kenter("{%d},,%zu", key_serial(keyring), buflen); | 464 | kenter("{%d},,%zu", key_serial(keyring), buflen); |
466 | 465 | ||
467 | if (buflen & (sizeof(key_serial_t) - 1)) | 466 | if (buflen & (sizeof(key_serial_t) - 1)) |
468 | return -EINVAL; | 467 | return -EINVAL; |
469 | 468 | ||
470 | nr_keys = keyring->keys.nr_leaves_on_tree; | 469 | /* Copy as many key IDs as fit into the buffer */ |
471 | if (nr_keys == 0) | 470 | if (buffer && buflen) { |
472 | return 0; | 471 | ctx.buffer = (key_serial_t __user *)buffer; |
473 | 472 | ctx.buflen = buflen; | |
474 | /* Calculate how much data we could return */ | 473 | ctx.count = 0; |
475 | if (!buffer || !buflen) | 474 | ret = assoc_array_iterate(&keyring->keys, |
476 | return nr_keys * sizeof(key_serial_t); | 475 | keyring_read_iterator, &ctx); |
477 | 476 | if (ret < 0) { | |
478 | /* Copy the IDs of the subscribed keys into the buffer */ | 477 | kleave(" = %ld [iterate]", ret); |
479 | ctx.buffer = (key_serial_t __user *)buffer; | 478 | return ret; |
480 | ctx.buflen = buflen; | 479 | } |
481 | ctx.count = 0; | ||
482 | ret = assoc_array_iterate(&keyring->keys, keyring_read_iterator, &ctx); | ||
483 | if (ret < 0) { | ||
484 | kleave(" = %d [iterate]", ret); | ||
485 | return ret; | ||
486 | } | 480 | } |
487 | 481 | ||
488 | kleave(" = %zu [ok]", ctx.count); | 482 | /* Return the size of the buffer needed */ |
489 | return ctx.count; | 483 | ret = keyring->keys.nr_leaves_on_tree * sizeof(key_serial_t); |
484 | if (ret <= buflen) | ||
485 | kleave("= %ld [ok]", ret); | ||
486 | else | ||
487 | kleave("= %ld [buffer too small]", ret); | ||
488 | return ret; | ||
490 | } | 489 | } |
491 | 490 | ||
492 | /* | 491 | /* |
diff --git a/security/keys/trusted.c b/security/keys/trusted.c index bd85315cbfeb..98aa89ff7bfd 100644 --- a/security/keys/trusted.c +++ b/security/keys/trusted.c | |||
@@ -1147,20 +1147,21 @@ static long trusted_read(const struct key *key, char __user *buffer, | |||
1147 | p = dereference_key_locked(key); | 1147 | p = dereference_key_locked(key); |
1148 | if (!p) | 1148 | if (!p) |
1149 | return -EINVAL; | 1149 | return -EINVAL; |
1150 | if (!buffer || buflen <= 0) | ||
1151 | return 2 * p->blob_len; | ||
1152 | ascii_buf = kmalloc(2 * p->blob_len, GFP_KERNEL); | ||
1153 | if (!ascii_buf) | ||
1154 | return -ENOMEM; | ||
1155 | 1150 | ||
1156 | bufp = ascii_buf; | 1151 | if (buffer && buflen >= 2 * p->blob_len) { |
1157 | for (i = 0; i < p->blob_len; i++) | 1152 | ascii_buf = kmalloc(2 * p->blob_len, GFP_KERNEL); |
1158 | bufp = hex_byte_pack(bufp, p->blob[i]); | 1153 | if (!ascii_buf) |
1159 | if ((copy_to_user(buffer, ascii_buf, 2 * p->blob_len)) != 0) { | 1154 | return -ENOMEM; |
1155 | |||
1156 | bufp = ascii_buf; | ||
1157 | for (i = 0; i < p->blob_len; i++) | ||
1158 | bufp = hex_byte_pack(bufp, p->blob[i]); | ||
1159 | if (copy_to_user(buffer, ascii_buf, 2 * p->blob_len) != 0) { | ||
1160 | kzfree(ascii_buf); | ||
1161 | return -EFAULT; | ||
1162 | } | ||
1160 | kzfree(ascii_buf); | 1163 | kzfree(ascii_buf); |
1161 | return -EFAULT; | ||
1162 | } | 1164 | } |
1163 | kzfree(ascii_buf); | ||
1164 | return 2 * p->blob_len; | 1165 | return 2 * p->blob_len; |
1165 | } | 1166 | } |
1166 | 1167 | ||