浏览代码

tls: fix wrong wbio usage

The openssl library sometimes (after write operations) sets a
buffering bio "over" the wbio that we set. In this case one can no
longer rely on the wbio returned by SSL_get_wbio() (it might be the
buffering bio).
Now the BIOs are set at connection initialization time (and not on
their first use) and are stored inside the tls_extra_data
structure attached to the tcp connection. This way we are sure we
are always controlling our wbio and not something that openssl
might have stacked on top of it.
Andrei Pelinescu-Onciul 15 年之前
父节点
当前提交
01c803a6c0
共有 3 个文件被更改,包括 24 次插入29 次删除
  1. 3 2
      modules/tls/tls_bio.c
  2. 18 27
      modules/tls/tls_server.c
  3. 3 0
      modules/tls/tls_server.h

+ 3 - 2
modules/tls/tls_bio.c

@@ -115,7 +115,7 @@ int tls_BIO_mbuf_set(BIO* b, struct tls_mbuf* rd, struct tls_mbuf* wr)
 {
 {
 	struct tls_bio_mbuf_data* d;
 	struct tls_bio_mbuf_data* d;
 	
 	
-	TLS_BIO_DBG("tls_BIO_muf_set called (%p, %p)\n", rd, wr);
+	TLS_BIO_DBG("tls_BIO_mbuf_set called (%p => %p, %p)\n", b, rd, wr);
 	if (unlikely(b->ptr == 0)){
 	if (unlikely(b->ptr == 0)){
 		BUG("null BIO ptr\n");
 		BUG("null BIO ptr\n");
 		return 0;
 		return 0;
@@ -195,7 +195,8 @@ static int tls_bio_mbuf_read(BIO* b, char* dst, int dst_len)
 				   as a shortcut when no data is available =>
 				   as a shortcut when no data is available =>
 				   simulate EAGIAN/WANT_READ */
 				   simulate EAGIAN/WANT_READ */
 				TLS_BIO_DBG("read (%p, %p, %d) called with null read buffer"
 				TLS_BIO_DBG("read (%p, %p, %d) called with null read buffer"
-						" => simulating EAGAIN/WANT_READ\n", b, dst, dst_len);
+						"(%p->%p) => simulating EAGAIN/WANT_READ\n",
+						b, dst, dst_len, d, d->rd);
 				BIO_set_retry_read(b);
 				BIO_set_retry_read(b);
 			}
 			}
 			return -1;
 			return -1;

+ 18 - 27
modules/tls/tls_server.c

@@ -126,11 +126,16 @@ static int tls_complete_init(struct tcp_connection* c)
 	}
 	}
 	memset(data, '\0', sizeof(struct tls_extra_data));
 	memset(data, '\0', sizeof(struct tls_extra_data));
 	data->ssl = SSL_new(dom->ctx[process_no]);
 	data->ssl = SSL_new(dom->ctx[process_no]);
+	data->rwbio = tls_BIO_new_mbuf(0, 0);
 	data->cfg = cfg;
 	data->cfg = cfg;
 	data->state = state;
 	data->state = state;
 
 
-	if (data->ssl == 0) {
-		TLS_ERR("Failed to create SSL structure:");
+	if (unlikely(data->ssl == 0 || data->rwbio == 0)) {
+		TLS_ERR("Failed to create SSL or BIO structure:");
+		if (data->ssl)
+			SSL_free(data->ssl);
+		if (data->rwbio)
+			BIO_free(data->rwbio);
 		goto error;
 		goto error;
 	}
 	}
 #ifdef TLS_KSSL_WORKARROUND
 #ifdef TLS_KSSL_WORKARROUND
@@ -140,6 +145,7 @@ static int tls_complete_init(struct tcp_connection* c)
 		data->ssl->kssl_ctx=0;
 		data->ssl->kssl_ctx=0;
 	}
 	}
 #endif
 #endif
+	SSL_set_bio(data->ssl, data->rwbio, data->rwbio);
 	c->extra_data = data;
 	c->extra_data = data;
 	return 0;
 	return 0;
 
 
