diff --git a/debian/changelog b/debian/changelog index 93529d1..9cb7818 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +tinc (1.0.31-1+deb9u1) stretch-security; urgency=high + + * Prevent oracle attacks (CVE-2018-16737, CVE-2018-16738). + * Prevent a MITM from forcing a NULL cipher for UDP (CVE-2018-16758). + + -- Guus Sliepen Sat, 22 Sep 2018 17:35:50 +0200 + tinc (1.0.31-1) unstable; urgency=medium * New upstream release. diff --git a/debian/patches/security-fixes b/debian/patches/security-fixes new file mode 100644 index 0000000..99d07b7 --- /dev/null +++ b/debian/patches/security-fixes @@ -0,0 +1,234 @@ +--- a/src/connection.h ++++ b/src/connection.h +@@ -42,7 +42,8 @@ + unsigned int decryptin:1; /* 1 if we have to decrypt incoming traffic */ + unsigned int mst:1; /* 1 if this connection is part of a minimum spanning tree */ + unsigned int proxy_passed:1; /* 1 if we are connecting via a proxy and we have finished talking with it */ +- unsigned int unused:22; ++ unsigned int tarpit:1; /* 1 if the connection should be added to the tarpit */ ++ unsigned int unused:21; + } connection_status_t; + + #include "edge.h" +--- a/src/net.c ++++ b/src/net.c +@@ -158,6 +158,22 @@ + return max; + } + ++/* Put a misbehaving connection in the tarpit */ ++void tarpit(int fd) { ++ static int pits[10] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; ++ static int next_pit = 0; ++ ++ if(pits[next_pit] != -1) { ++ closesocket(pits[next_pit]); ++ } ++ ++ pits[next_pit++] = fd; ++ ++ if(next_pit >= sizeof pits / sizeof pits[0]) { ++ next_pit = 0; ++ } ++} ++ + /* + Terminate a connection: + - Close the socket +@@ -178,8 +194,13 @@ + if(c->node) + c->node->connection = NULL; + +- if(c->socket) +- closesocket(c->socket); ++ if(c->socket) { ++ if(c->status.tarpit) { ++ tarpit(c->socket); ++ } else { ++ closesocket(c->socket); ++ } ++ } + + if(c->edge) { + if(!c->node) { +@@ -266,6 +287,7 @@ + closesocket(c->socket); + do_outgoing_connection(c); + } else { ++ c->status.tarpit = true; + terminate_connection(c, false); + } + } +@@ -345,6 +367,7 @@ + + if(FD_ISSET(c->socket, readset)) { + if(!receive_meta(c)) { ++ c->status.tarpit = true; + terminate_connection(c, c->status.active); + continue; + } +--- a/src/net.h ++++ b/src/net.h +@@ -150,6 +150,7 @@ + extern bool read_rsa_public_key(struct connection_t *); + extern void send_mtu_probe(struct node_t *); + extern void load_all_subnets(void); ++extern void tarpit(int fd); + + #ifndef HAVE_MINGW + #define closesocket(s) close(s) +--- a/src/net_socket.c ++++ b/src/net_socket.c +@@ -552,6 +552,9 @@ + new connection + */ + bool handle_new_meta_connection(int sock) { ++ static const int max_accept_burst = 10; ++ static int last_accept_burst; ++ static int last_accept_time; + connection_t *c; + sockaddr_t sa; + int fd; +@@ -564,6 +567,22 @@ + return false; + } + ++ if(last_accept_time == now) { ++ last_accept_burst++; ++ ++ if(last_accept_burst >= max_accept_burst) { ++ if(last_accept_burst == max_accept_burst) { ++ ifdebug(CONNECTIONS) logger(LOG_WARNING, "Throttling incoming connections"); ++ } ++ ++ tarpit(fd); ++ return false; ++ } ++ } else { ++ last_accept_burst = 0; ++ last_accept_time = now; ++ } ++ + sockaddrunmap(&sa); + + c = new_connection(); +@@ -585,7 +604,6 @@ + connection_add(c); + + c->allow_request = ID; +- send_id(c); + + return true; + } +--- a/src/protocol_auth.c ++++ b/src/protocol_auth.c +@@ -59,7 +59,7 @@ + + /* Check if identity is a valid name */ + +- if(!check_id(name)) { ++ if(!check_id(name) || !strcmp(name, myself->name)) { + logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ID", c->name, + c->hostname, "invalid name"); + return false; +@@ -91,6 +91,11 @@ + if(!c->config_tree) + init_configuration(&c->config_tree); + c->allow_request = ACK; ++ ++ if(!c->outgoing) { ++ send_id(c); ++ } ++ + return send_ack(c); + } + +@@ -110,6 +115,10 @@ + + c->allow_request = METAKEY; + ++ if(!c->outgoing) { ++ send_id(c); ++ } ++ + return send_metakey(c); + } + +@@ -292,7 +301,8 @@ + c->inbudget = byte_budget(c->incipher); + c->status.decryptin = true; + } else { +- c->incipher = NULL; ++ logger(LOG_ERR, "%s (%s) uses null cipher!", c->name, c->hostname); ++ return false; + } + + c->inmaclength = maclength; +@@ -310,7 +320,8 @@ + return false; + } + } else { +- c->indigest = NULL; ++ logger(LOG_ERR, "%s (%s) uses null digest!", c->name, c->hostname); ++ return false; + } + + c->incompression = compression; +@@ -384,7 +395,11 @@ + + /* Rest is done by send_chal_reply() */ + +- return send_chal_reply(c); ++ if(c->outgoing) { ++ return send_chal_reply(c); ++ } else { ++ return true; ++ } + } + + bool send_chal_reply(connection_t *c) { +@@ -482,6 +497,10 @@ + + c->allow_request = ACK; + ++ if(!c->outgoing) { ++ send_chal_reply(c); ++ } ++ + return send_ack(c); + } + +--- a/src/protocol_edge.c ++++ b/src/protocol_edge.c +@@ -70,7 +70,7 @@ + + /* Check if names are valid */ + +- if(!check_id(from_name) || !check_id(to_name)) { ++ if(!check_id(from_name) || !check_id(to_name) || !strcmp(from_name, to_name)) { + logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ADD_EDGE", c->name, + c->hostname, "invalid name"); + return false; +@@ -192,7 +192,7 @@ + + /* Check if names are valid */ + +- if(!check_id(from_name) || !check_id(to_name)) { ++ if(!check_id(from_name) || !check_id(to_name) || !strcmp(from_name, to_name)) { + logger(LOG_ERR, "Got bad %s from %s (%s): %s", "DEL_EDGE", c->name, + c->hostname, "invalid name"); + return false; +--- a/src/protocol_key.c ++++ b/src/protocol_key.c +@@ -274,6 +274,11 @@ + return true; + } + } else { ++ if(from->outkeylength != 1) { ++ logger(LOG_ERR, "Node %s (%s) uses wrong keylength!", from->name, from->hostname); ++ return true; ++ } ++ + from->outcipher = NULL; + } + diff --git a/debian/patches/series b/debian/patches/series index e69de29..a9c233b 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -0,0 +1 @@ +security-fixes