untrusted comment: signature from openbsd 5.7 base secret key
RWSvUZXnw9gUb305RQbAZ3BNddG21lovpLcx/MxcRtwVkmTLMM3EO5tS5H8DVYUocvaFTDE31T/Ff2DeJJEaP/3qH88rtEaL+ww=
OpenBSD 5.7 errata 15, Sept 28, 2015:
Various problems were identified in relayd and merged back from
current to 5.7 in this maintanance update.
Apply by doing:
signify -Vep /etc/signify/openbsd-57-base.pub -x 015_relayd.patch.sig \
-m - | (cd /usr/src && patch -p0)
And then rebuild and install the patch utility:
cd /usr/src/usr.sbin/relayd
make obj
make depend
make
make install
Index: usr.sbin/relayd/ca.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/ca.c,v
retrieving revision 1.12
diff -u -p -r1.12 ca.c
--- usr.sbin/relayd/ca.c 22 Jan 2015 17:42:09 -0000 1.12
+++ usr.sbin/relayd/ca.c 28 Sep 2015 17:43:06 -0000
@@ -417,11 +417,14 @@ rsae_keygen(RSA *rsa, int bits, BIGNUM *
void
ca_engine_init(struct relayd *x_env)
{
- ENGINE *e;
+ ENGINE *e = NULL;
const char *errstr, *name;
if (env == NULL)
env = x_env;
+
+ if (rsa_default != NULL)
+ return;
if ((e = ENGINE_get_default_RSA()) == NULL) {
if ((e = ENGINE_new()) == NULL) {
Index: usr.sbin/relayd/config.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/config.c,v
retrieving revision 1.24
diff -u -p -r1.24 config.c
--- usr.sbin/relayd/config.c 22 Jan 2015 17:42:09 -0000 1.24
+++ usr.sbin/relayd/config.c 28 Sep 2015 17:43:06 -0000
@@ -142,7 +142,7 @@ config_purge(struct relayd *env, u_int r
if (what & CONFIG_TABLES && env->sc_tables != NULL) {
while ((table = TAILQ_FIRST(env->sc_tables)) != NULL)
- purge_table(env->sc_tables, table);
+ purge_table(env, env->sc_tables, table);
env->sc_tablecount = 0;
}
if (what & CONFIG_RDRS && env->sc_rdrs != NULL) {
Index: usr.sbin/relayd/parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/parse.y,v
retrieving revision 1.203
diff -u -p -r1.203 parse.y
--- usr.sbin/relayd/parse.y 8 Feb 2015 04:50:32 -0000 1.203
+++ usr.sbin/relayd/parse.y 28 Sep 2015 17:43:06 -0000
@@ -531,12 +531,12 @@ rdroptsl : forwardmode TO tablespec inte
if ($3->conf.check == CHECK_NOCHECK) {
yyerror("table %s has no check", $3->conf.name);
- purge_table(conf->sc_tables, $3);
+ purge_table(conf, conf->sc_tables, $3);
YYERROR;
}
if (rdr->backup) {
yyerror("only one backup table is allowed");
- purge_table(conf->sc_tables, $3);
+ purge_table(conf, conf->sc_tables, $3);
YYERROR;
}
if (rdr->table) {
@@ -1930,7 +1930,7 @@ routeoptsl : ROUTE address '/' NUMBER {
if (router->rt_gwtable) {
yyerror("router %s table already specified",
router->rt_conf.name);
- purge_table(conf->sc_tables, $3);
+ purge_table(conf, conf->sc_tables, $3);
YYERROR;
}
router->rt_gwtable = $3;
@@ -3091,7 +3091,7 @@ table_inherit(struct table *tb)
goto fail;
}
if ((oldtb = table_findbyconf(conf, tb)) != NULL) {
- purge_table(NULL, tb);
+ purge_table(conf, NULL, tb);
return (oldtb);
}
@@ -3134,7 +3134,7 @@ table_inherit(struct table *tb)
return (tb);
fail:
- purge_table(NULL, tb);
+ purge_table(conf, NULL, tb);
return (NULL);
}
Index: usr.sbin/relayd/pfe.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/pfe.c,v
retrieving revision 1.79
diff -u -p -r1.79 pfe.c
--- usr.sbin/relayd/pfe.c 8 Feb 2015 01:39:06 -0000 1.79
+++ usr.sbin/relayd/pfe.c 28 Sep 2015 17:43:06 -0000
@@ -289,8 +289,11 @@ pfe_dispatch_relay(int fd, struct privse
return (0); /* XXX */
memcpy(s, imsg->data, sizeof(*s));
TAILQ_FOREACH(t, &env->sc_sessions, se_entry) {
- if (t->se_id == s->se_id) /* duplicate registration */
+ /* duplicate registration */
+ if (t->se_id == s->se_id) {
+ free(s);
return (0);
+ }
if (t->se_id > s->se_id)
break;
}
Index: usr.sbin/relayd/relay.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relay.c,v
retrieving revision 1.191
diff -u -p -r1.191 relay.c
--- usr.sbin/relayd/relay.c 6 Feb 2015 01:37:11 -0000 1.191
+++ usr.sbin/relayd/relay.c 28 Sep 2015 17:43:06 -0000
@@ -829,6 +829,12 @@ relay_read(struct bufferevent *bev, void
relay_close(con, strerror(errno));
}
+/*
+ * Splice sockets from cre to cre->dst if applicable. Returns:
+ * -1 socket splicing has failed
+ * 0 socket splicing is currently not possible
+ * 1 socket splicing was successful
+ */
int
relay_splice(struct ctl_relay_event *cre)
{
@@ -878,7 +884,7 @@ relay_splice(struct ctl_relay_event *cre
DPRINTF("%s: session %d: splice dir %d, maximum %lld, successful",
__func__, con->se_id, cre->dir, cre->toread);
- return (0);
+ return (1);
}
int
@@ -988,7 +994,7 @@ relay_error(struct bufferevent *bev, sho
dst = EVBUFFER_OUTPUT(cre->dst->bev);
if (EVBUFFER_LENGTH(dst))
return;
- } else
+ } else if (cre->toread == TOREAD_UNLIMITED || cre->toread == 0)
return;
relay_close(con, "done");
@@ -1041,6 +1047,12 @@ relay_accept(int fd, short event, void *
if ((con = calloc(1, sizeof(*con))) == NULL)
goto err;
+ /* Pre-allocate log buffer */
+ con->se_haslog = 0;
+ con->se_log = evbuffer_new();
+ if (con->se_log == NULL)
+ goto err;
+
con->se_in.s = s;
con->se_in.ssl = NULL;
con->se_out.s = -1;
@@ -1094,14 +1106,6 @@ relay_accept(int fd, short event, void *
return;
}
- /* Pre-allocate log buffer */
- con->se_haslog = 0;
- con->se_log = evbuffer_new();
- if (con->se_log == NULL) {
- relay_close(con, "failed to allocate log buffer");
- return;
- }
-
if (rlay->rl_conf.flags & F_DIVERT) {
slen = sizeof(con->se_out.ss);
if (getsockname(s, (struct sockaddr *)&con->se_out.ss,
@@ -1265,7 +1269,7 @@ relay_from_table(struct rsession *con)
return (-1);
}
host = rlt->rlt_host[idx];
- DPRINTF("%s: session %d: table %s host %s, p 0x%08x, idx %d",
+ DPRINTF("%s: session %d: table %s host %s, p 0x%016llx, idx %d",
__func__, con->se_id, table->conf.name, host->conf.name, p, idx);
while (host != NULL) {
DPRINTF("%s: session %d: host %s", __func__,
@@ -1404,8 +1408,10 @@ relay_connect_retry(int fd, short sig, v
struct relay *rlay = con->se_relay;
int bnds = -1;
- if (relay_inflight < 1)
- fatalx("relay_connect_retry: no connection in flight");
+ if (relay_inflight < 1) {
+ log_warnx("relay_connect_retry: no connection in flight");
+ relay_inflight = 1;
+ }
DPRINTF("%s: retry %d of %d, inflight: %d",__func__,
con->se_retrycount, con->se_retry, relay_inflight);
@@ -1462,6 +1468,10 @@ relay_connect_retry(int fd, short sig, v
return;
}
+ if (rlay->rl_conf.flags & F_TLSINSPECT)
+ con->se_out.state = STATE_PRECONNECT;
+ else
+ con->se_out.state = STATE_CONNECTED;
relay_inflight--;
DPRINTF("%s: inflight decremented, now %d",__func__, relay_inflight);
@@ -1480,9 +1490,14 @@ relay_connect_retry(int fd, short sig, v
int
relay_preconnect(struct rsession *con)
{
+ int rv;
+
log_debug("%s: session %d: process %d", __func__,
con->se_id, privsep_process);
- return (relay_connect(con));
+ rv = relay_connect(con);
+ if (con->se_out.state == STATE_CONNECTED)
+ con->se_out.state = STATE_PRECONNECT;
+ return (rv);
}
int
@@ -1492,18 +1507,28 @@ relay_connect(struct rsession *con)
struct timeval evtpause = { 1, 0 };
int bnds = -1, ret;
+ /* relay_connect should only be called once per relay */
+ if (con->se_out.state == STATE_CONNECTED) {
+ log_debug("%s: connect already called once", __func__);
+ return (0);
+ }
+
/* Connection is already established but session not active */
- if ((rlay->rl_conf.flags & F_TLSINSPECT) && con->se_out.s != -1) {
+ if ((rlay->rl_conf.flags & F_TLSINSPECT) &&
+ con->se_out.state == STATE_PRECONNECT) {
if (con->se_out.ssl == NULL) {
log_debug("%s: tls connect failed", __func__);
return (-1);
}
relay_connected(con->se_out.s, EV_WRITE, con);
+ con->se_out.state = STATE_CONNECTED;
return (0);
}
- if (relay_inflight < 1)
- fatalx("relay_connect: no connection in flight");
+ if (relay_inflight < 1) {
+ log_warnx("relay_connect: no connection in flight");
+ relay_inflight = 1;
+ }
getmonotime(&con->se_tv_start);
@@ -1551,6 +1576,9 @@ relay_connect(struct rsession *con)
event_del(&rlay->rl_ev);
evtimer_add(&con->se_inflightevt, &evtpause);
evtimer_add(&rlay->rl_evt, &evtpause);
+
+ /* this connect is pending */
+ con->se_out.state = STATE_PENDING;
return (0);
} else {
if (con->se_retry) {
@@ -1568,6 +1596,7 @@ relay_connect(struct rsession *con)
}
}
+ con->se_out.state = STATE_CONNECTED;
relay_inflight--;
DPRINTF("%s: inflight decremented, now %d",__func__,
relay_inflight);
@@ -1669,6 +1698,7 @@ relay_close(struct rsession *con, const
event_add(&rlay->rl_ev, NULL);
}
}
+ con->se_out.state = STATE_INIT;
if (con->se_out.buf != NULL)
free(con->se_out.buf);
Index: usr.sbin/relayd/relay_http.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relay_http.c,v
retrieving revision 1.43
diff -u -p -r1.43 relay_http.c
--- usr.sbin/relayd/relay_http.c 22 Jan 2015 17:42:09 -0000 1.43
+++ usr.sbin/relayd/relay_http.c 28 Sep 2015 17:43:06 -0000
@@ -35,6 +35,7 @@
#include <fnmatch.h>
#include <siphash.h>
#include <imsg.h>
+#include <unistd.h>
#include "relayd.h"
#include "http.h"
@@ -146,6 +147,7 @@ relay_httpdesc_free(struct http_descript
desc->query_val = NULL;
}
kv_purge(&desc->http_headers);
+ desc->http_lastheader = NULL;
}
void
@@ -210,7 +212,7 @@ relay_read_http(struct bufferevent *bev,
else
value = strchr(key, ':');
if (value == NULL) {
- if (cre->line == 1) {
+ if (cre->line <= 2) {
free(line);
relay_abort_http(con, 400, "malformed", 0);
return;
@@ -271,8 +273,10 @@ relay_read_http(struct bufferevent *bev,
goto lookup;
} else if (cre->line == 1 && cre->dir == RELAY_DIR_REQUEST) {
if ((desc->http_method = relay_httpmethod_byname(key))
- == HTTP_METHOD_NONE)
+ == HTTP_METHOD_NONE) {
+ free(line);
goto fail;
+ }
/*
* Decode request path and query
*/
@@ -415,7 +419,7 @@ relay_read_http(struct bufferevent *bev,
relay_reset_http(cre);
done:
if (cre->dir == RELAY_DIR_REQUEST && cre->toread <= 0 &&
- cre->dst->bev == NULL) {
+ cre->dst->state != STATE_CONNECTED) {
if (rlay->rl_conf.fwdmode == FWD_TRANS) {
relay_bindanyreq(con, 0, IPPROTO_TCP);
return;
@@ -430,11 +434,18 @@ relay_read_http(struct bufferevent *bev,
relay_close(con, "last http read (done)");
return;
}
+ switch (relay_splice(cre)) {
+ case -1:
+ relay_close(con, strerror(errno));
+ case 1:
+ return;
+ case 0:
+ break;
+ }
+ bufferevent_enable(bev, EV_READ);
if (EVBUFFER_LENGTH(src) && bev->readcb != relay_read_http)
bev->readcb(bev, arg);
- bufferevent_enable(bev, EV_READ);
- if (relay_splice(cre) == -1)
- relay_close(con, strerror(errno));
+ /* The callback readcb() might have freed the session. */
return;
fail:
relay_abort_http(con, 500, strerror(errno), 0);
@@ -484,9 +495,10 @@ relay_read_httpcontent(struct buffereven
}
if (con->se_done)
goto done;
+ bufferevent_enable(bev, EV_READ);
if (bev->readcb != relay_read_httpcontent)
bev->readcb(bev, arg);
- bufferevent_enable(bev, EV_READ);
+ /* The callback readcb() might have freed the session. */
return;
done:
relay_close(con, "last http content read");
@@ -601,9 +613,10 @@ relay_read_httpchunks(struct bufferevent
next:
if (con->se_done)
goto done;
+ bufferevent_enable(bev, EV_READ);
if (EVBUFFER_LENGTH(src))
bev->readcb(bev, arg);
- bufferevent_enable(bev, EV_READ);
+ /* The callback readcb() might have freed the session. */
return;
done:
@@ -1363,7 +1376,7 @@ relay_match_actions(struct ctl_relay_eve
struct kvlist *matches, struct kvlist *actions)
{
struct rsession *con = cre->con;
- struct kv *kv;
+ struct kv *kv, *tmp;
/*
* Apply the following options instantly (action per match).
@@ -1382,7 +1395,7 @@ relay_match_actions(struct ctl_relay_eve
*/
if (matches == NULL) {
/* 'pass' or 'block' rule */
- TAILQ_FOREACH(kv, &rule->rule_kvlist, kv_rule_entry) {
+ TAILQ_FOREACH_SAFE(kv, &rule->rule_kvlist, kv_rule_entry, tmp) {
TAILQ_INSERT_TAIL(actions, kv, kv_action_entry);
TAILQ_REMOVE(&rule->rule_kvlist, kv, kv_rule_entry);
}
Index: usr.sbin/relayd/relayd.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relayd.c,v
retrieving revision 1.138
diff -u -p -r1.138 relayd.c
--- usr.sbin/relayd/relayd.c 22 Jan 2015 17:42:09 -0000 1.138
+++ usr.sbin/relayd/relayd.c 28 Sep 2015 17:43:06 -0000
@@ -546,12 +546,13 @@ parent_dispatch_ca(int fd, struct privse
}
void
-purge_table(struct tablelist *head, struct table *table)
+purge_table(struct relayd *env, struct tablelist *head, struct table *table)
{
struct host *host;
while ((host = TAILQ_FIRST(&table->hosts)) != NULL) {
TAILQ_REMOVE(&table->hosts, host, entry);
+ TAILQ_REMOVE(&env->sc_hosts, host, globalentry);
if (event_initialized(&host->cte.ev)) {
event_del(&host->cte.ev);
close(host->cte.s);
@@ -766,18 +767,13 @@ kv_purge(struct kvtree *keys)
void
kv_free(struct kv *kv)
{
- if (kv->kv_type == KEY_TYPE_NONE)
- return;
- if (kv->kv_key != NULL) {
- free(kv->kv_key);
- }
- kv->kv_key = NULL;
- if (kv->kv_value != NULL) {
- free(kv->kv_value);
- }
- kv->kv_value = NULL;
- kv->kv_matchtree = NULL;
- kv->kv_match = NULL;
+ /*
+ * This function does not clear memory referenced by
+ * kv_children or stuff on the tailqs. Use kv_delete() instead.
+ */
+
+ free(kv->kv_key);
+ free(kv->kv_value);
memset(kv, 0, sizeof(*kv));
}
Index: usr.sbin/relayd/relayd.h
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relayd.h,v
retrieving revision 1.207
diff -u -p -r1.207 relayd.h
--- usr.sbin/relayd/relayd.h 22 Jan 2015 17:42:09 -0000 1.207
+++ usr.sbin/relayd/relayd.h 28 Sep 2015 17:43:06 -0000
@@ -180,6 +180,13 @@ enum tlsreneg_state {
TLSRENEG_ABORT = 3 /* the connection should be aborted */
};
+enum relay_state {
+ STATE_INIT,
+ STATE_PENDING,
+ STATE_PRECONNECT,
+ STATE_CONNECTED
+};
+
struct ctl_relay_event {
int s;
in_port_t port;
@@ -200,6 +207,7 @@ struct ctl_relay_event {
int line;
int done;
int timedout;
+ enum relay_state state;
enum direction dir;
u_int8_t *buf;
@@ -1253,7 +1261,8 @@ struct ca_pkey *pkey_add(struct relayd *
int expand_string(char *, size_t, const char *, const char *);
void translate_string(char *);
void purge_key(char **, off_t);
-void purge_table(struct tablelist *, struct table *);
+void purge_table(struct relayd *, struct tablelist *,
+ struct table *);
void purge_relay(struct relayd *, struct relay *);
char *digeststr(enum digest_type, const u_int8_t *, size_t, char *);
const char *canonicalize_host(const char *, char *, size_t);
Index: usr.sbin/relayd/ssl.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/ssl.c,v
retrieving revision 1.28
diff -u -p -r1.28 ssl.c
--- usr.sbin/relayd/ssl.c 22 Jan 2015 17:42:09 -0000 1.28
+++ usr.sbin/relayd/ssl.c 28 Sep 2015 17:43:06 -0000
@@ -454,6 +454,7 @@ ssl_load_pkey(const void *data, size_t d
EVP_PKEY_free(pkey);
if (x509 != NULL)
X509_free(x509);
+ free(exdata);
return (0);
}