diff options
author | Matt Caswell <matt@openssl.org> | 2016-07-21 12:17:29 +0100 |
---|---|---|
committer | Matt Caswell <matt@openssl.org> | 2016-07-29 14:09:57 +0100 |
commit | 65e2d672548e7c4bcb28f1c5c835362830b1745b (patch) | |
tree | 6d87e72458317ce13c8f54aebd368b9965619525 /ssl/ssl_lib.c | |
parent | 9a7169870e803bdd9767d75ca8f64802ca0e7f1c (diff) |
Simplify and rename SSL_set_rbio() and SSL_set_wbio()
SSL_set_rbio() and SSL_set_wbio() are new functions in 1.1.0 and really
should be called SSL_set0_rbio() and SSL_set0_wbio(). The old
implementation was not consistent with what "set0" means though as there
were special cases around what happens if the rbio and wbio are the same.
We were only ever taking one reference on the BIO, and checking everywhere
whether the rbio and wbio are the same so as not to double free.
A better approach is to rename the functions to SSL_set0_rbio() and
SSL_set0_wbio(). If an existing BIO is present it is *always* freed
regardless of whether the rbio and wbio are the same or not. It is
therefore the callers responsibility to ensure that a reference is taken
for *each* usage, i.e. one for the rbio and one for the wbio.
The legacy function SSL_set_bio() takes both the rbio and wbio in one go
and sets them both. We can wrap up the old behaviour in the implementation
of that function, i.e. previously if the rbio and wbio are the same in the
call to this function then the caller only needed to ensure one reference
was passed. This behaviour is retained by internally upping the ref count.
This commit was inspired by BoringSSL commit f715c423224.
RT#4572
Reviewed-by: Rich Salz <rsalz@openssl.org>
Diffstat (limited to 'ssl/ssl_lib.c')
-rw-r--r-- | ssl/ssl_lib.c | 65 |
1 files changed, 50 insertions, 15 deletions
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index c49fc5c704..df71f7b0dc 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -979,8 +979,7 @@ void SSL_free(SSL *s) ssl_free_wbio_buffer(s); - if (s->wbio != s->rbio) - BIO_free_all(s->wbio); + BIO_free_all(s->wbio); BIO_free_all(s->rbio); BUF_MEM_free(s->init_buf); @@ -1043,14 +1042,13 @@ void SSL_free(SSL *s) OPENSSL_free(s); } -void SSL_set_rbio(SSL *s, BIO *rbio) +void SSL_set0_rbio(SSL *s, BIO *rbio) { - if (s->rbio != rbio && s->rbio != s->wbio) - BIO_free_all(s->rbio); + BIO_free_all(s->rbio); s->rbio = rbio; } -void SSL_set_wbio(SSL *s, BIO *wbio) +void SSL_set0_wbio(SSL *s, BIO *wbio) { /* * If the output buffering BIO is still in place, remove it @@ -1058,8 +1056,7 @@ void SSL_set_wbio(SSL *s, BIO *wbio) if (s->bbio != NULL) s->wbio = BIO_pop(s->wbio); - if (s->wbio != wbio && s->rbio != s->wbio) - BIO_free_all(s->wbio); + BIO_free_all(s->wbio); s->wbio = wbio; /* Re-attach |bbio| to the new |wbio|. */ @@ -1069,8 +1066,42 @@ void SSL_set_wbio(SSL *s, BIO *wbio) void SSL_set_bio(SSL *s, BIO *rbio, BIO *wbio) { - SSL_set_wbio(s, wbio); - SSL_set_rbio(s, rbio); + /* + * For historical reasons, this function has many different cases in + * ownership handling. + */ + + /* If nothing has changed, do nothing */ + if (rbio == SSL_get_rbio(s) && wbio == SSL_get_wbio(s)) + return; + + /* + * If the two arguments are equal then one fewer reference is granted by the + * caller than we want to take + */ + if (rbio != NULL && rbio == wbio) + BIO_up_ref(rbio); + + /* + * If only the wbio is changed only adopt one reference. + */ + if (rbio == SSL_get_rbio(s)) { + SSL_set0_wbio(s, wbio); + return; + } + /* + * There is an asymmetry here for historical reasons. If only the rbio is + * changed AND the rbio and wbio were originally different, then we only + * adopt one reference. + */ + if (wbio == SSL_get_wbio(s) && SSL_get_rbio(s) != SSL_get_wbio(s)) { + SSL_set0_rbio(s, rbio); + return; + } + + /* Otherwise, adopt both references. */ + SSL_set0_rbio(s, rbio); + SSL_set0_wbio(s, wbio); } BIO *SSL_get_rbio(const SSL *s) @@ -1151,9 +1182,10 @@ int SSL_set_wfd(SSL *s, int fd) return 0; } BIO_set_fd(bio, fd, BIO_NOCLOSE); - SSL_set_wbio(s, bio); + SSL_set0_wbio(s, bio); } else { - SSL_set_wbio(s, rbio); + BIO_up_ref(rbio); + SSL_set0_wbio(s, rbio); } return 1; } @@ -1171,9 +1203,10 @@ int SSL_set_rfd(SSL *s, int fd) return 0; } BIO_set_fd(bio, fd, BIO_NOCLOSE); - SSL_set_rbio(s, bio); + SSL_set0_rbio(s, bio); } else { - SSL_set_rbio(s, wbio); + BIO_up_ref(wbio); + SSL_set0_rbio(s, wbio); } return 1; @@ -3141,8 +3174,10 @@ SSL *SSL_dup(SSL *s) if (s->wbio != s->rbio) { if (!BIO_dup_state(s->wbio, (char *)&ret->wbio)) goto err; - } else + } else { + BIO_up_ref(ret->rbio); ret->wbio = ret->rbio; + } } ret->server = s->server; |