mirror of
https://github.com/Divested-Mobile/DivestOS-Build.git
synced 2024-12-29 01:16:26 -05:00
89 lines
2.6 KiB
Diff
89 lines
2.6 KiB
Diff
From 23c8a812dc3c621009e4f0e5342aa4e2ede1ceaa Mon Sep 17 00:00:00 2001
|
|
From: David Howells <dhowells@redhat.com>
|
|
Date: Tue, 23 Feb 2016 11:03:12 +0000
|
|
Subject: [PATCH] KEYS: Fix ASN.1 indefinite length object parsing
|
|
|
|
This fixes CVE-2016-0758.
|
|
|
|
In the ASN.1 decoder, when the length field of an ASN.1 value is extracted,
|
|
it isn't validated against the remaining amount of data before being added
|
|
to the cursor. With a sufficiently large size indicated, the check:
|
|
|
|
datalen - dp < 2
|
|
|
|
may then fail due to integer overflow.
|
|
|
|
Fix this by checking the length indicated against the amount of remaining
|
|
data in both places a definite length is determined.
|
|
|
|
Whilst we're at it, make the following changes:
|
|
|
|
(1) Check the maximum size of extended length does not exceed the capacity
|
|
of the variable it's being stored in (len) rather than the type that
|
|
variable is assumed to be (size_t).
|
|
|
|
(2) Compare the EOC tag to the symbolic constant ASN1_EOC rather than the
|
|
integer 0.
|
|
|
|
(3) To reduce confusion, move the initialisation of len outside of:
|
|
|
|
for (len = 0; n > 0; n--) {
|
|
|
|
since it doesn't have anything to do with the loop counter n.
|
|
|
|
Signed-off-by: David Howells <dhowells@redhat.com>
|
|
Reviewed-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
|
|
Acked-by: David Woodhouse <David.Woodhouse@intel.com>
|
|
Acked-by: Peter Jones <pjones@redhat.com>
|
|
---
|
|
lib/asn1_decoder.c | 16 +++++++++-------
|
|
1 file changed, 9 insertions(+), 7 deletions(-)
|
|
|
|
diff --git a/lib/asn1_decoder.c b/lib/asn1_decoder.c
|
|
index 2b3f46c049d45..554522934c442 100644
|
|
--- a/lib/asn1_decoder.c
|
|
+++ b/lib/asn1_decoder.c
|
|
@@ -74,7 +74,7 @@ static int asn1_find_indefinite_length(const unsigned char *data, size_t datalen
|
|
|
|
/* Extract a tag from the data */
|
|
tag = data[dp++];
|
|
- if (tag == 0) {
|
|
+ if (tag == ASN1_EOC) {
|
|
/* It appears to be an EOC. */
|
|
if (data[dp++] != 0)
|
|
goto invalid_eoc;
|
|
@@ -96,10 +96,8 @@ static int asn1_find_indefinite_length(const unsigned char *data, size_t datalen
|
|
|
|
/* Extract the length */
|
|
len = data[dp++];
|
|
- if (len <= 0x7f) {
|
|
- dp += len;
|
|
- goto next_tag;
|
|
- }
|
|
+ if (len <= 0x7f)
|
|
+ goto check_length;
|
|
|
|
if (unlikely(len == ASN1_INDEFINITE_LENGTH)) {
|
|
/* Indefinite length */
|
|
@@ -110,14 +108,18 @@ static int asn1_find_indefinite_length(const unsigned char *data, size_t datalen
|
|
}
|
|
|
|
n = len - 0x80;
|
|
- if (unlikely(n > sizeof(size_t) - 1))
|
|
+ if (unlikely(n > sizeof(len) - 1))
|
|
goto length_too_long;
|
|
if (unlikely(n > datalen - dp))
|
|
goto data_overrun_error;
|
|
- for (len = 0; n > 0; n--) {
|
|
+ len = 0;
|
|
+ for (; n > 0; n--) {
|
|
len <<= 8;
|
|
len |= data[dp++];
|
|
}
|
|
+check_length:
|
|
+ if (len > datalen - dp)
|
|
+ goto data_overrun_error;
|
|
dp += len;
|
|
goto next_tag;
|
|
|