[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: [Nbd] TLS implementation in reference nbd-server



On 10/12/2016 01:40 PM, Wouter Verhelst wrote:
> Hi,
> 
> While stuck in an airport on a 9-hour layover two days ago, I (finally)
> spent some time working on a STARTTLS implementation for the reference
> nbd-server implementation. Configuration is fairly basic; just add a
> "tlsdir = " configuration item to the nbd-server config file, create a
> ca.pem, priv.pem, and cert.pem file in that location, and you're good.
> The current implementation doesn't allow for authenticating clients
> through certificates or other means; I will probably want to add that at
> some point in the future, but not just yet.
> 
> It's not been tested yet, however, because the client side hasn't been
> done yet.

It has at least one bug, from what I've quickly seen.  You HAVE to parse
off length and any data the client sends before you can try to read the
next option; you have this bug in multiple places.  And I would know,
because I had to fix the same bug in both qemu-nbd and in nbd-kit; it
matters when talking with a client that wants to use NBD_OPT_GO.
Something like the following (untested) patch is needed (Untested
because I can't get past autoreconf at the moment; see other thread...):


diff --git i/nbd-server.c w/nbd-server.c
index 25c335b..f394690 100644
--- i/nbd-server.c
+++ w/nbd-server.c
@@ -352,8 +352,14 @@ static void socket_write_tls(CLIENT* client, void
*buf, size_t len) {
 }

 static void socket_read(CLIENT* client, void *buf, size_t len) {
+	void *tmp = NULL;
+	if (!buf) {
+		/* FIXME: Enforce maximum bound on client-provided len? */
+		tmp = buf = malloc(len);
+	}
 	g_assert(client->socket_read != NULL);
 	client->socket_read(client, buf, len);
+	free(tmp);
 }

 /**
@@ -1457,6 +1463,7 @@ CLIENT* negotiate(int net, GArray* servers, const
gchar* tlsdir) {
 	uint64_t magic;
 	uint32_t cflags = 0;
 	uint32_t opt;
+	uint32_t len;
 	CLIENT* client = g_new0(CLIENT, 1);
 	client->net = net;
 	client->socket_read = socket_read_notls;
@@ -1491,6 +1498,11 @@ CLIENT* negotiate(int net, GArray* servers, const
gchar* tlsdir) {
 				// so must do hard close
 				goto hard_close;
 			}
+			socket_read(client, &len, sizeof(len));
+			len = ntohl(len);
+			if(len) {
+				socket_read(client, NULL, len);
+			}
 			send_reply(client, opt, NBD_REP_ERR_TLS_REQD, -1, "TLS is required
on this server");
 			continue;
 		}
@@ -1514,16 +1526,32 @@ CLIENT* negotiate(int net, GArray* servers,
const gchar* tlsdir) {
 		case NBD_OPT_STARTTLS:
 			if(client->tls_session != NULL) {
 				send_reply(client, opt, NBD_REP_ERR_INVALID, -1, "Invalid STARTTLS
request: TLS has already been negotiated!");
+				socket_read(client, &len, sizeof(len));
+				len = ntohl(len);
+				if(len) {
+					socket_read(client, NULL, len);
+				}
 				continue;
 			}
 			if(tlsdir == NULL) {
 				send_reply(client, opt, NBD_REP_ERR_POLICY, -1, "TLS not allowed on
this server");
+				socket_read(client, &len, sizeof(len));
+				len = ntohl(len);
+				if(len) {
+					socket_read(client, NULL, len);
+				}
+				continue;
 			}
 			if(handle_starttls(client, opt, servers, cflags, tlsdir) == NULL) {
 				// can't recover from failed TLS negotiation.
 				goto hard_close;
 			}
 		default:
+			socket_read(client, &len, sizeof(len));
+			len = ntohl(len);
+			if(len) {
+				socket_read(client, NULL, len);
+			}
 			send_reply(client, opt, NBD_REP_ERR_UNSUP, -1, "The given option is
unknown to this server implementation");
 			break;
 		}

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org

Attachment: signature.asc
Description: OpenPGP digital signature


Reply to: