File diff_release_1_8_2..44ee01c7.patch of Package radvd
diff --git a/CHANGES b/CHANGES
index 07ad3a5..7a4501e 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,8 @@
+08/10/2011 More careful checking of iface name
+
+06/10/2011 Updating buffer usage tracking in send_ra to track buffer usage BEFORE
+ the buffer is used rather than after in order to prevent buffer overflow
+
06/10/2011 1.8.2 release
04/10/2011 1) A privilege escalation flaw was found in radvd, due to a buffer overflow
diff --git a/VERSION b/VERSION
index b60874f..db3aa84 100644
--- a/VERSION
+++ b/VERSION
@@ -3,4 +3,4 @@
#
# this file is automatically processed by configure
#
-1.8.2
+1.8.3rc1
diff --git a/defaults.h b/defaults.h
index 55f44d5..72809d2 100644
--- a/defaults.h
+++ b/defaults.h
@@ -200,7 +200,7 @@ struct nd_opt_dnssl_info_local
uint8_t nd_opt_dnssli_len;
uint16_t nd_opt_dnssli_reserved;
uint32_t nd_opt_dnssli_lifetime;
- char nd_opt_dnssli_suffixes[];
+ unsigned char nd_opt_dnssli_suffixes[];
};
/* Flags */
diff --git a/device-linux.c b/device-linux.c
index c836f93..9187b4e 100644
--- a/device-linux.c
+++ b/device-linux.c
@@ -244,7 +244,7 @@ set_interface_var(const char *iface,
return -1;
/* No path traversal */
- if (strstr(name, "..") || strchr(name, '/'))
+ if (!iface[0] || !strcmp(iface, ".") || !strcmp(iface, "..") || strchr(iface, '/'))
return -1;
if (access(spath, F_OK) != 0)
diff --git a/process.c b/process.c
index 581905e..6b99103 100644
--- a/process.c
+++ b/process.c
@@ -423,7 +423,7 @@ process_ra(struct Interface *iface, unsigned char *msg, int len,
suffix[0] = '\0';
for (offset = 0; offset < (dnsslinfo->nd_opt_dnssli_len-1)*8;) {
- if (&dnsslinfo->nd_opt_dnssli_suffixes[offset] - (char*)opt_str >= len)
+ if (&dnsslinfo->nd_opt_dnssli_suffixes[offset] - opt_str >= len)
return;
label_len = dnsslinfo->nd_opt_dnssli_suffixes[offset++];
@@ -450,7 +450,7 @@ process_ra(struct Interface *iface, unsigned char *msg, int len,
*/
if ((sizeof(suffix) - strlen(suffix)) < (label_len + 2) ||
label_len > label_len + 2 ||
- &dnsslinfo->nd_opt_dnssli_suffixes[offset+label_len] - (char*)opt_str >= len ||
+ &dnsslinfo->nd_opt_dnssli_suffixes[offset+label_len] - opt_str >= len ||
offset + label_len < offset) {
flog(LOG_ERR, "oversized suffix in DNSSL option on %s from %s",
iface->Name, addr_str);
@@ -459,7 +459,7 @@ process_ra(struct Interface *iface, unsigned char *msg, int len,
if (suffix[0] != '\0')
strcat(suffix, ".");
- strncat(suffix, &dnsslinfo->nd_opt_dnssli_suffixes[offset], label_len);
+ strncat(suffix, (char*)&dnsslinfo->nd_opt_dnssli_suffixes[offset], label_len);
offset += label_len;
}
break;
diff --git a/radvdump.c b/radvdump.c
index 46ad609..07025f4 100644
--- a/radvdump.c
+++ b/radvdump.c
@@ -463,7 +463,7 @@ print_ff(unsigned char *msg, int len, struct sockaddr_in6 *addr, int hoplimit, u
if (suffix[0] != '\0')
strcat(suffix, ".");
- strncat(suffix, &dnssl_info->nd_opt_dnssli_suffixes[offset], label_len);
+ strncat(suffix, (char*)&dnssl_info->nd_opt_dnssli_suffixes[offset], label_len);
offset += label_len;
}
diff --git a/send.c b/send.c
index b5ac52d..acdcfd6 100644
--- a/send.c
+++ b/send.c
@@ -72,7 +72,7 @@ send_ra_inc_len(size_t *len, int add)
*len += add;
if(*len >= MSG_SIZE_SEND)
{
- flog(LOG_ERR, "Too many prefixes or routes. Exiting.");
+ flog(LOG_ERR, "Too many prefixes, routes, rdnss or dnssl to fit in buffer. Exiting.");
exit(1);
}
}
@@ -187,6 +187,8 @@ send_ra(struct Interface *iface, struct in6_addr *dest)
memset(buff, 0, sizeof(buff));
radvert = (struct nd_router_advert *) buff;
+ send_ra_inc_len(&len, sizeof(struct nd_router_advert));
+
radvert->nd_ra_type = ND_ROUTER_ADVERT;
radvert->nd_ra_code = 0;
radvert->nd_ra_cksum = 0;
@@ -212,8 +214,6 @@ send_ra(struct Interface *iface, struct in6_addr *dest)
radvert->nd_ra_reachable = htonl(iface->AdvReachableTime);
radvert->nd_ra_retransmit = htonl(iface->AdvRetransTimer);
- len = sizeof(struct nd_router_advert);
-
prefix = iface->AdvPrefixList;
/*
@@ -228,6 +228,8 @@ send_ra(struct Interface *iface, struct in6_addr *dest)
pinfo = (struct nd_opt_prefix_info *) (buff + len);
+ send_ra_inc_len(&len, sizeof(*pinfo));
+
pinfo->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
pinfo->nd_opt_pi_len = 4;
pinfo->nd_opt_pi_prefix_len = prefix->PrefixLen;
@@ -260,8 +262,6 @@ send_ra(struct Interface *iface, struct in6_addr *dest)
}
pinfo->nd_opt_pi_reserved2 = 0;
- send_ra_inc_len(&len, sizeof(*pinfo));
-
memcpy(&pinfo->nd_opt_pi_prefix, &prefix->Prefix,
sizeof(struct in6_addr));
}
@@ -281,6 +281,8 @@ send_ra(struct Interface *iface, struct in6_addr *dest)
rinfo = (struct nd_opt_route_info_local *) (buff + len);
+ send_ra_inc_len(&len, sizeof(*rinfo));
+
rinfo->nd_opt_ri_type = ND_OPT_ROUTE_INFORMATION;
/* XXX: the prefixes are allowed to be sent in smaller chunks as well */
rinfo->nd_opt_ri_len = 3;
@@ -294,8 +296,6 @@ send_ra(struct Interface *iface, struct in6_addr *dest)
rinfo->nd_opt_ri_lifetime = htonl(route->AdvRouteLifetime);
}
- send_ra_inc_len(&len, sizeof(*rinfo));
-
memcpy(&rinfo->nd_opt_ri_prefix, &route->Prefix,
sizeof(struct in6_addr));
@@ -314,6 +314,8 @@ send_ra(struct Interface *iface, struct in6_addr *dest)
rdnssinfo = (struct nd_opt_rdnss_info_local *) (buff + len);
+ send_ra_inc_len(&len, sizeof(*rdnssinfo) - (3-rdnss->AdvRDNSSNumber)*sizeof(struct in6_addr));
+
rdnssinfo->nd_opt_rdnssi_type = ND_OPT_RDNSS_INFORMATION;
rdnssinfo->nd_opt_rdnssi_len = 1 + 2*rdnss->AdvRDNSSNumber;
rdnssinfo->nd_opt_rdnssi_pref_flag_reserved = 0;
@@ -330,7 +332,6 @@ send_ra(struct Interface *iface, struct in6_addr *dest)
sizeof(struct in6_addr));
memcpy(&rdnssinfo->nd_opt_rdnssi_addr3, &rdnss->AdvRDNSSAddr3,
sizeof(struct in6_addr));
- send_ra_inc_len(&len, sizeof(*rdnssinfo) - (3-rdnss->AdvRDNSSNumber)*sizeof(struct in6_addr));
rdnss = rdnss->next;
}
@@ -344,13 +345,18 @@ send_ra(struct Interface *iface, struct in6_addr *dest)
while(dnssl)
{
struct nd_opt_dnssl_info_local *dnsslinfo;
+ int const start_len = len;
int i;
- char *buff_ptr;
dnsslinfo = (struct nd_opt_dnssl_info_local *) (buff + len);
+ send_ra_inc_len(&len, sizeof(dnsslinfo->nd_opt_dnssli_type) +
+ sizeof(dnsslinfo->nd_opt_dnssli_len) +
+ sizeof(dnsslinfo->nd_opt_dnssli_reserved) +
+ sizeof(dnsslinfo->nd_opt_dnssli_lifetime)
+ );
+
dnsslinfo->nd_opt_dnssli_type = ND_OPT_DNSSL_INFORMATION;
- dnsslinfo->nd_opt_dnssli_len = 1; /* more further down */
dnsslinfo->nd_opt_dnssli_reserved = 0;
if (iface->cease_adv && dnssl->FlushDNSSLFlag) {
@@ -359,7 +365,6 @@ send_ra(struct Interface *iface, struct in6_addr *dest)
dnsslinfo->nd_opt_dnssli_lifetime = htonl(dnssl->AdvDNSSLLifetime);
}
- buff_ptr = dnsslinfo->nd_opt_dnssli_suffixes;
for (i = 0; i < dnssl->AdvDNSSLNumber; i++) {
char *label;
int label_len;
@@ -372,24 +377,32 @@ send_ra(struct Interface *iface, struct in6_addr *dest)
else
label_len = strchr(label, '.') - label;
- *buff_ptr++ = label_len;
+ buff_dest = len;
+ send_ra_inc_len(&len, 1);
+ buff[buff_dest] = label_len;
- memcpy(buff_ptr, label, label_len);
- buff_ptr += label_len;
+ buff_dest = len;
+ send_ra_inc_len(&len, label_len);
+ memcpy(buff + buff_dest, label, label_len);
label += label_len;
if (label[0] == '.')
label++;
- else
- *buff_ptr++ = 0;
+ else {
+ buff_dest = len;
+ send_ra_inc_len(&len, 1);
+ buff[buff_dest] = 0;
+ }
}
}
- dnsslinfo->nd_opt_dnssli_len += ((buff_ptr-dnsslinfo->nd_opt_dnssli_suffixes)+7)/8;
+ dnsslinfo->nd_opt_dnssli_len = (len - start_len) / 8;
- /* TODO: If buff will overflow, it's already happened. This needs to be checked BEFORE the overflow. */
- send_ra_inc_len(&len, dnsslinfo->nd_opt_dnssli_len * 8);
+ if ( (len - start_len) % 8 != 0 ) {
+ send_ra_inc_len(&len, 8 - (len - start_len) % 8);
+ ++dnsslinfo->nd_opt_dnssli_len;
+ }
dnssl = dnssl->next;
}