Package: nss / 3.12.8-1+squeeze14

CVE-2015-7182.patch Patch series | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
From: =?utf-8?q?Guido_G=C3=BCnther?= <agx@sigxcpu.org>
Date: Mon, 23 Nov 2015 11:20:50 +0100
Subject: CVE-2015-7182

Consisting of upstream commits

    https://hg.mozilla.org/projects/nss/raw-rev/4dc247276e58
    https://hg.mozilla.org/projects/nss/raw-rev/534aca7a5bca
    https://hg.mozilla.org/projects/nss/raw-rev/b4feb2cb0ed6
---
 mozilla/security/nss/lib/util/secasn1d.c | 99 +++++++++++++++++++++++++++++++-
 1 file changed, 98 insertions(+), 1 deletion(-)

diff --git a/mozilla/security/nss/lib/util/secasn1d.c b/mozilla/security/nss/lib/util/secasn1d.c
index a1323f2..1b4bad8 100644
--- a/mozilla/security/nss/lib/util/secasn1d.c
+++ b/mozilla/security/nss/lib/util/secasn1d.c
@@ -1754,10 +1754,107 @@ sec_asn1d_next_substring (sec_asn1d_state *state)
 	if (state->pending == 0)
 	    done = PR_TRUE;
     } else {
+	PRBool preallocatedString;
+	sec_asn1d_state *temp_state;
 	PORT_Assert (state->indefinite);
 
 	item = (SECItem *)(child->dest);
-	if (item != NULL && item->data != NULL) {
+
+	/**
+	 * At this point, there's three states at play:
+	 *   child: The element that was just parsed
+	 *   state: The currently processed element
+	 *   'parent' (aka state->parent): The enclosing construct
+	 *      of state, or NULL if this is the top-most element.
+	 *
+	 * This state handles both substrings of a constructed string AND
+	 * child elements of items whose template type was that of
+	 * SEC_ASN1_ANY, SEC_ASN1_SAVE, SEC_ASN1_ANY_CONTENTS, SEC_ASN1_SKIP
+	 * template, as described in sec_asn1d_prepare_for_contents. For
+	 * brevity, these will be referred to as 'string' and 'any' types.
+	 *
+	 * This leads to the following possibilities:
+	 *   1: This element is an indefinite length string, part of a
+	 *      definite length string.
+	 *   2: This element is an indefinite length string, part of an
+	 *      indefinite length string.
+	 *   3: This element is an indefinite length any, part of a
+	 *      definite length any.
+	 *   4: This element is an indefinite length any, part of an
+	 *      indefinite length any.
+	 *   5: This element is an indefinite length any and does not
+	 *      meet any of the above criteria. Note that this would include
+	 *      an indefinite length string type matching an indefinite
+	 *      length any template.
+	 *
+	 * In Cases #1 and #3, the definite length 'parent' element will
+	 * have allocated state->dest based on the parent elements definite
+	 * size. During the processing of 'child', sec_asn1d_parse_leaf will
+	 * have copied the (string, any) data directly into the offset of
+	 * dest, as appropriate, so there's no need for this class to still
+	 * store the child - it's already been processed.
+	 *
+	 * In Cases #2 and #4, dest will be set to the parent element's dest,
+	 * but dest->data will not have been allocated yet, due to the
+	 * indefinite length encoding. In this situation, it's necessary to
+	 * hold onto child (and all other children) until the EOC, at which
+	 * point, it becomes possible to compute 'state's overall length. Once
+	 * 'state' has a computed length, this can then be fed to 'parent' (via
+	 * this state), and then 'parent' can similarly compute the length of
+	 * all of its children up to the EOC, which will ultimately transit to
+	 * sec_asn1d_concat_substrings, determine the overall size needed,
+	 * allocate, and copy the contents (of all of parent's children, which
+	 * would include 'state', just as 'state' will have copied all of its
+	 * children via sec_asn1d_concat_substrings)
+	 *
+	 * The final case, Case #5, will manifest in that item->data and
+	 * item->len will be NULL/0, respectively, since this element was
+	 * indefinite-length encoded. In that case, both the tag and length will
+	 * already exist in state's subitems, via sec_asn1d_record_any_header,
+	 * and so the contents (aka 'child') should be added to that list of
+	 * items to concatenate in sec_asn1d_concat_substrings once the EOC
+	 * is encountered.
+	 *
+	 * To distinguish #2/#4 from #1/#3, it's sufficient to walk the ancestor
+	 * tree. If the current type is a string type, then the enclosing
+	 * construct will be that same type (#1/#2). If the current type is an
+	 * any type, then the enclosing construct is either an any type (#3/#4)
+	 * or some other type (#5). Since this is BER, this nesting relationship
+	 * between 'state' and 'parent' may go through several levels of
+	 * constructed encoding, so continue walking the ancestor chain until a
+	 * clear determination can be made.
+	 *
+	 * The variable preallocatedString is used to indicate Case #1/#3,
+	 * indicating an in-place copy has already occurred, and Cases #2, #4,
+	 * and #5 all have the same behaviour of adding a new substring.
+	 */
+	preallocatedString = PR_FALSE;
+	temp_state = state;
+	while (temp_state && item == temp_state->dest && temp_state->indefinite) {
+	    sec_asn1d_state *parent = sec_asn1d_get_enclosing_construct(temp_state);
+	    if (!parent || parent->underlying_kind != temp_state->underlying_kind) {
+	        /* Case #5 - Either this is a top-level construct or it is part
+	         * of some other element (e.g. a SEQUENCE), in which case, a
+	         * new item should be allocated. */
+	        break;
+	    }
+	    if (!parent->indefinite) {
+	        /* Cases #1 / #3 - A definite length ancestor exists, for which
+	         * this is a substring that has already copied into dest. */
+	        preallocatedString = PR_TRUE;
+	        break;
+	    }
+	    if (!parent->substring) {
+	        /* Cases #2 / #4 - If the parent is not a substring, but is
+	         * indefinite, then there's nothing further up that may have
+	         * preallocated dest, thus child will not have already
+		 * been copied in place, therefore it's necessary to save child
+		 * as a subitem. */
+	        break;
+	    }
+	    temp_state = parent;
+	}
+	if (item != NULL && item->data != NULL && !preallocatedString) {
 	    /*
 	     * Save the string away for later concatenation.
 	     */