diff options
author | djm <> | 2012-04-22 01:38:24 +0000 |
---|---|---|
committer | djm <> | 2012-04-22 01:38:24 +0000 |
commit | 0757e0fdcc16f903467fb60ce960a41f09cb62d6 (patch) | |
tree | 9caa6ce28230c0ae8dafd61b3b9e5006aacdb463 | |
parent | e19d8021cba737c4b0797c786c4bc2a2968c1b37 (diff) | |
download | openbsd-OPENBSD_5_0.tar.gz openbsd-OPENBSD_5_0.tar.bz2 openbsd-OPENBSD_5_0.zip |
MFCOPENBSD_5_0
mem.c
revision 1.14
date: 2012/04/19 22:57:38; author: djm; state: Exp; lines: +4 -0
cherrypick fix for CVE-2012-2110: libcrypto ASN.1 parsing heap overflow
ok miod@ deraadt@
asn1/a_d2i_fp.c
revision 1.6
date: 2012/04/19 22:57:38; author: djm; state: Exp; lines: +40 -14
cherrypick fix for CVE-2012-2110: libcrypto ASN.1 parsing heap overflow
ok miod@ deraadt@
buffer/buffer.c
revision 1.9
date: 2012/04/19 22:57:38; author: djm; state: Exp; lines: +17 -0
cherrypick fix for CVE-2012-2110: libcrypto ASN.1 parsing heap overflow
ok miod@ deraadt@
-rw-r--r-- | src/lib/libcrypto/mem.c | 4 | ||||
-rw-r--r-- | src/lib/libssl/src/crypto/asn1/a_d2i_fp.c | 54 | ||||
-rw-r--r-- | src/lib/libssl/src/crypto/buffer/buffer.c | 17 | ||||
-rw-r--r-- | src/lib/libssl/src/crypto/mem.c | 4 |
4 files changed, 65 insertions, 14 deletions
diff --git a/src/lib/libcrypto/mem.c b/src/lib/libcrypto/mem.c index 8f06d190a1..9ecb8d26b1 100644 --- a/src/lib/libcrypto/mem.c +++ b/src/lib/libcrypto/mem.c | |||
@@ -362,6 +362,10 @@ void *CRYPTO_realloc_clean(void *str, int old_len, int num, const char *file, | |||
362 | 362 | ||
363 | if (num <= 0) return NULL; | 363 | if (num <= 0) return NULL; |
364 | 364 | ||
365 | /* We don't support shrinking the buffer. Note the memcpy that copies | ||
366 | * |old_len| bytes to the new buffer, below. */ | ||
367 | if (num < old_len) return NULL; | ||
368 | |||
365 | if (realloc_debug_func != NULL) | 369 | if (realloc_debug_func != NULL) |
366 | realloc_debug_func(str, NULL, num, file, line, 0); | 370 | realloc_debug_func(str, NULL, num, file, line, 0); |
367 | ret=malloc_ex_func(num,file,line); | 371 | ret=malloc_ex_func(num,file,line); |
diff --git a/src/lib/libssl/src/crypto/asn1/a_d2i_fp.c b/src/lib/libssl/src/crypto/asn1/a_d2i_fp.c index ece40bc4c0..52b2ebdb63 100644 --- a/src/lib/libssl/src/crypto/asn1/a_d2i_fp.c +++ b/src/lib/libssl/src/crypto/asn1/a_d2i_fp.c | |||
@@ -57,6 +57,7 @@ | |||
57 | */ | 57 | */ |
58 | 58 | ||
59 | #include <stdio.h> | 59 | #include <stdio.h> |
60 | #include <limits.h> | ||
60 | #include "cryptlib.h" | 61 | #include "cryptlib.h" |
61 | #include <openssl/buffer.h> | 62 | #include <openssl/buffer.h> |
62 | #include <openssl/asn1_mac.h> | 63 | #include <openssl/asn1_mac.h> |
@@ -143,17 +144,11 @@ static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb) | |||
143 | BUF_MEM *b; | 144 | BUF_MEM *b; |
144 | unsigned char *p; | 145 | unsigned char *p; |
145 | int i; | 146 | int i; |
146 | int ret=-1; | ||
147 | ASN1_const_CTX c; | 147 | ASN1_const_CTX c; |
148 | int want=HEADER_SIZE; | 148 | size_t want=HEADER_SIZE; |
149 | int eos=0; | 149 | int eos=0; |
150 | #if defined(__GNUC__) && defined(__ia64) | 150 | size_t off=0; |
151 | /* pathetic compiler bug in all known versions as of Nov. 2002 */ | 151 | size_t len=0; |
152 | long off=0; | ||
153 | #else | ||
154 | int off=0; | ||
155 | #endif | ||
156 | int len=0; | ||
157 | 152 | ||
158 | b=BUF_MEM_new(); | 153 | b=BUF_MEM_new(); |
159 | if (b == NULL) | 154 | if (b == NULL) |
@@ -169,7 +164,7 @@ static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb) | |||
169 | { | 164 | { |
170 | want-=(len-off); | 165 | want-=(len-off); |
171 | 166 | ||
172 | if (!BUF_MEM_grow_clean(b,len+want)) | 167 | if (len + want < len || !BUF_MEM_grow_clean(b,len+want)) |
173 | { | 168 | { |
174 | ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ERR_R_MALLOC_FAILURE); | 169 | ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ERR_R_MALLOC_FAILURE); |
175 | goto err; | 170 | goto err; |
@@ -181,7 +176,14 @@ static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb) | |||
181 | goto err; | 176 | goto err; |
182 | } | 177 | } |
183 | if (i > 0) | 178 | if (i > 0) |
179 | { | ||
180 | if (len+i < len) | ||
181 | { | ||
182 | ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ASN1_R_TOO_LONG); | ||
183 | goto err; | ||
184 | } | ||
184 | len+=i; | 185 | len+=i; |
186 | } | ||
185 | } | 187 | } |
186 | /* else data already loaded */ | 188 | /* else data already loaded */ |
187 | 189 | ||
@@ -206,6 +208,11 @@ static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb) | |||
206 | { | 208 | { |
207 | /* no data body so go round again */ | 209 | /* no data body so go round again */ |
208 | eos++; | 210 | eos++; |
211 | if (eos < 0) | ||
212 | { | ||
213 | ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ASN1_R_HEADER_TOO_LONG); | ||
214 | goto err; | ||
215 | } | ||
209 | want=HEADER_SIZE; | 216 | want=HEADER_SIZE; |
210 | } | 217 | } |
211 | else if (eos && (c.slen == 0) && (c.tag == V_ASN1_EOC)) | 218 | else if (eos && (c.slen == 0) && (c.tag == V_ASN1_EOC)) |
@@ -220,10 +227,16 @@ static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb) | |||
220 | else | 227 | else |
221 | { | 228 | { |
222 | /* suck in c.slen bytes of data */ | 229 | /* suck in c.slen bytes of data */ |
223 | want=(int)c.slen; | 230 | want=c.slen; |
224 | if (want > (len-off)) | 231 | if (want > (len-off)) |
225 | { | 232 | { |
226 | want-=(len-off); | 233 | want-=(len-off); |
234 | if (want > INT_MAX /* BIO_read takes an int length */ || | ||
235 | len+want < len) | ||
236 | { | ||
237 | ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ASN1_R_TOO_LONG); | ||
238 | goto err; | ||
239 | } | ||
227 | if (!BUF_MEM_grow_clean(b,len+want)) | 240 | if (!BUF_MEM_grow_clean(b,len+want)) |
228 | { | 241 | { |
229 | ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ERR_R_MALLOC_FAILURE); | 242 | ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ERR_R_MALLOC_FAILURE); |
@@ -238,11 +251,18 @@ static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb) | |||
238 | ASN1_R_NOT_ENOUGH_DATA); | 251 | ASN1_R_NOT_ENOUGH_DATA); |
239 | goto err; | 252 | goto err; |
240 | } | 253 | } |
254 | /* This can't overflow because | ||
255 | * |len+want| didn't overflow. */ | ||
241 | len+=i; | 256 | len+=i; |
242 | want -= i; | 257 | want-=i; |
243 | } | 258 | } |
244 | } | 259 | } |
245 | off+=(int)c.slen; | 260 | if (off + c.slen < off) |
261 | { | ||
262 | ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ASN1_R_TOO_LONG); | ||
263 | goto err; | ||
264 | } | ||
265 | off+=c.slen; | ||
246 | if (eos <= 0) | 266 | if (eos <= 0) |
247 | { | 267 | { |
248 | break; | 268 | break; |
@@ -252,9 +272,15 @@ static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb) | |||
252 | } | 272 | } |
253 | } | 273 | } |
254 | 274 | ||
275 | if (off > INT_MAX) | ||
276 | { | ||
277 | ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ASN1_R_TOO_LONG); | ||
278 | goto err; | ||
279 | } | ||
280 | |||
255 | *pb = b; | 281 | *pb = b; |
256 | return off; | 282 | return off; |
257 | err: | 283 | err: |
258 | if (b != NULL) BUF_MEM_free(b); | 284 | if (b != NULL) BUF_MEM_free(b); |
259 | return(ret); | 285 | return -1; |
260 | } | 286 | } |
diff --git a/src/lib/libssl/src/crypto/buffer/buffer.c b/src/lib/libssl/src/crypto/buffer/buffer.c index 620ea8d536..bc803ab6c8 100644 --- a/src/lib/libssl/src/crypto/buffer/buffer.c +++ b/src/lib/libssl/src/crypto/buffer/buffer.c | |||
@@ -60,6 +60,11 @@ | |||
60 | #include "cryptlib.h" | 60 | #include "cryptlib.h" |
61 | #include <openssl/buffer.h> | 61 | #include <openssl/buffer.h> |
62 | 62 | ||
63 | /* LIMIT_BEFORE_EXPANSION is the maximum n such that (n+3)/3*4 < 2**31. That | ||
64 | * function is applied in several functions in this file and this limit ensures | ||
65 | * that the result fits in an int. */ | ||
66 | #define LIMIT_BEFORE_EXPANSION 0x5ffffffc | ||
67 | |||
63 | BUF_MEM *BUF_MEM_new(void) | 68 | BUF_MEM *BUF_MEM_new(void) |
64 | { | 69 | { |
65 | BUF_MEM *ret; | 70 | BUF_MEM *ret; |
@@ -105,6 +110,12 @@ int BUF_MEM_grow(BUF_MEM *str, size_t len) | |||
105 | str->length=len; | 110 | str->length=len; |
106 | return(len); | 111 | return(len); |
107 | } | 112 | } |
113 | /* This limit is sufficient to ensure (len+3)/3*4 < 2**31 */ | ||
114 | if (len > LIMIT_BEFORE_EXPANSION) | ||
115 | { | ||
116 | BUFerr(BUF_F_BUF_MEM_GROW,ERR_R_MALLOC_FAILURE); | ||
117 | return 0; | ||
118 | } | ||
108 | n=(len+3)/3*4; | 119 | n=(len+3)/3*4; |
109 | if (str->data == NULL) | 120 | if (str->data == NULL) |
110 | ret=OPENSSL_malloc(n); | 121 | ret=OPENSSL_malloc(n); |
@@ -142,6 +153,12 @@ int BUF_MEM_grow_clean(BUF_MEM *str, size_t len) | |||
142 | str->length=len; | 153 | str->length=len; |
143 | return(len); | 154 | return(len); |
144 | } | 155 | } |
156 | /* This limit is sufficient to ensure (len+3)/3*4 < 2**31 */ | ||
157 | if (len > LIMIT_BEFORE_EXPANSION) | ||
158 | { | ||
159 | BUFerr(BUF_F_BUF_MEM_GROW,ERR_R_MALLOC_FAILURE); | ||
160 | return 0; | ||
161 | } | ||
145 | n=(len+3)/3*4; | 162 | n=(len+3)/3*4; |
146 | if (str->data == NULL) | 163 | if (str->data == NULL) |
147 | ret=OPENSSL_malloc(n); | 164 | ret=OPENSSL_malloc(n); |
diff --git a/src/lib/libssl/src/crypto/mem.c b/src/lib/libssl/src/crypto/mem.c index 8f06d190a1..9ecb8d26b1 100644 --- a/src/lib/libssl/src/crypto/mem.c +++ b/src/lib/libssl/src/crypto/mem.c | |||
@@ -362,6 +362,10 @@ void *CRYPTO_realloc_clean(void *str, int old_len, int num, const char *file, | |||
362 | 362 | ||
363 | if (num <= 0) return NULL; | 363 | if (num <= 0) return NULL; |
364 | 364 | ||
365 | /* We don't support shrinking the buffer. Note the memcpy that copies | ||
366 | * |old_len| bytes to the new buffer, below. */ | ||
367 | if (num < old_len) return NULL; | ||
368 | |||
365 | if (realloc_debug_func != NULL) | 369 | if (realloc_debug_func != NULL) |
366 | realloc_debug_func(str, NULL, num, file, line, 0); | 370 | realloc_debug_func(str, NULL, num, file, line, 0); |
367 | ret=malloc_ex_func(num,file,line); | 371 | ret=malloc_ex_func(num,file,line); |