Import dhcpcd-5.1.12 with the following changes:
* 20-resolv.conf now uses the correct variable for $IF_METRIC * Exclude interface values when dumping the lease * Parse static value subnet_mask when it exists instead of deriving from ip address * logger calls now resemble dhcpcd calls to syslog(3) * Reject offered IP address if INADDR_BROADCAST or INADDR_ANY * Change the route if source address has changed * Note the address we are requesting in the broadcast log entry * When operating on one interface, respect the timeout for in dhcpcd.conf * Escape | and & characters before passing the value to the shell Ensure we set a valid hostname, DNS domain and NIS domain. Document the need for input validation in dhcpcd-run-hooks(8). Fixes CVE-2011-996 Based on a patch to dhcpcd-3 by Marius Tomaschewski <mt@suse.de>
This commit is contained in:
parent
e21f0b912e
commit
a2af890d85
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2008 Roy Marples <roy@marples.name>
|
||||
* Copyright (c) 2006-2011 Roy Marples <roy@marples.name>
|
||||
* All rights reserved
|
||||
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -119,7 +119,7 @@ handle_arp_packet(void *arg)
|
|||
state->fail.s_addr = 0;
|
||||
for(;;) {
|
||||
bytes = get_raw_packet(iface, ETHERTYPE_ARP,
|
||||
arp_buffer, sizeof(arp_buffer));
|
||||
arp_buffer, sizeof(arp_buffer), NULL);
|
||||
if (bytes == 0 || bytes == -1)
|
||||
return;
|
||||
/* We must have a full ARP header */
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2008 Roy Marples <roy@marples.name>
|
||||
* Copyright (c) 2006-2011 Roy Marples <roy@marples.name>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
|
@ -160,7 +160,7 @@ send_raw_packet(const struct interface *iface, int protocol,
|
|||
* So we pass the buffer in the API so we can loop on >1 packet. */
|
||||
ssize_t
|
||||
get_raw_packet(struct interface *iface, int protocol,
|
||||
void *data, ssize_t len)
|
||||
void *data, ssize_t len, int *partialcsum)
|
||||
{
|
||||
int fd = -1;
|
||||
struct bpf_hdr packet;
|
||||
|
@ -172,6 +172,9 @@ get_raw_packet(struct interface *iface, int protocol,
|
|||
else
|
||||
fd = iface->raw_fd;
|
||||
|
||||
if (partialcsum != NULL)
|
||||
*partialcsum = 0; /* Not supported on BSD */
|
||||
|
||||
for (;;) {
|
||||
if (iface->buffer_len == 0) {
|
||||
bytes = read(fd, iface->buffer, iface->buffer_size);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2010 Roy Marples <roy@marples.name>
|
||||
* Copyright (c) 2006-2011 Roy Marples <roy@marples.name>
|
||||
* All rights reserved
|
||||
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -170,8 +170,14 @@ make_env(const struct interface *iface, char ***argv)
|
|||
const struct if_options *ifo = iface->state->options;
|
||||
const struct interface *ifp;
|
||||
|
||||
/* When dumping the lease, we only want to report interface and
|
||||
reason - the other interface variables are meaningless */
|
||||
if (options & DHCPCD_DUMPLEASE)
|
||||
elen = 2;
|
||||
else
|
||||
elen = 8;
|
||||
|
||||
/* Make our env */
|
||||
elen = 8;
|
||||
env = xmalloc(sizeof(char *) * (elen + 1));
|
||||
e = strlen("interface") + strlen(iface->name) + 2;
|
||||
env[0] = xmalloc(e);
|
||||
|
@ -179,7 +185,10 @@ make_env(const struct interface *iface, char ***argv)
|
|||
e = strlen("reason") + strlen(iface->state->reason) + 2;
|
||||
env[1] = xmalloc(e);
|
||||
snprintf(env[1], e, "reason=%s", iface->state->reason);
|
||||
e = 20;
|
||||
if (options & DHCPCD_DUMPLEASE)
|
||||
goto dumplease;
|
||||
|
||||
e = 20;
|
||||
env[2] = xmalloc(e);
|
||||
snprintf(env[2], e, "pid=%d", getpid());
|
||||
env[3] = xmalloc(e);
|
||||
|
@ -237,6 +246,8 @@ make_env(const struct interface *iface, char ***argv)
|
|||
append_config(&env, &elen, "old",
|
||||
(const char *const *)ifo->config);
|
||||
}
|
||||
|
||||
dumplease:
|
||||
if (iface->state->new) {
|
||||
e = configure_env(NULL, NULL, iface->state->new, ifo);
|
||||
if (e > 0) {
|
||||
|
@ -653,9 +664,11 @@ build_routes(void)
|
|||
/* Is this route already in our table? */
|
||||
if ((find_route(nrs, rt, NULL, NULL)) != NULL)
|
||||
continue;
|
||||
rt->src.s_addr = ifp->addr.s_addr;
|
||||
/* Do we already manage it? */
|
||||
if ((or = find_route(routes, rt, &rtl, NULL))) {
|
||||
if (or->iface != ifp ||
|
||||
or->src.s_addr != ifp->addr.s_addr ||
|
||||
rt->gate.s_addr != or->gate.s_addr)
|
||||
{
|
||||
if (c_route(or, rt, ifp) != 0)
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#define CONFIG_H
|
||||
|
||||
#define PACKAGE "dhcpcd"
|
||||
#define VERSION "5.2.11"
|
||||
#define VERSION "5.2.12"
|
||||
|
||||
#ifndef CONFIG
|
||||
# define CONFIG SYSCONFDIR "/" PACKAGE ".conf"
|
||||
|
|
|
@ -1143,7 +1143,9 @@ print_string(char *s, ssize_t len, int dl, const uint8_t *data)
|
|||
case '\'': /* FALLTHROUGH */
|
||||
case '$': /* FALLTHROUGH */
|
||||
case '`': /* FALLTHROUGH */
|
||||
case '\\':
|
||||
case '\\': /* FALLTHROUGH */
|
||||
case '|': /* FALLTHROUGH */
|
||||
case '&':
|
||||
if (s) {
|
||||
if (len < 3) {
|
||||
errno = ENOBUFS;
|
||||
|
|
|
@ -81,20 +81,28 @@ add_resolv_conf()
|
|||
if [ -n "$new_domain_name" ]; then
|
||||
set -- $new_domain_name
|
||||
new_domain_name="$1"
|
||||
conf="${conf}domain $new_domain_name\n"
|
||||
if valid_domainname "$new_domain_name"; then
|
||||
conf="${conf}domain $new_domain_name\n"
|
||||
else
|
||||
syslog err "Invalid domain name: $new_domain_name"
|
||||
fi
|
||||
# Support RFC violating search in domain
|
||||
if [ -z "$new_domain_search" -a -n "$2" ]; then
|
||||
new_domain_search="$@"
|
||||
fi
|
||||
fi
|
||||
if [ -n "$new_domain_search" ]; then
|
||||
conf="${conf}search $new_domain_search\n"
|
||||
if valid_domainname_list; then
|
||||
conf="${conf}search $new_domain_search\n"
|
||||
else
|
||||
syslog err "Invalid domain name in list: $new_domain_search"
|
||||
fi
|
||||
fi
|
||||
for x in ${new_domain_name_servers}; do
|
||||
conf="${conf}nameserver $x\n"
|
||||
done
|
||||
if type resolvconf >/dev/null 2>&1; then
|
||||
[ -n "$metric" ] && export IF_METRIC="$metric"
|
||||
[ -n "$ifmetric" ] && export IF_METRIC="$ifmetric"
|
||||
printf "$conf" | resolvconf -a "$interface"
|
||||
return $?
|
||||
fi
|
||||
|
|
|
@ -18,13 +18,22 @@ need_hostname()
|
|||
esac
|
||||
}
|
||||
|
||||
try_hostname()
|
||||
{
|
||||
if valid_domainname "$1"; then
|
||||
hostname "$1"
|
||||
else
|
||||
syslog err "Invalid hostname: $1"
|
||||
fi
|
||||
}
|
||||
|
||||
set_hostname()
|
||||
{
|
||||
if need_hostname; then
|
||||
if [ -n "$new_host_name" ]; then
|
||||
hostname "$new_host_name"
|
||||
try_hostname "$new_host_name"
|
||||
elif [ -n "$new_fqdn_name" ]; then
|
||||
hostname "$new_fqdn_name"
|
||||
try_hostname "$new_fqdn_name"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
|
|
@ -67,7 +67,11 @@ if [ "$reason" = PREINIT ]; then
|
|||
rm -f "$ypbind_dir/$interface"
|
||||
elif $if_up || $if_down; then
|
||||
if [ -n "$new_nis_domain" ]; then
|
||||
make_yp_binding
|
||||
if valid_domainname "$new_nis_domain"; then
|
||||
make_yp_binding
|
||||
else
|
||||
syslog err "Invalid NIS domain name: $new_nis_domain"
|
||||
fi
|
||||
elif [ -n "$old_nis_domain" ]; then
|
||||
restore_yp_binding
|
||||
fi
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.\" Copyright (c) 2006-2010 Roy Marples
|
||||
.\" Copyright (c) 2006-2011 Roy Marples
|
||||
.\" All rights reserved
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
|
@ -22,7 +22,7 @@
|
|||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd August 24, 2010
|
||||
.Dd March 23, 2011
|
||||
.Dt DHCPCD-RUN-HOOKS 8 SMM
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -135,3 +135,11 @@ in a lexical order and then finally
|
|||
.An Roy Marples Aq roy@marples.name
|
||||
.Sh BUGS
|
||||
Please report them to http://roy.marples.name/projects/dhcpcd
|
||||
.Sh SECURITY CONSIDERATIONS
|
||||
Little validation of DHCP options is done in dhcpcd itself.
|
||||
Instead, it is up to the hooks to handle any validation needed.
|
||||
To this end, some helper functions are provided, such as valid_domainname as
|
||||
used by the
|
||||
.Pa 20-resolv.conf
|
||||
hook to ensure that the hostname is not set to an invalid value.
|
||||
valid_path is also provided, but is currently unused by a stock hook script.
|
||||
|
|
|
@ -142,11 +142,51 @@ syslog()
|
|||
[ -n "$lvl" ] && shift
|
||||
if [ -n "$*" ]; then
|
||||
if type logger >/dev/null 2>&1; then
|
||||
logger -t dhcpcd -p daemon."$lvl" -s "$*"
|
||||
logger -t dhcpcd -p daemon."$lvl" -is "$interface: $*"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Check for a valid domain name as per RFC1123 with the exception of
|
||||
# allowing - and _ as they seem to be widely used.
|
||||
valid_domainname()
|
||||
{
|
||||
local name="$1" label
|
||||
|
||||
[ -z "$name" -o ${#name} -gt 255 ] && return 1
|
||||
|
||||
while [ -n "$name" ]; do
|
||||
label="${name%%.*}"
|
||||
[ -z "$label" -o ${#label} -gt 63 ] && return 1
|
||||
case "$label" in
|
||||
-*|_*|*-|*_) return 1;;
|
||||
*[![:alnum:]-_]*) return 1;;
|
||||
esac
|
||||
[ "$name" = "${name#*.}" ] && break
|
||||
name="${name#*.}"
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
valid_domainname_list()
|
||||
{
|
||||
local name
|
||||
|
||||
for name in $@; do
|
||||
valid_domainname "$name" || return $?
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
# Check for a valid path
|
||||
valid_path()
|
||||
{
|
||||
case "$@" in
|
||||
*[![:alnum:]#%+-_:\.,@~\\/\[\]=\ ]*) return 1;;
|
||||
esac
|
||||
return 0
|
||||
}
|
||||
|
||||
# Check a system service exists
|
||||
service_exists()
|
||||
{
|
||||
|
|
|
@ -528,7 +528,17 @@ handle_dhcp(struct interface *iface, struct dhcp_message **dhcpp, const struct i
|
|||
log_dhcp(LOG_WARNING, "reject DHCP", iface, dhcp, from);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensure that the address offered is valid */
|
||||
if ((type == 0 || type == DHCP_OFFER || type == DHCP_ACK) &&
|
||||
(dhcp->ciaddr == INADDR_ANY || dhcp->ciaddr == INADDR_BROADCAST) &&
|
||||
(dhcp->yiaddr == INADDR_ANY || dhcp->yiaddr == INADDR_BROADCAST))
|
||||
{
|
||||
log_dhcp(LOG_WARNING, "reject invalid address",
|
||||
iface, dhcp, from);
|
||||
return;
|
||||
}
|
||||
|
||||
/* No NAK, so reset the backoff */
|
||||
state->nakoff = 1;
|
||||
|
@ -631,7 +641,7 @@ handle_dhcp_packet(void *arg)
|
|||
const uint8_t *pp;
|
||||
ssize_t bytes;
|
||||
struct in_addr from;
|
||||
int i;
|
||||
int i, partialcsum = 0;
|
||||
|
||||
/* We loop through until our buffer is empty.
|
||||
* The benefit is that if we get >1 DHCP packet in our buffer and
|
||||
|
@ -639,10 +649,10 @@ handle_dhcp_packet(void *arg)
|
|||
packet = xmalloc(udp_dhcp_len);
|
||||
for(;;) {
|
||||
bytes = get_raw_packet(iface, ETHERTYPE_IP,
|
||||
packet, udp_dhcp_len);
|
||||
packet, udp_dhcp_len, &partialcsum);
|
||||
if (bytes == 0 || bytes == -1)
|
||||
break;
|
||||
if (valid_udp_packet(packet, bytes, &from) == -1) {
|
||||
if (valid_udp_packet(packet, bytes, &from, partialcsum) == -1) {
|
||||
syslog(LOG_ERR, "%s: invalid UDP packet from %s",
|
||||
iface->name, inet_ntoa(from));
|
||||
continue;
|
||||
|
@ -919,7 +929,11 @@ start_discover(void *arg)
|
|||
else
|
||||
add_timeout_sec(ifo->timeout, start_ipv4ll, iface);
|
||||
}
|
||||
syslog(LOG_INFO, "%s: broadcasting for a lease", iface->name);
|
||||
if (ifo->options & DHCPCD_REQUEST)
|
||||
syslog(LOG_INFO, "%s: broadcasting for a lease (requesting %s)",
|
||||
iface->name, inet_ntoa(ifo->req_addr));
|
||||
else
|
||||
syslog(LOG_INFO, "%s: broadcasting for a lease", iface->name);
|
||||
send_discover(iface);
|
||||
}
|
||||
|
||||
|
@ -2011,17 +2025,20 @@ main(int argc, char **argv)
|
|||
}
|
||||
}
|
||||
}
|
||||
if (options & DHCPCD_MASTER)
|
||||
i = if_options->timeout;
|
||||
else
|
||||
i = ifaces->state->options->timeout;
|
||||
if (opt == 0 &&
|
||||
options & DHCPCD_LINK &&
|
||||
!(options & DHCPCD_WAITIP))
|
||||
{
|
||||
syslog(LOG_WARNING, "no interfaces have a carrier");
|
||||
daemonise();
|
||||
} else if (if_options->timeout > 0) {
|
||||
} else if (i > 0) {
|
||||
if (options & DHCPCD_IPV4LL)
|
||||
options |= DHCPCD_TIMEOUT_IPV4LL;
|
||||
add_timeout_sec(if_options->timeout,
|
||||
handle_exit_timeout, NULL);
|
||||
add_timeout_sec(i, handle_exit_timeout, NULL);
|
||||
}
|
||||
}
|
||||
free_options(if_options);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2008 Roy Marples <roy@marples.name>
|
||||
* Copyright (c) 2006-2010 Roy Marples <roy@marples.name>
|
||||
* All rights reserved
|
||||
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2008 Roy Marples <roy@marples.name>
|
||||
* Copyright (c) 2006-2010 Roy Marples <roy@marples.name>
|
||||
* All rights reserved
|
||||
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
|
@ -625,11 +625,16 @@ parse_option(struct if_options *ifo, int opt, const char *arg)
|
|||
}
|
||||
p++;
|
||||
if (strncmp(arg, "ip_address=", strlen("ip_address=")) == 0) {
|
||||
if (parse_addr(&ifo->req_addr, &ifo->req_mask, p) != 0)
|
||||
if (parse_addr(&ifo->req_addr,
|
||||
ifo->req_mask.s_addr == 0 ? &ifo->req_mask : NULL,
|
||||
p) != 0)
|
||||
return -1;
|
||||
|
||||
ifo->options |= DHCPCD_STATIC;
|
||||
ifo->options &= ~DHCPCD_INFORM;
|
||||
} else if (strncmp(arg, "subnet_mask=", strlen("subnet_mask=")) == 0) {
|
||||
if (parse_addr(&ifo->req_mask, NULL, p) != 0)
|
||||
return -1;
|
||||
} else if (strncmp(arg, "routes=", strlen("routes=")) == 0 ||
|
||||
strncmp(arg, "static_routes=", strlen("static_routes=")) == 0 ||
|
||||
strncmp(arg, "classless_static_routes=", strlen("classless_static_routes=")) == 0 ||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2008 Roy Marples <roy@marples.name>
|
||||
* Copyright (c) 2006-2010 Roy Marples <roy@marples.name>
|
||||
* All rights reserved
|
||||
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2010 Roy Marples <roy@marples.name>
|
||||
* Copyright (c) 2006-2011 Roy Marples <roy@marples.name>
|
||||
* All rights reserved
|
||||
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -726,7 +726,8 @@ get_udp_data(const uint8_t **data, const uint8_t *udp)
|
|||
}
|
||||
|
||||
int
|
||||
valid_udp_packet(const uint8_t *data, size_t data_len, struct in_addr *from)
|
||||
valid_udp_packet(const uint8_t *data, size_t data_len, struct in_addr *from,
|
||||
int noudpcsum)
|
||||
{
|
||||
struct udp_dhcp_packet packet;
|
||||
uint16_t bytes, udpsum;
|
||||
|
@ -754,19 +755,22 @@ valid_udp_packet(const uint8_t *data, size_t data_len, struct in_addr *from)
|
|||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
udpsum = packet.udp.uh_sum;
|
||||
packet.udp.uh_sum = 0;
|
||||
packet.ip.ip_hl = 0;
|
||||
packet.ip.ip_v = 0;
|
||||
packet.ip.ip_tos = 0;
|
||||
packet.ip.ip_len = packet.udp.uh_ulen;
|
||||
packet.ip.ip_id = 0;
|
||||
packet.ip.ip_off = 0;
|
||||
packet.ip.ip_ttl = 0;
|
||||
packet.ip.ip_sum = 0;
|
||||
if (udpsum && checksum(&packet, bytes) != udpsum) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
|
||||
if (noudpcsum == 0) {
|
||||
udpsum = packet.udp.uh_sum;
|
||||
packet.udp.uh_sum = 0;
|
||||
packet.ip.ip_hl = 0;
|
||||
packet.ip.ip_v = 0;
|
||||
packet.ip.ip_tos = 0;
|
||||
packet.ip.ip_len = packet.udp.uh_ulen;
|
||||
packet.ip.ip_id = 0;
|
||||
packet.ip.ip_off = 0;
|
||||
packet.ip.ip_ttl = 0;
|
||||
packet.ip.ip_sum = 0;
|
||||
if (udpsum && checksum(&packet, bytes) != udpsum) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* dhcpcd - DHCP client daemon
|
||||
* Copyright (c) 2006-2010 Roy Marples <roy@marples.name>
|
||||
* Copyright (c) 2006-2011 Roy Marples <roy@marples.name>
|
||||
* All rights reserved
|
||||
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -84,6 +84,7 @@ struct rt {
|
|||
struct in_addr net;
|
||||
struct in_addr gate;
|
||||
const struct interface *iface;
|
||||
struct in_addr src;
|
||||
struct rt *next;
|
||||
};
|
||||
|
||||
|
@ -139,14 +140,14 @@ extern const size_t udp_dhcp_len;
|
|||
ssize_t make_udp_packet(uint8_t **, const uint8_t *, size_t,
|
||||
struct in_addr, struct in_addr);
|
||||
ssize_t get_udp_data(const uint8_t **, const uint8_t *);
|
||||
int valid_udp_packet(const uint8_t *, size_t, struct in_addr *);
|
||||
int valid_udp_packet(const uint8_t *, size_t, struct in_addr *, int);
|
||||
|
||||
int open_socket(struct interface *, int);
|
||||
ssize_t send_packet(const struct interface *, struct in_addr,
|
||||
const uint8_t *, ssize_t);
|
||||
ssize_t send_raw_packet(const struct interface *, int,
|
||||
const void *, ssize_t);
|
||||
ssize_t get_raw_packet(struct interface *, int, void *, ssize_t);
|
||||
ssize_t get_raw_packet(struct interface *, int, void *, ssize_t, int *);
|
||||
|
||||
int init_sockets(void);
|
||||
int open_link_socket(void);
|
||||
|
|
Loading…
Reference in New Issue