@@ -182,25 +188,9 @@ static int tls_set_mbufs(struct tcp_connection *c,
 							struct tls_mbuf* rd,
 							struct tls_mbuf* rd,
 							struct tls_mbuf* wr)
 							struct tls_mbuf* wr)
 {
 {
-	SSL *ssl;
 	BIO *rwbio;
 	BIO *rwbio;
 	
 	
-	/* if (unlikely(tls_fix_connection(c) < 0))
-		return -1;
-	*/
-	
-	ssl = ((struct tls_extra_data*)c->extra_data)->ssl;
-	if (unlikely(((rwbio=SSL_get_rbio(ssl))==0) ||
-					((rwbio=SSL_get_wbio(ssl))==0))) {
-		rwbio = tls_BIO_new_mbuf(rd, wr);
-		if (unlikely(rwbio == 0)) {
-			ERR("new mbuf BIO creation failure\n");
-			return -1;
-		}
-		/* use the same bio for both read & write */
-		SSL_set_bio(ssl, rwbio, rwbio);
-		return 0;
-	}
+	rwbio = ((struct tls_extra_data*)c->extra_data)->rwbio;
 	if (unlikely(tls_BIO_mbuf_set(rwbio, rd, wr)<=0)) {
 	if (unlikely(tls_BIO_mbuf_set(rwbio, rd, wr)<=0)) {
 		/* it should be always 1 */
 		/* it should be always 1 */
 		ERR("failed to set mbufs");
 		ERR("failed to set mbufs");
@@ -875,7 +865,7 @@ redo_read:
 	*/
 	*/
 	if (unlikely(tls_c->enc_rd_buf)) {
 	if (unlikely(tls_c->enc_rd_buf)) {
 		/* use queued data */
 		/* use queued data */
-		/* safe to use without locks, because only read changes it and 
+		/* safe to use without locks, because only read changes it and
 		   there can't be parallel reads on the same connection */
 		   there can't be parallel reads on the same connection */
 		enc_rd_buf = tls_c->enc_rd_buf;
 		enc_rd_buf = tls_c->enc_rd_buf;
 		tls_c->enc_rd_buf = 0;
 		tls_c->enc_rd_buf = 0;
@@ -980,8 +970,8 @@ ssl_read_skipped:
 				goto error_send;
 				goto error_send;
 			}
 			}
 		}
 		}
-		/* quickly catch bugs: segfault if accessed and not set */
-		tls_set_mbufs(c, 0, 0);
+	/* quickly catch bugs: segfault if accessed and not set */
+	tls_set_mbufs(c, 0, 0);
 	lock_release(&c->write_lock);
 	lock_release(&c->write_lock);
 	switch(ssl_error) {
 	switch(ssl_error) {
 		case SSL_ERROR_NONE:
 		case SSL_ERROR_NONE:
@@ -1027,11 +1017,12 @@ ssl_read_skipped:
 		if (unlikely(n < 0))
 		if (unlikely(n < 0))
 			/* here n should always be >= 0 */
 			/* here n should always be >= 0 */
 			BUG("unexpected value (n = %d)\n", n);
 			BUG("unexpected value (n = %d)\n", n);
-		else if (unlikely(n < bytes_free))
-			BUG("read buffer not exhausted (rbio still has %d bytes,"
-					"last SSL_read %d / %d)\n",
-					rd.used - rd.pos, n, bytes_free);
-		else if (n == bytes_free) {
+		else {
+			if (unlikely(n < bytes_free))
+				BUG("read buffer not exhausted (rbio still has %d bytes,"
+						"last SSL_read %d / %d)\n",
+						rd.used - rd.pos, n, bytes_free);
+			/* n <= bytes_free */
 			/*  queue read data if not fully consumed by SSL_read()
 			/*  queue read data if not fully consumed by SSL_read()
 			 * (very unlikely situation)
 			 * (very unlikely situation)
 			 */
 			 */

+ 3 - 0
modules/tls/tls_server.h

@@ -55,6 +55,9 @@ struct tls_rd_buf {
 struct tls_extra_data {
 struct tls_extra_data {
 	tls_domains_cfg_t* cfg; /* Configuration used for this connection */
 	tls_domains_cfg_t* cfg; /* Configuration used for this connection */
 	SSL* ssl;               /* SSL context used for the connection */
 	SSL* ssl;               /* SSL context used for the connection */
+	BIO* rwbio;             /* bio used for read/write
+							   (openssl code might add buffering BIOs so
+							    it's better to remember our original BIO) */
 	tls_ct_q* ct_wq;
 	tls_ct_q* ct_wq;
 	struct tls_rd_buf* enc_rd_buf;
 	struct tls_rd_buf* enc_rd_buf;
 	unsigned int flags;
 	unsigned int flags;