summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorschwarze <>2020-07-23 17:15:35 +0000
committerschwarze <>2020-07-23 17:15:35 +0000
commit006d896f4376dbbbff0a958d5fe8639ab0c070d5 (patch)
treec8fd156c6634db94fcd09f8530f24d6fe60371b3 /src/lib
parentf9151c76d47b4d5c6c4e171b7c4d485a6ff5dd12 (diff)
downloadopenbsd-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.c38
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
288err: 287err:
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