DHCP messages are really BOOTP so lets name the structure accordingly.

While here, stop making assumptions about the size of a DHCP packet based
on a fixed structure from a default MTU of 1500.
Instead, make it flexable and set the DHCP packet size to the interface MTU
less UDP and IP headers.
As a result, we need to know the size of the DHCP packet received
rather than just walking the old fixed DHCP message structure.

This makes Coverity happy about tainted scalar values when parsing DHCP
messages.
This commit is contained in:
Roy Marples 2016-05-06 13:26:41 +00:00
parent 416a319e23
commit a67f0194df
8 changed files with 632 additions and 601 deletions

12
auth.c
View File

@ -320,8 +320,8 @@ gottoken:
/* RFC3318, section 5.2 - zero giaddr and hops */
if (mp == 4) {
*(mm + offsetof(struct dhcp_message, hwopcount)) = '\0';
memset(mm + offsetof(struct dhcp_message, giaddr), 0, 4);
*(mm + offsetof(struct bootp, hops)) = '\0';
memset(mm + offsetof(struct bootp, giaddr), 0, 4);
}
memset(hmac, 0, sizeof(hmac));
@ -638,10 +638,10 @@ dhcp_auth_encode(struct auth *auth, const struct token *t,
/* RFC3318, section 5.2 - zero giaddr and hops */
if (mp == 4) {
p = m + offsetof(struct dhcp_message, hwopcount);
p = m + offsetof(struct bootp, hops);
hops = *p;
*p = '\0';
p = m + offsetof(struct dhcp_message, giaddr);
p = m + offsetof(struct bootp, giaddr);
memcpy(&giaddr, p, sizeof(giaddr));
memset(p, 0, sizeof(giaddr));
} else {
@ -660,9 +660,9 @@ dhcp_auth_encode(struct auth *auth, const struct token *t,
/* RFC3318, section 5.2 - restore giaddr and hops */
if (mp == 4) {
p = m + offsetof(struct dhcp_message, hwopcount);
p = m + offsetof(struct bootp, hops);
*p = hops;
p = m + offsetof(struct dhcp_message, giaddr);
p = m + offsetof(struct bootp, giaddr);
memcpy(p, &giaddr, sizeof(giaddr));
}

1088
dhcp.c

File diff suppressed because it is too large Load Diff

83
dhcp.h
View File

@ -1,6 +1,6 @@
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
* Copyright (c) 2006-2016 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -131,14 +131,6 @@ enum FQDN {
FQDN_BOTH = 0x31
};
/* Sizes for DHCP options */
#define DHCP_CHADDR_LEN 16
#define SERVERNAME_LEN 64
#define BOOTFILE_LEN 128
#define DHCP_UDP_LEN (14 + 20 + 8)
#define DHCP_FIXED_LEN (DHCP_UDP_LEN + 226)
#define DHCP_OPTION_LEN (MTU_MAX - DHCP_FIXED_LEN)
/* Some crappy DHCP servers require the BOOTP minimum length */
#define BOOTP_MESSAGE_LENTH_MIN 300
@ -154,23 +146,30 @@ enum FQDN {
# endif
#endif
struct dhcp_message {
uint8_t op; /* message type */
uint8_t hwtype; /* hardware address type */
uint8_t hwlen; /* hardware address length */
uint8_t hwopcount; /* should be zero in client message */
uint32_t xid; /* transaction id */
uint16_t secs; /* elapsed time in sec. from boot */
uint16_t flags;
uint32_t ciaddr; /* (previously allocated) client IP */
uint32_t yiaddr; /* 'your' client IP address */
uint32_t siaddr; /* should be zero in client's messages */
uint32_t giaddr; /* should be zero in client's messages */
uint8_t chaddr[DHCP_CHADDR_LEN]; /* client's hardware address */
uint8_t servername[SERVERNAME_LEN]; /* server host name */
uint8_t bootfile[BOOTFILE_LEN]; /* boot file name */
uint32_t cookie;
uint8_t options[DHCP_OPTION_LEN]; /* message options - cookie */
/* Sizes for BOOTP options */
#define BOOTP_CHADDR_LEN 16
#define BOOTP_SNAME_LEN 64
#define BOOTP_FILE_LEN 128
#define BOOTP_VEND_LEN 64
/* DHCP is basically an extension to BOOTP */
struct bootp {
uint8_t op; /* message type */
uint8_t htype; /* hardware address type */
uint8_t hlen; /* hardware address length */
uint8_t hops; /* should be zero in client message */
uint32_t xid; /* transaction id */
uint16_t secs; /* elapsed time in sec. from boot */
uint16_t flags; /* such as broadcast flag */
uint32_t ciaddr; /* (previously allocated) client IP */
uint32_t yiaddr; /* 'your' client IP address */
uint32_t siaddr; /* should be zero in client's messages */
uint32_t giaddr; /* should be zero in client's messages */
uint8_t chaddr[BOOTP_CHADDR_LEN]; /* client's hardware address */
uint8_t sname[BOOTP_SNAME_LEN]; /* server host name */
uint8_t file[BOOTP_FILE_LEN]; /* boot file name */
uint8_t vend[BOOTP_VEND_LEN]; /* vendor specific area */
/* DHCP allows a variable length vendor area */
} __packed;
struct dhcp_lease {
@ -201,10 +200,14 @@ enum DHS {
struct dhcp_state {
enum DHS state;
struct dhcp_message *sent;
struct dhcp_message *offer;
struct dhcp_message *new;
struct dhcp_message *old;
struct bootp *sent;
size_t sent_len;
struct bootp *offer;
size_t offer_len;
struct bootp *new;
size_t new_len;
struct bootp *old;
size_t old_len;
struct dhcp_lease lease;
const char *reason;
time_t interval;
@ -232,6 +235,12 @@ struct dhcp_state {
#define D_STATE_RUNNING(ifp) \
(D_CSTATE((ifp)) && D_CSTATE((ifp))->new && D_CSTATE((ifp))->reason)
#define IS_DHCP(b) ((b) != NULL && \
(b)->vend[0] == 0x63 && \
(b)->vend[1] == 0x82 && \
(b)->vend[2] == 0x53 && \
(b)->vend[3] == 0x63)
#include "dhcpcd.h"
#include "if-options.h"
@ -241,23 +250,11 @@ ssize_t decode_rfc3442(char *, size_t, const uint8_t *p, size_t);
void dhcp_printoptions(const struct dhcpcd_ctx *,
const struct dhcp_opt *, size_t);
int get_option_addr(struct dhcpcd_ctx *,struct in_addr *,
const struct dhcp_message *, uint8_t);
#define IS_BOOTP(i, m) ((m) != NULL && \
get_option_uint8((i)->ctx, NULL, (m), DHO_MESSAGETYPE) == -1)
uint16_t dhcp_get_mtu(const struct interface *);
struct rt_head *dhcp_get_routes(struct interface *);
ssize_t dhcp_env(char **, const char *, const struct dhcp_message *,
ssize_t dhcp_env(char **, const char *, const struct bootp *, size_t,
const struct interface *);
uint32_t dhcp_xid(const struct interface *);
struct dhcp_message *dhcp_message_new(const struct in_addr *addr,
const struct in_addr *mask);
int dhcp_message_add_addr(struct dhcp_message *, uint8_t, struct in_addr);
ssize_t make_message(struct dhcp_message **, const struct interface *,
uint8_t);
int valid_dhcp_packet(unsigned char *);
void dhcp_handleifa(int, struct interface *,
const struct in_addr *, const struct in_addr *, const struct in_addr *,
int);

View File

@ -461,25 +461,6 @@ configure_interface1(struct interface *ifp)
ifo->options |= DHCPCD_IPV6RA_OWN;
}
/* If we haven't specified a ClientID and our hardware address
* length is greater than DHCP_CHADDR_LEN then we enforce a ClientID
* of the hardware address family and the hardware address.
* If there is no hardware address and no ClientID set,
* force a DUID based ClientID. */
if (ifp->hwlen > DHCP_CHADDR_LEN)
ifo->options |= DHCPCD_CLIENTID;
else if (ifp->hwlen == 0 && !(ifo->options & DHCPCD_CLIENTID))
ifo->options |= DHCPCD_CLIENTID | DHCPCD_DUID;
/* Firewire and InfiniBand interfaces require ClientID and
* the broadcast option being set. */
switch (ifp->family) {
case ARPHRD_IEEE1394: /* FALLTHROUGH */
case ARPHRD_INFINIBAND:
ifo->options |= DHCPCD_CLIENTID | DHCPCD_BROADCAST;
break;
}
if (!(ifo->options & DHCPCD_IAID)) {
/*
* An IAID is for identifying a unqiue interface within

View File

@ -156,12 +156,13 @@ struct dhcpcd_ctx {
struct rt_head *ipv4_kroutes;
int udp_fd;
uint8_t *packet;
uint8_t packet[1500]; /* maximum packet we deal with */
/* Our aggregate option buffer.
* We ONLY use this when options are split, which for most purposes is
* practically never. See RFC3396 for details. */
uint8_t *opt_buffer;
size_t opt_buffer_len;
#endif
#ifdef INET6
unsigned char secret[SECRET_LEN];

View File

@ -498,11 +498,7 @@ if_readrawpacket(struct interface *ifp, uint16_t protocol,
*flags = 0;
for (;;) {
if (state->buffer_len == 0) {
/* alias a void pointer to our buffer
* so that Coverity does not treat this as tainted. */
void *bufp = state->buffer;
bytes = read(fd, bufp, state->buffer_size);
bytes = read(fd, state->buffer, state->buffer_size);
if (bytes == -1 || bytes == 0)
return bytes;
state->buffer_len = (size_t)bytes;

13
ipv4.c
View File

@ -324,11 +324,9 @@ ipv4_ifcmp(const struct interface *si, const struct interface *ti)
/* If we are either, they neither have a lease, or they both have.
* We need to check for IPv4LL and make it non-preferred. */
if (sis->new && tis->new) {
int sill = (sis->new->cookie == htonl(MAGIC_COOKIE));
int till = (tis->new->cookie == htonl(MAGIC_COOKIE));
if (sill && !till)
if (IS_DHCP(sis->new) && !IS_DHCP(tis->new))
return -1;
if (!sill && till)
if (!IS_DHCP(sis->new) && IS_DHCP(tis->new))
return 1;
}
return 0;
@ -1098,7 +1096,6 @@ ipv4_applyaddr(void *arg)
{
struct interface *ifp = arg, *ifn;
struct dhcp_state *state = D_STATE(ifp), *nstate;
struct dhcp_message *dhcp;
struct dhcp_lease *lease;
struct if_options *ifo = ifp->options;
struct ipv4_addr *ap;
@ -1106,11 +1103,11 @@ ipv4_applyaddr(void *arg)
if (state == NULL)
return;
dhcp = state->new;
lease = &state->lease;
lease = &state->lease;
if_sortinterfaces(ifp->ctx);
if (dhcp == NULL) {
if (state->new == NULL) {
if ((ifo->options & (DHCPCD_EXITING | DHCPCD_PERSISTENT)) !=
(DHCPCD_EXITING | DHCPCD_PERSISTENT))
{

View File

@ -421,7 +421,7 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
}
#ifdef INET
if (dhcp && state && state->old) {
n = dhcp_env(NULL, NULL, state->old, ifp);
n = dhcp_env(NULL, NULL, state->old, state->old_len, ifp);
if (n == -1)
goto eexit;
if (n > 0) {
@ -430,7 +430,8 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
if (nenv == NULL)
goto eexit;
env = nenv;
n = dhcp_env(env + elen, "old", state->old, ifp);
n = dhcp_env(env + elen, "old",
state->old, state->old_len, ifp);
if (n == -1)
goto eexit;
elen += (size_t)n;
@ -476,7 +477,7 @@ dumplease:
}
}
if (dhcp && state && state->new) {
n = dhcp_env(NULL, NULL, state->new, ifp);
n = dhcp_env(NULL, NULL, state->new, state->new_len, ifp);
if (n > 0) {
nenv = realloc(env, sizeof(char *) *
(elen + (size_t)n + 1));
@ -484,7 +485,7 @@ dumplease:
goto eexit;
env = nenv;
n = dhcp_env(env + elen, "new",
state->new, ifp);
state->new, state->new_len, ifp);
if (n == -1)
goto eexit;
elen += (size_t)n;