diff options
author | schwarze <> | 2020-07-23 17:15:35 +0000 |
---|---|---|
committer | schwarze <> | 2020-07-23 17:15:35 +0000 |
commit | 006d896f4376dbbbff0a958d5fe8639ab0c070d5 (patch) | |
tree | c8fd156c6634db94fcd09f8530f24d6fe60371b3 /src/lib | |
parent | f9151c76d47b4d5c6c4e171b7c4d485a6ff5dd12 (diff) | |
download | openbsd-006d896f4376dbbbff0a958d5fe8639ab0c070d5.tar.gz openbsd-006d896f4376dbbbff0a958d5fe8639ab0c070d5.tar.bz2 openbsd-006d896f4376dbbbff0a958d5fe8639ab0c070d5.zip |
Fix a bug in PEM_X509_INFO_read_bio(3) that is very likely to cause
use-after-free and double-free issues in calling programs.
The bug was introduced in SSLeay-0.6.0 released on June 21, 1996
and has been present since OpenBSD 2.4.
I found the bug while documenting the function.
The bug could bite in two ways that looked quite different from the
perspective of the calling code:
* If a stack was passed in that already contained some X509_INFO
objects and an error occurred, all the objects passed in would be
freed, but without removing the freed pointers from the stack,
so the calling code would probable continue to access the freed
pointers and eventually free them a second time.
* If the input BIO contained at least two valid PEM objects followed by
at least one PEM object causing an error, at least one freed pointer
would be put onto the stack, even though the function would return NULL
rather than the stack. But the calling code would still have a pointer
to the stack, so it would be likely to access the new bogus pointers
sooner or later.
Fix all this by remembering the size of the input stack on entry
and cutting it back to exactly that size when exiting due to an
error, but no further.
While here, do some related cleanup:
* Garbage collect the automatic variables "error" and "i"
which were only used at one single place each.
* Use NULL rather than 0 for pointers.
I like bugfixes that make the code four lines shorter, reduce the
number of variables by one, reduce the number of brace-blocks by
one, reduce the number if if-statements by one, and reduce the
number of else-clauses by one.
Tweaks and OK tb@.
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/libcrypto/pem/pem_info.c | 38 |
1 files changed, 17 insertions, 21 deletions
diff --git a/src/lib/libcrypto/pem/pem_info.c b/src/lib/libcrypto/pem/pem_info.c index f02aaa8bb4..9561b5f4df 100644 --- a/src/lib/libcrypto/pem/pem_info.c +++ b/src/lib/libcrypto/pem/pem_info.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: pem_info.c,v 1.22 2017/01/29 17:49:23 beck Exp $ */ | 1 | /* $OpenBSD: pem_info.c,v 1.23 2020/07/23 17:15:35 schwarze Exp $ */ |
2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) | 2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
3 | * All rights reserved. | 3 | * All rights reserved. |
4 | * | 4 | * |
@@ -101,29 +101,28 @@ PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb, | |||
101 | void *pp; | 101 | void *pp; |
102 | unsigned char *data = NULL; | 102 | unsigned char *data = NULL; |
103 | const unsigned char *p; | 103 | const unsigned char *p; |
104 | long len, error = 0; | 104 | long len; |
105 | int ok = 0; | 105 | int ok = 0; |
106 | STACK_OF(X509_INFO) *ret = NULL; | 106 | int num_in, ptype, raw; |
107 | unsigned int i, raw, ptype; | 107 | STACK_OF(X509_INFO) *ret = sk; |
108 | d2i_of_void *d2i = 0; | 108 | d2i_of_void *d2i = NULL; |
109 | 109 | ||
110 | if (sk == NULL) { | 110 | if (ret == NULL) { |
111 | if ((ret = sk_X509_INFO_new_null()) == NULL) { | 111 | if ((ret = sk_X509_INFO_new_null()) == NULL) { |
112 | PEMerror(ERR_R_MALLOC_FAILURE); | 112 | PEMerror(ERR_R_MALLOC_FAILURE); |
113 | return 0; | 113 | return NULL; |
114 | } | 114 | } |
115 | } else | 115 | } |
116 | ret = sk; | 116 | num_in = sk_X509_INFO_num(ret); |
117 | 117 | ||
118 | if ((xi = X509_INFO_new()) == NULL) | 118 | if ((xi = X509_INFO_new()) == NULL) |
119 | goto err; | 119 | goto err; |
120 | for (;;) { | 120 | for (;;) { |
121 | raw = 0; | 121 | raw = 0; |
122 | ptype = 0; | 122 | ptype = 0; |
123 | i = PEM_read_bio(bp, &name, &header, &data, &len); | 123 | if (!PEM_read_bio(bp, &name, &header, &data, &len)) { |
124 | if (i == 0) { | 124 | if (ERR_GET_REASON(ERR_peek_last_error()) == |
125 | error = ERR_GET_REASON(ERR_peek_last_error()); | 125 | PEM_R_NO_START_LINE) { |
126 | if (error == PEM_R_NO_START_LINE) { | ||
127 | ERR_clear_error(); | 126 | ERR_clear_error(); |
128 | break; | 127 | break; |
129 | } | 128 | } |
@@ -286,22 +285,19 @@ start: | |||
286 | ok = 1; | 285 | ok = 1; |
287 | 286 | ||
288 | err: | 287 | err: |
289 | if (xi != NULL) | ||
290 | X509_INFO_free(xi); | ||
291 | if (!ok) { | 288 | if (!ok) { |
292 | for (i = 0; ((int)i) < sk_X509_INFO_num(ret); i++) { | 289 | while (sk_X509_INFO_num(ret) > num_in) |
293 | xi = sk_X509_INFO_value(ret, i); | 290 | X509_INFO_free(sk_X509_INFO_pop(ret)); |
294 | X509_INFO_free(xi); | ||
295 | } | ||
296 | if (ret != sk) | 291 | if (ret != sk) |
297 | sk_X509_INFO_free(ret); | 292 | sk_X509_INFO_free(ret); |
298 | ret = NULL; | 293 | ret = NULL; |
299 | } | 294 | } |
300 | 295 | X509_INFO_free(xi); | |
301 | free(name); | 296 | free(name); |
302 | free(header); | 297 | free(header); |
303 | free(data); | 298 | free(data); |
304 | return (ret); | 299 | |
300 | return ret; | ||
305 | } | 301 | } |
306 | 302 | ||
307 | 303 | ||