Import dhcpcd-6.4.6 with the following changes:

*  Detect removal of IPv6 routes
  *  Don't add link-local addresses to POINTOPOINT interfaces
  *  Don't discard expired DHCPv6 leases when dumping them
  *  If a DHCPv6 lease has no timers, expire it right away
  *  Report delegated addresses
  *  Call dhcpcd-run-hooks correctly when delegated prefixes already exist
  *  Fix a memory error when ia_* config exists but IPv6 is disabled
  *  Ensure servername and bootfile are safely exported
  *  Sanitise the following characters using svis(3) with VIS_CTYLE and
     VIS_OCTAL:
         | ^ & ; < > ( ) $ ` \ " ' <tab> <newline>
     This allows a non buggy unvis(1) to decode it 100% and stays compatible
     with how dhcpcd used to handle encoding on most platforms.
     For systems that supply svis(3) there is a code reduction, for systems
     that do not, a slight code increase. This change mitigates systems
     affected by bash CVE-2014-6271 and CVE-2014-7169.
This commit is contained in:
roy 2014-09-27 01:14:51 +00:00
parent 566336d596
commit 83f33c897c
6 changed files with 148 additions and 75 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: config.h,v 1.1.1.26 2014/06/14 20:51:06 roy Exp $ */
/* $NetBSD: config.h,v 1.1.1.27 2014/09/27 01:14:55 roy Exp $ */
/* netbsd */
#define SYSCONFDIR "/etc"
@ -7,6 +7,7 @@
#define LIBEXECDIR "/libexec"
#define DBDIR "/var/db"
#define RUNDIR "/var/run"
#define HAVE_VIS_H
#define HAVE_SPAWN_H
#define HAVE_MD5_H
#define SHA2_H <sha2.h>

View File

@ -1,4 +1,4 @@
/* $NetBSD: defs.h,v 1.1.1.43 2014/09/18 20:43:58 roy Exp $ */
/* $NetBSD: defs.h,v 1.1.1.44 2014/09/27 01:14:55 roy Exp $ */
/*
* dhcpcd - DHCP client daemon
@ -30,7 +30,7 @@
#define CONFIG_H
#define PACKAGE "dhcpcd"
#define VERSION "6.4.5"
#define VERSION "6.4.6"
#ifndef CONFIG
# define CONFIG SYSCONFDIR "/" PACKAGE ".conf"

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: dhcp-common.c,v 1.1.1.8 2014/09/16 22:23:18 roy Exp $");
__RCSID("$NetBSD: dhcp-common.c,v 1.1.1.9 2014/09/27 01:14:51 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -39,6 +39,11 @@
#include <unistd.h>
#include "config.h"
#ifdef HAVE_VIS_H
#include <vis.h>
#endif
#include "common.h"
#include "dhcp-common.h"
#include "dhcp.h"
@ -294,14 +299,28 @@ decode_rfc3397(char *out, size_t len, const uint8_t *p, size_t pl)
return (ssize_t)count;
}
/*
* Escape these characters to avoid any nastiness passing to a POSIX shell.
* See IEEE Std 1003.1, 2004 Shell Command Language, 2.2 Quoting
* space is not escaped.
*/
#define ESCAPE_CHARS "|&;<>()$`\\\"'\t\n"
/*
* Prints a chunk of data to a string.
* Escapes some characters defnined above to try and avoid any loopholes
* in the shell we're passing to.
* Any non visible characters are escaped as an octal number.
*/
ssize_t
print_string(char *s, size_t len, const uint8_t *data, size_t dl)
{
uint8_t c;
const uint8_t *e, *p;
ssize_t bytes = 0;
ssize_t r;
size_t bytes;
char v[5], *vp, *ve;
bytes = 0;
e = data + dl;
while (data < e) {
c = *data++;
@ -313,51 +332,25 @@ print_string(char *s, size_t len, const uint8_t *data, size_t dl)
if (p == e)
break;
}
if (!isascii(c) || !isprint(c)) {
if (s) {
if (len < 5) {
errno = ENOBUFS;
return -1;
}
r = snprintf(s, len, "\\%03o", c);
len -= (size_t)r;
bytes += r;
s += r;
} else
bytes += 4;
continue;
}
switch (c) {
case '"': /* FALLTHROUGH */
case '\'': /* FALLTHROUGH */
case '$': /* FALLTHROUGH */
case '`': /* FALLTHROUGH */
case '\\': /* FALLTHROUGH */
case '|': /* FALLTHROUGH */
case '&':
if (s) {
if (len < 3) {
errno = ENOBUFS;
return -1;
}
*s++ = '\\';
len--;
}
bytes++;
break;
ve = svis(v, c, VIS_CSTYLE | VIS_OCTAL,
data <= e ? *data : 0, ESCAPE_CHARS);
if (s && len < (size_t)(ve - v) + 1) {
errno = ENOBUFS;
return -1;
}
bytes += (size_t)(ve - v);
if (s) {
*s++ = (char)c;
len--;
vp = v;
while (vp != ve)
*s++ = *vp++;
}
bytes++;
}
/* NULL */
if (s)
*s = '\0';
bytes++;
return bytes;
return (ssize_t)bytes;
}
#define ADDRSZ 4

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: dhcp6.c,v 1.1.1.15 2014/09/18 20:43:56 roy Exp $");
__RCSID("$NetBSD: dhcp6.c,v 1.1.1.16 2014/09/27 01:14:55 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -1171,7 +1171,7 @@ dhcp6_dadcompleted(const struct interface *ifp)
TAILQ_FOREACH(ap, &state->addrs, next) {
if (ap->flags & IPV6_AF_ADDED &&
!(ap->flags & IPV6_AF_DADCOMPLETED))
return 0;
return 0;
}
return 1;
}
@ -1494,7 +1494,7 @@ dhcp6_startexpire(void *arg)
dhcp6_freedrop_addrs(ifp, 1, NULL);
dhcp6_delete_delegates(ifp);
script_runreason(ifp, "EXPIRE6");
if (ipv6nd_hasradhcp(ifp))
if (ipv6nd_hasradhcp(ifp) || dhcp6_hasprefixdelegation(ifp))
dhcp6_startdiscover(ifp);
else
syslog(LOG_WARNING,
@ -2061,7 +2061,9 @@ dhcp6_readlease(struct interface *ifp)
if (fd == -1)
goto ex;
if (state->expire != ND6_INFINITE_LIFETIME) {
if (!(ifp->ctx->options & DHCPCD_DUMPLEASE) &&
state->expire != ND6_INFINITE_LIFETIME)
{
gettimeofday(&now, NULL);
if ((time_t)state->expire < now.tv_sec - st.st_mtime) {
syslog(LOG_DEBUG,"%s: discarding expired lease",
@ -2218,6 +2220,39 @@ dhcp6_ifdelegateaddr(struct interface *ifp, struct ipv6_addr *prefix,
return a;
}
static void
dhcp6_script_try_run(struct interface *ifp)
{
struct dhcp6_state *state;
struct ipv6_addr *ap;
int completed;
state = D6_STATE(ifp);
if (!TAILQ_FIRST(&state->addrs))
return;
completed = 1;
/* If all addresses have completed DAD run the script */
TAILQ_FOREACH(ap, &state->addrs, next) {
if (ap->flags & IPV6_AF_ONLINK) {
if (!(ap->flags & IPV6_AF_DADCOMPLETED) &&
ipv6_findaddr(ap->iface, &ap->addr))
ap->flags |= IPV6_AF_DADCOMPLETED;
if ((ap->flags & IPV6_AF_DADCOMPLETED) == 0) {
completed = 0;
break;
}
}
}
if (completed) {
script_runreason(ifp, state->reason);
dhcpcd_daemonise(ifp->ctx);
} else
syslog(LOG_DEBUG,
"%s: waiting for DHCPv6 DAD to complete",
ifp->name);
}
static void
dhcp6_delegate_prefix(struct interface *ifp)
{
@ -2317,6 +2352,7 @@ dhcp6_delegate_prefix(struct interface *ifp)
if (k && !carrier_warned) {
ifd_state = D6_STATE(ifd);
ipv6_addaddrs(&ifd_state->addrs);
dhcp6_script_try_run(ifd);
}
}
}
@ -2381,6 +2417,7 @@ dhcp6_find_delegates(struct interface *ifp)
state->state = DH6S_DELEGATED;
ipv6_addaddrs(&state->addrs);
ipv6_buildroutes(ifp->ctx);
dhcp6_script_try_run(ifp);
}
return k;
}
@ -2790,13 +2827,13 @@ recv:
if (state->renew == 0) {
if (state->expire == ND6_INFINITE_LIFETIME)
state->renew = ND6_INFINITE_LIFETIME;
else
else if (state->lowpl != ND6_INFINITE_LIFETIME)
state->renew = (uint32_t)(state->lowpl * 0.5);
}
if (state->rebind == 0) {
if (state->expire == ND6_INFINITE_LIFETIME)
state->rebind = ND6_INFINITE_LIFETIME;
else
else if (state->lowpl != ND6_INFINITE_LIFETIME)
state->rebind = (uint32_t)(state->lowpl * 0.8);
}
break;
@ -2830,7 +2867,7 @@ recv:
if (state->rebind && state->rebind != ND6_INFINITE_LIFETIME)
eloop_timeout_add_sec(ifp->ctx->eloop,
(time_t)state->rebind, dhcp6_startrebind, ifp);
if (state->expire && state->expire != ND6_INFINITE_LIFETIME)
if (state->expire != ND6_INFINITE_LIFETIME)
eloop_timeout_add_sec(ifp->ctx->eloop,
(time_t)state->expire, dhcp6_startexpire, ifp);
@ -2846,29 +2883,12 @@ recv:
"%s: renew in %"PRIu32" seconds,"
" rebind in %"PRIu32" seconds",
ifp->name, state->renew, state->rebind);
else if (state->expire == 0)
syslog(has_new ? LOG_INFO : LOG_DEBUG,
"%s: will expire", ifp->name);
ipv6_buildroutes(ifp->ctx);
dhcp6_writelease(ifp);
len = 1;
/* If all addresses have completed DAD run the script */
TAILQ_FOREACH(ap, &state->addrs, next) {
if (ap->flags & IPV6_AF_ONLINK) {
if (!(ap->flags & IPV6_AF_DADCOMPLETED) &&
ipv6_findaddr(ap->iface, &ap->addr))
ap->flags |= IPV6_AF_DADCOMPLETED;
if ((ap->flags & IPV6_AF_DADCOMPLETED) == 0) {
len = 0;
break;
}
}
}
if (len) {
script_runreason(ifp, state->reason);
dhcpcd_daemonise(ifp->ctx);
} else
syslog(LOG_DEBUG,
"%s: waiting for DHCPv6 DAD to complete",
ifp->name);
dhcp6_script_try_run(ifp);
}
if (ifp->ctx->options & DHCPCD_TEST ||
@ -3253,6 +3273,13 @@ dhcp6_env(char **env, const char *prefix, const struct interface *ifp,
char *pfx;
uint32_t en;
const struct dhcpcd_ctx *ctx;
const struct dhcp6_state *state;
const struct ipv6_addr *ap;
char *v, *val;
n = 0;
if (m == NULL)
goto delegated;
if (len < sizeof(*m)) {
/* Should be impossible with guards at packet in
@ -3261,7 +3288,6 @@ dhcp6_env(char **env, const char *prefix, const struct interface *ifp,
return -1;
}
n = 0;
ifo = ifp->options;
ctx = ifp->ctx;
@ -3344,6 +3370,35 @@ dhcp6_env(char **env, const char *prefix, const struct interface *ifp,
}
free(pfx);
delegated:
/* Needed for Delegated Prefixes */
state = D6_CSTATE(ifp);
i = 0;
TAILQ_FOREACH(ap, &state->addrs, next) {
if (ap->delegating_iface) {
i += strlen(ap->saddr) + 1;
}
}
if (env && i) {
i += strlen(prefix) + strlen("_dhcp6_prefix=");
v = val = env[n] = malloc(i);
if (v == NULL) {
syslog(LOG_ERR, "%s: %m", __func__);
return -1;
}
v += snprintf(val, i, "%s_dhcp6_prefix=", prefix);
TAILQ_FOREACH(ap, &state->addrs, next) {
if (ap->delegating_iface) {
strcpy(v, ap->saddr);
v += strlen(ap->saddr);
*v++ = ' ';
}
}
*--v = '\0';
}
if (i)
n++;
return (ssize_t)n;
}

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: ipv6.c,v 1.1.1.12 2014/09/16 22:23:19 roy Exp $");
__RCSID("$NetBSD: ipv6.c,v 1.1.1.13 2014/09/27 01:14:54 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -999,6 +999,11 @@ ipv6_start(struct interface *ifp)
const struct ipv6_state *state;
const struct ipv6_addr *ap;
/* We can't assign a link-locak address to this,
* the ppp process has to. */
if (ifp->flags & IFF_POINTOPOINT)
return 0;
state = IPV6_CSTATE(ifp);
if (state) {
TAILQ_FOREACH(ap, &state->addrs, next) {
@ -1100,7 +1105,8 @@ find_route6(struct rt6_head *rts, const struct rt6 *r)
TAILQ_FOREACH(rt, rts, next) {
if (IN6_ARE_ADDR_EQUAL(&rt->dest, &r->dest) &&
#if HAVE_ROUTE_METRIC
rt->iface->metric == r->iface->metric &&
(r->iface == NULL || rt->iface == NULL ||
rt->iface->metric == r->iface->metric) &&
#endif
IN6_ARE_ADDR_EQUAL(&rt->net, &r->net))
return rt;
@ -1113,8 +1119,9 @@ desc_route(const char *cmd, const struct rt6 *rt)
{
char destbuf[INET6_ADDRSTRLEN];
char gatebuf[INET6_ADDRSTRLEN];
const char *ifname = rt->iface->name, *dest, *gate;
const char *ifname, *dest, *gate;
ifname = rt->iface ? rt->iface->name : "(no iface)";
dest = inet_ntop(AF_INET6, &rt->dest, destbuf, INET6_ADDRSTRLEN);
gate = inet_ntop(AF_INET6, &rt->gate, gatebuf, INET6_ADDRSTRLEN);
if (IN6_ARE_ADDR_EQUAL(&rt->gate, &in6addr_any))
@ -1130,6 +1137,22 @@ desc_route(const char *cmd, const struct rt6 *rt)
dest, ipv6_prefixlen(&rt->net), gate);
}
/* If something other than dhcpcd removes a route,
* we need to remove it from our internal table. */
int
ipv6_routedeleted(struct dhcpcd_ctx *ctx, const struct rt6 *rt)
{
struct rt6 *f;
f = find_route6(ctx->ipv6->routes, rt);
if (f == NULL)
return 0;
desc_route("removing", f);
TAILQ_REMOVE(ctx->ipv6->routes, f, next);
free(f);
return 1;
}
#define n_route(a) nc_route(1, a, a)
#define c_route(a, b) nc_route(0, a, b)
static int

View File

@ -1,4 +1,4 @@
/* $NetBSD: ipv6.h,v 1.1.1.11 2014/09/18 20:43:58 roy Exp $ */
/* $NetBSD: ipv6.h,v 1.1.1.12 2014/09/27 01:14:55 roy Exp $ */
/*
* dhcpcd - DHCP client daemon
@ -201,6 +201,7 @@ void ipv6_free_ll_callbacks(struct interface *);
int ipv6_start(struct interface *);
void ipv6_free(struct interface *);
void ipv6_ctxfree(struct dhcpcd_ctx *);
int ipv6_routedeleted(struct dhcpcd_ctx *, const struct rt6 *);
int ipv6_removesubnet(struct interface *, struct ipv6_addr *);
void ipv6_buildroutes(struct dhcpcd_ctx *);