summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Fedoryshchenko <denys.f@collabora.com>2026-09-07 20:54:47 +0300
committerGitHub <noreply@github.com>2026-09-07 20:54:47 +0300
commit7e81fd4a4c5fb47f9ddfc6d99124ade83ca58940 (patch)
treeee978a149543f91c8a155a6f6dcbee26564f7bf5
parent57ae56148c5519b9207ede623098d3cfad5211b8 (diff)
parent4654c4a9c083780f5e151ee064e69a357c48d364 (diff)
downloadaccel-ppp-7e81fd4a4c5fb47f9ddfc6d99124ade83ca58940.tar.gz
accel-ppp-7e81fd4a4c5fb47f9ddfc6d99124ade83ca58940.zip
Merge pull request #361 from nuclearcat/fix-protocol-buffer-access
Fix several unsafe or unaligned integer accesses found in protocol parsing paths, including option-gated MPPE, DHCP, PPPoE, RADIUS, IPCP and IPv6CP code.
-rw-r--r--accel-pppd/backup/backup_file.c8
-rw-r--r--accel-pppd/ctrl/ipoe/dhcpv4.c26
-rw-r--r--accel-pppd/ctrl/ipoe/dhcpv4_options.c14
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.c50
-rw-r--r--accel-pppd/ctrl/l2tp/packet.c68
-rw-r--r--accel-pppd/ctrl/l2tp/packet_test.c2
-rw-r--r--accel-pppd/ctrl/pppoe/pppoe.c28
-rw-r--r--accel-pppd/ctrl/pppoe/tr101.c29
-rw-r--r--accel-pppd/extra/ippool.c4
-rw-r--r--accel-pppd/extra/ipv6pool.c13
-rw-r--r--accel-pppd/ifcfg.c4
-rw-r--r--accel-pppd/ipdb.c11
-rw-r--r--accel-pppd/ipv6/dhcpv6.c18
-rw-r--r--accel-pppd/ipv6/dhcpv6_packet.c111
-rw-r--r--accel-pppd/memdebug.c23
-rw-r--r--accel-pppd/ppp/ccp_mppe.c3
-rw-r--r--accel-pppd/ppp/ipv6cp_opt_intfid.c9
-rw-r--r--accel-pppd/ppp/ppp_ccp.c47
-rw-r--r--accel-pppd/ppp/ppp_ipcp.c47
-rw-r--r--accel-pppd/ppp/ppp_ipv6cp.c47
-rw-r--r--accel-pppd/ppp/ppp_lcp.c56
-rw-r--r--accel-pppd/radius/backup.c21
-rw-r--r--accel-pppd/radius/packet.c32
-rw-r--r--accel-pppd/session_backup.c11
-rw-r--r--accel-pppd/utils.h73
-rw-r--r--tests/accel-pppd/pppoe/test_pppoe_session_wo_auth.py3
26 files changed, 506 insertions, 252 deletions
diff --git a/accel-pppd/backup/backup_file.c b/accel-pppd/backup/backup_file.c
index 472694f0..eaaf87d2 100644
--- a/accel-pppd/backup/backup_file.c
+++ b/accel-pppd/backup/backup_file.c
@@ -96,7 +96,7 @@ static int fs_commit(struct backup_data *d)
ptr = (uint8_t *)(tag + 1);
*ptr = tag->id; ptr++;
*ptr = tag->internal ? 1 : 0; ptr++;
- *(uint16_t *)ptr = tag->size;
+ memcpy(ptr, &tag->size, sizeof(tag->size));
MD5_Update(&md5, tag + 1, 4 + tag->size);
iov[i].iov_base = tag + 1;
iov[i].iov_len = 4 + tag->size;
@@ -278,14 +278,16 @@ static void restore_session(const char *fn, int internal)
}
if (!internal && ptr[1]) {
- ptr += 4 + *(uint16_t *)(ptr + 2);
+ uint16_t tag_size;
+ memcpy(&tag_size, ptr + 2, sizeof(tag_size));
+ ptr += 4 + tag_size;
continue;
}
tag = fs_alloc_tag(d, 0);
tag->id = *ptr; ptr++;
tag->internal = (*ptr & 0x01) ? 1 : 0; ptr ++;
- tag->size = *(uint16_t *)ptr; ptr += 2;
+ memcpy(&tag->size, ptr, sizeof(tag->size)); ptr += 2;
tag->data = ptr; ptr += tag->size;
list_add_tail(&tag->entry, &mod->tag_list);
diff --git a/accel-pppd/ctrl/ipoe/dhcpv4.c b/accel-pppd/ctrl/ipoe/dhcpv4.c
index d80a80f3..f1427e17 100644
--- a/accel-pppd/ctrl/ipoe/dhcpv4.c
+++ b/accel-pppd/ctrl/ipoe/dhcpv4.c
@@ -349,6 +349,12 @@ static int dhcpv4_parse_packet(struct dhcpv4_packet *pack, int len)
list_add_tail(&opt->entry, &pack->options);
+ }
+
+ if (dhcpv4_check_options(pack))
+ return -1;
+
+ list_for_each_entry(opt, &pack->options, entry) {
if (opt->type == 53)
pack->msg_type = opt->data[0];
else if (opt->type == 82)
@@ -356,17 +362,14 @@ static int dhcpv4_parse_packet(struct dhcpv4_packet *pack, int len)
else if (opt->type == 62)
pack->client_id = opt;
else if (opt->type == 50)
- memcpy(&pack->request_ip, opt->data, 4);
+ memcpy(&pack->request_ip, opt->data, sizeof(pack->request_ip));
else if (opt->type == 54)
- memcpy(&pack->server_id, opt->data, 4);
+ memcpy(&pack->server_id, opt->data, sizeof(pack->server_id));
}
if (pack->msg_type == 0 || pack->msg_type > 8)
return -1;
- if (dhcpv4_check_options(pack))
- return -1;
-
pack->ptr = ptr;
/*if (conf_verbose) {
@@ -933,6 +936,7 @@ void dhcpv4_send_notify(struct dhcpv4_serv *serv, struct dhcpv4_packet *req, uns
{
struct dhcpv4_packet *pack = dhcpv4_packet_alloc();
uint8_t opt[8 + ETH_ALEN];
+ uint32_t value;
if (!pack) {
log_emerg("out of memory\n");
@@ -946,8 +950,10 @@ void dhcpv4_send_notify(struct dhcpv4_serv *serv, struct dhcpv4_packet *req, uns
pack->hdr->siaddr = 0;
pack->hdr->giaddr = 0;
- *(uint32_t *)opt = htonl(ACCEL_PPP_MAGIC);
- *(uint32_t *)(opt + 4) = htonl(weight);
+ value = htonl(ACCEL_PPP_MAGIC);
+ memcpy(opt, &value, sizeof(value));
+ value = htonl(weight);
+ memcpy(opt + sizeof(value), &value, sizeof(value));
memcpy(opt + 8, serv->hwaddr, ETH_ALEN);
dhcpv4_packet_add_opt_u8(pack, 53, DHCPDISCOVER);
@@ -1100,8 +1106,8 @@ int dhcpv4_relay_send(struct dhcpv4_relay *relay, struct dhcpv4_packet *request,
if (server_id) {
opt = dhcpv4_packet_find_opt(request, 54);
if (opt) {
- _server_id = *(uint32_t *)opt->data;
- *(uint32_t *)opt->data = server_id;
+ memcpy(&_server_id, opt->data, sizeof(_server_id));
+ memcpy(opt->data, &server_id, sizeof(server_id));
}
}
@@ -1123,7 +1129,7 @@ int dhcpv4_relay_send(struct dhcpv4_relay *relay, struct dhcpv4_packet *request,
request->hdr->giaddr = giaddr;
if (opt)
- *(uint32_t *)opt->data = _server_id;
+ memcpy(opt->data, &_server_id, sizeof(_server_id));
if (n != len)
return -1;
diff --git a/accel-pppd/ctrl/ipoe/dhcpv4_options.c b/accel-pppd/ctrl/ipoe/dhcpv4_options.c
index 042a7406..fe6c2a5f 100644
--- a/accel-pppd/ctrl/ipoe/dhcpv4_options.c
+++ b/accel-pppd/ctrl/ipoe/dhcpv4_options.c
@@ -205,7 +205,10 @@ static void print_message_type(const struct dhcpv4_option *opt, int elem_size, v
{
const char *msg_name[] = {"", "Discover", "Offer", "Request", "Decline", "Ack", "Nak", "Release", "Inform"};
- print("%s", msg_name[opt->data[0]]);
+ if (opt->data[0] < sizeof(msg_name) / sizeof(msg_name[0]))
+ print("%s", msg_name[opt->data[0]]);
+ else
+ print("%u", opt->data[0]);
}
static void print_request_list(const struct dhcpv4_option *opt, int elem_size, void (*print)(const char *fmt, ...))
@@ -232,14 +235,19 @@ static void print_relay_agent(const struct dhcpv4_option *opt, int elem_size, vo
int type, len;
while (ptr < endptr) {
+ if (endptr - ptr < 2) {
+ print("invalid");
+ return;
+ }
+
if (ptr != opt->data)
print(" ");
type = *ptr++;
len = *ptr++;
- /*if (ptr + len > endptr) {
+ if (endptr - ptr < len) {
print(" invalid");
return;
- }*/
+ }
if (type == 1)
print("{Agent-Circuit-ID ");
else if (type == 2)
diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c
index 1e3f7054..e7b1320f 100644
--- a/accel-pppd/ctrl/ipoe/ipoe.c
+++ b/accel-pppd/ctrl/ipoe/ipoe.c
@@ -1835,6 +1835,7 @@ static int check_notify(struct ipoe_serv *serv, struct dhcpv4_packet *pack)
struct dhcpv4_option *opt = dhcpv4_packet_find_opt(pack, 43);
struct ipoe_session *ses;
unsigned int w;
+ uint32_t value;
if (!opt)
return 0;
@@ -1842,10 +1843,12 @@ static int check_notify(struct ipoe_serv *serv, struct dhcpv4_packet *pack)
if (opt->len != 8 + ETH_ALEN)
return 0;
- if (*(uint32_t *)opt->data != htonl(ACCEL_PPP_MAGIC))
+ memcpy(&value, opt->data, sizeof(value));
+ if (value != htonl(ACCEL_PPP_MAGIC))
return 0;
- w = htonl(*(uint32_t *)(opt->data + 4));
+ memcpy(&value, opt->data + sizeof(value), sizeof(value));
+ w = ntohl(value);
list_for_each_entry(ses, &serv->sessions, entry) {
if (ses->xid == pack->hdr->xid && memcmp(pack->hdr->chaddr, ses->hwaddr, ETH_ALEN) == 0) {
@@ -2029,6 +2032,7 @@ static void ipoe_ses_recv_dhcpv4_relay(struct dhcpv4_packet *pack)
{
struct ipoe_session *ses = container_of(triton_context_self(), typeof(*ses), ctx);
struct dhcpv4_option *opt;
+ uint32_t value;
if (ses->dhcpv4_relay_reply)
dhcpv4_packet_free(ses->dhcpv4_relay_reply);
@@ -2047,24 +2051,32 @@ static void ipoe_ses_recv_dhcpv4_relay(struct dhcpv4_packet *pack)
}
opt = dhcpv4_packet_find_opt(pack, 51);
- if (opt)
- ses->lease_time = ntohl(*(uint32_t *)opt->data);
+ if (opt) {
+ memcpy(&value, opt->data, sizeof(value));
+ ses->lease_time = ntohl(value);
+ }
opt = dhcpv4_packet_find_opt(pack, 58);
- if (opt)
- ses->renew_time = ntohl(*(uint32_t *)opt->data);
+ if (opt) {
+ memcpy(&value, opt->data, sizeof(value));
+ ses->renew_time = ntohl(value);
+ }
opt = dhcpv4_packet_find_opt(pack, 59);
- if (opt)
- ses->rebind_time = ntohl(*(uint32_t *)opt->data);
+ if (opt) {
+ memcpy(&value, opt->data, sizeof(value));
+ ses->rebind_time = ntohl(value);
+ }
opt = dhcpv4_packet_find_opt(pack, 1);
- if (opt)
- ses->mask = parse_dhcpv4_mask(ntohl(*(uint32_t *)opt->data));
+ if (opt) {
+ memcpy(&value, opt->data, sizeof(value));
+ ses->mask = parse_dhcpv4_mask(ntohl(value));
+ }
opt = dhcpv4_packet_find_opt(pack, 3);
if (opt)
- ses->router = *(uint32_t *)opt->data;
+ memcpy(&ses->router, opt->data, sizeof(ses->router));
if (pack->msg_type == DHCPOFFER) {
if (ses->ses.state == AP_STATE_STARTING) {
@@ -2409,7 +2421,7 @@ static void ev_radius_access_accept(struct ev_radius_t *ev)
ses->siaddr = attr->val.ipaddr;
break;
case DHCP_Router_Address:
- ses->router = *(in_addr_t *)attr->raw;
+ memcpy(&ses->router, attr->raw, sizeof(ses->router));
break;
case DHCP_Subnet_Mask:
ses->mask = ipaddr_to_prefix(attr->val.ipaddr);
@@ -2977,32 +2989,38 @@ static void ipoe_serv_timeout(struct triton_timer_t *t)
static void ipoe_ipv6_enable(struct ipoe_serv *serv)
{
struct ifreq ifr;
+ uint32_t addr;
strcpy(ifr.ifr_name, serv->ifname);
ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
ifr.ifr_hwaddr.sa_data[0] = 0x33;
ifr.ifr_hwaddr.sa_data[1] = 0x33;
- *(uint32_t *)(ifr.ifr_hwaddr.sa_data + 2) = htonl(0x02);
+ addr = htonl(0x02);
+ memcpy(ifr.ifr_hwaddr.sa_data + 2, &addr, sizeof(addr));
ioctl(sock_fd, SIOCADDMULTI, &ifr);
- *(uint32_t *)(ifr.ifr_hwaddr.sa_data + 2) = htonl(0x010002);
+ addr = htonl(0x010002);
+ memcpy(ifr.ifr_hwaddr.sa_data + 2, &addr, sizeof(addr));
ioctl(sock_fd, SIOCADDMULTI, &ifr);
}
static void ipoe_ipv6_disable(struct ipoe_serv *serv)
{
struct ifreq ifr;
+ uint32_t addr;
strcpy(ifr.ifr_name, serv->ifname);
ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
ifr.ifr_hwaddr.sa_data[0] = 0x33;
ifr.ifr_hwaddr.sa_data[1] = 0x33;
- *(uint32_t *)(ifr.ifr_hwaddr.sa_data + 2) = htonl(0x02);
+ addr = htonl(0x02);
+ memcpy(ifr.ifr_hwaddr.sa_data + 2, &addr, sizeof(addr));
ioctl(sock_fd, SIOCDELMULTI, &ifr);
- *(uint32_t *)(ifr.ifr_hwaddr.sa_data + 2) = htonl(0x010002);
+ addr = htonl(0x010002);
+ memcpy(ifr.ifr_hwaddr.sa_data + 2, &addr, sizeof(addr));
ioctl(sock_fd, SIOCDELMULTI, &ifr);
}
diff --git a/accel-pppd/ctrl/l2tp/packet.c b/accel-pppd/ctrl/l2tp/packet.c
index 0a4113a0..f134666d 100644
--- a/accel-pppd/ctrl/l2tp/packet.c
+++ b/accel-pppd/ctrl/l2tp/packet.c
@@ -111,58 +111,6 @@ void l2tp_packet_free(struct l2tp_packet_t *pack)
mempool_free(pack);
}
-/*
- * AVPs are not aligned in any way inside the packet buffer: their offset
- * depends on the length of every preceding AVP, which is peer chosen.
- * Always go through memcpy() to read multi-byte fields out of them, both to
- * stay portable on strict alignment architectures and to avoid tripping
- * -fsanitize=alignment.
- */
-static uint16_t unaligned_ntohs(const void *ptr)
-{
- uint16_t val;
-
- memcpy(&val, ptr, sizeof(val));
-
- return ntohs(val);
-}
-
-static uint32_t unaligned_ntohl(const void *ptr)
-{
- uint32_t val;
-
- memcpy(&val, ptr, sizeof(val));
-
- return ntohl(val);
-}
-
-static uint64_t unaligned_be64toh(const void *ptr)
-{
- uint64_t val;
-
- memcpy(&val, ptr, sizeof(val));
-
- return be64toh(val);
-}
-
-static void unaligned_htons(void *ptr, uint16_t val)
-{
- val = htons(val);
- memcpy(ptr, &val, sizeof(val));
-}
-
-static void unaligned_htonl(void *ptr, uint32_t val)
-{
- val = htonl(val);
- memcpy(ptr, &val, sizeof(val));
-}
-
-static void unaligned_htobe64(void *ptr, uint64_t val)
-{
- val = htobe64(val);
- memcpy(ptr, &val, sizeof(val));
-}
-
static void memxor(uint8_t *dst, const uint8_t *src, size_t sz)
{
size_t indx;
@@ -223,7 +171,7 @@ static int decode_avp(struct l2tp_avp_t *avp, const struct l2tp_attr_t *RV,
}
memxor(p1, avp->val, MD5_DIGEST_LENGTH);
- orig_attr_len = unaligned_ntohs(p1);
+ orig_attr_len = u_read_be16(p1);
if (orig_attr_len <= MD5_DIGEST_LENGTH - sizeof(uint16_t)) {
/* Enough bytes decoded already, no need to decode padding */
@@ -271,7 +219,7 @@ out:
trustworthy as the peer's knowledge of the shared secret. Bound it
against the room actually available in the received AVP before
letting it drive any read of the attribute value */
- orig_attr_len = unaligned_ntohs(avp->val);
+ orig_attr_len = u_read_be16(avp->val);
if (orig_attr_len > attr_len - sizeof(uint16_t)) {
log_warn("l2tp: incorrect hidden avp received (type %hu):"
" deciphered attribute length too big (ciphered"
@@ -502,17 +450,17 @@ int l2tp_recv(int fd, struct l2tp_packet_t **p, struct in_pktinfo *pkt_info,
case ATTR_TYPE_INT16:
if (orig_avp_len != sizeof(*avp) + 2)
goto out_err_len;
- attr->val.uint16 = unaligned_ntohs(orig_avp_val);
+ attr->val.uint16 = u_read_be16(orig_avp_val);
break;
case ATTR_TYPE_INT32:
if (orig_avp_len != sizeof(*avp) + 4)
goto out_err_len;
- attr->val.uint32 = unaligned_ntohl(orig_avp_val);
+ attr->val.uint32 = u_read_be32(orig_avp_val);
break;
case ATTR_TYPE_INT64:
if (orig_avp_len != sizeof(*avp) + 8)
goto out_err_len;
- attr->val.uint64 = unaligned_be64toh(orig_avp_val);
+ attr->val.uint64 = u_read_be64(orig_avp_val);
break;
case ATTR_TYPE_OCTETS:
attr->val.octets = _malloc(attr->length);
@@ -589,13 +537,13 @@ int l2tp_packet_send(int sock, struct l2tp_packet_t *pack)
else
switch (attr->attr->type) {
case ATTR_TYPE_INT16:
- unaligned_htons(avp->val, attr->val.int16);
+ u_write_be16(avp->val, attr->val.int16);
break;
case ATTR_TYPE_INT32:
- unaligned_htonl(avp->val, attr->val.int32);
+ u_write_be32(avp->val, attr->val.int32);
break;
case ATTR_TYPE_INT64:
- unaligned_htobe64(avp->val, attr->val.uint64);
+ u_write_be64(avp->val, attr->val.uint64);
break;
case ATTR_TYPE_STRING:
case ATTR_TYPE_OCTETS:
diff --git a/accel-pppd/ctrl/l2tp/packet_test.c b/accel-pppd/ctrl/l2tp/packet_test.c
index 9f962407..a6c9a182 100644
--- a/accel-pppd/ctrl/l2tp/packet_test.c
+++ b/accel-pppd/ctrl/l2tp/packet_test.c
@@ -4,7 +4,7 @@
* Not part of the cmake build. Compile and run with:
* gcc -O1 -g -Wall -fno-strict-aliasing -D_GNU_SOURCE \
* -fsanitize=address,undefined -fno-sanitize-recover=all \
- * -I accel-pppd/include -I accel-pppd/ctrl/l2tp \
+ * -I accel-pppd -I accel-pppd/include -I accel-pppd/ctrl/l2tp \
* -o /tmp/l2tp_packet_test \
* accel-pppd/ctrl/l2tp/packet_test.c accel-pppd/ctrl/l2tp/packet.c \
* -lcrypto && /tmp/l2tp_packet_test
diff --git a/accel-pppd/ctrl/pppoe/pppoe.c b/accel-pppd/ctrl/pppoe/pppoe.c
index 0e65168d..bd92cbf8 100644
--- a/accel-pppd/ctrl/pppoe/pppoe.c
+++ b/accel-pppd/ctrl/pppoe/pppoe.c
@@ -556,7 +556,12 @@ static void print_tag_octets(struct pppoe_tag *tag)
static void print_tag_u16(struct pppoe_tag *tag)
{
- log_info2("%i", (uint16_t)ntohs(*(uint16_t *)tag->tag_data));
+ if (ntohs(tag->tag_len) != sizeof(uint16_t)) {
+ log_info2("invalid");
+ return;
+ }
+
+ log_info2("%i", u_read_be16(tag->tag_data));
}
static void print_packet(const char *ifname, const char *op, uint8_t *pack)
@@ -633,7 +638,7 @@ static void print_packet(const char *ifname, const char *op, uint8_t *pack)
if (ntohs(tag->tag_len) < 4)
log_info2(" <Vendor-Specific invalid>");
else
- log_info2(" <Vendor-Specific %x>", ntohl(*(uint32_t *)tag->tag_data));
+ log_info2(" <Vendor-Specific %x>", u_read_be32(tag->tag_data));
break;
case TAG_RELAY_SESSION_ID:
log_info2(" <Relay-Session-Id ");
@@ -701,7 +706,10 @@ static void generate_cookie(struct pppoe_serv_t *serv, const uint8_t *src, uint8
} else
memset(u1.raw + 16, 0, 4);
- *(uint32_t *)(u1.raw + 20) = ts.tv_sec + conf_cookie_timeout;
+ {
+ uint32_t expires = ts.tv_sec + conf_cookie_timeout;
+ memcpy(u1.raw + 20, &expires, sizeof(expires));
+ }
for (i = 0; i < 3; i++)
DES_ecb_encrypt(&u1.b[i], &u2.b[i], &ks, DES_ENCRYPT);
@@ -739,8 +747,12 @@ static int check_cookie(struct pppoe_serv_t *serv, const uint8_t *src, const uin
for (i = 0; i < 3; i++)
DES_ecb_encrypt(&u2.b[i], &u1.b[i], &ks, DES_DECRYPT);
- if (*(uint32_t *)(u1.raw + 20) < ts.tv_sec)
- return 1;
+ {
+ uint32_t expires;
+ memcpy(&expires, u1.raw + 20, sizeof(expires));
+ if (expires < ts.tv_sec)
+ return 1;
+ }
MD5_Init(&ctx);
MD5_Update(&ctx, serv->secret, SECRET_LENGTH);
@@ -1073,7 +1085,7 @@ static void pppoe_recv_PADI(struct pppoe_serv_t *serv, uint8_t *pack, int size)
break;
case TAG_PPP_MAX_PAYLOAD:
if (ntohs(tag->tag_len) == 2)
- ppp_max_payload = ntohs(*(uint16_t *)tag->tag_data);
+ ppp_max_payload = u_read_be16(tag->tag_data);
break;
}
}
@@ -1220,14 +1232,14 @@ static void pppoe_recv_PADR(struct pppoe_serv_t *serv, uint8_t *pack, int size)
case TAG_VENDOR_SPECIFIC:
if (ntohs(tag->tag_len) < 4)
continue;
- vendor_id = ntohl(*(uint32_t *)tag->tag_data);
+ vendor_id = u_read_be32(tag->tag_data);
if (vendor_id == VENDOR_ADSL_FORUM)
if (conf_tr101)
tr101_tag = tag;
break;
case TAG_PPP_MAX_PAYLOAD:
if (ntohs(tag->tag_len) == 2)
- ppp_max_payload = ntohs(*(uint16_t *)tag->tag_data);
+ ppp_max_payload = u_read_be16(tag->tag_data);
break;
}
}
diff --git a/accel-pppd/ctrl/pppoe/tr101.c b/accel-pppd/ctrl/pppoe/tr101.c
index bb8b845a..06aeff86 100644
--- a/accel-pppd/ctrl/pppoe/tr101.c
+++ b/accel-pppd/ctrl/pppoe/tr101.c
@@ -8,6 +8,7 @@
#include "log.h"
#include "radius.h"
#include "memdebug.h"
+#include "utils.h"
#include "pppoe.h"
@@ -75,85 +76,85 @@ static int tr101_send_request(struct pppoe_tag *tr101, struct rad_packet_t *pack
case OPT_ACTUAL_DATA_RATE_UP:
if (len != 4)
goto inval;
- if (rad_packet_add_int(pack, "ADSL-Forum", "Actual-Data-Rate-Upstream", ntohl(*(uint32_t *)ptr)))
+ if (rad_packet_add_int(pack, "ADSL-Forum", "Actual-Data-Rate-Upstream", u_read_be32(ptr)))
return -1;
break;
case OPT_ACTUAL_DATA_RATE_DOWN:
if (len != 4)
goto inval;
- if (rad_packet_add_int(pack, "ADSL-Forum", "Actual-Data-Rate-Downstream", ntohl(*(uint32_t *)ptr)))
+ if (rad_packet_add_int(pack, "ADSL-Forum", "Actual-Data-Rate-Downstream", u_read_be32(ptr)))
return -1;
break;
case OPT_MIN_DATA_RATE_UP:
if (len != 4)
goto inval;
- if (rad_packet_add_int(pack, "ADSL-Forum", "Minimum-Data-Rate-Upstream", ntohl(*(uint32_t *)ptr)))
+ if (rad_packet_add_int(pack, "ADSL-Forum", "Minimum-Data-Rate-Upstream", u_read_be32(ptr)))
return -1;
break;
case OPT_MIN_DATA_RATE_DOWN:
if (len != 4)
goto inval;
- if (rad_packet_add_int(pack, "ADSL-Forum", "Minimum-Data-Rate-Downstream", ntohl(*(uint32_t *)ptr)))
+ if (rad_packet_add_int(pack, "ADSL-Forum", "Minimum-Data-Rate-Downstream", u_read_be32(ptr)))
return -1;
break;
case OPT_ATT_DATA_RATE_UP:
if (len != 4)
goto inval;
- if (rad_packet_add_int(pack, "ADSL-Forum", "Attainable-Data-Rate-Upstream", ntohl(*(uint32_t *)ptr)))
+ if (rad_packet_add_int(pack, "ADSL-Forum", "Attainable-Data-Rate-Upstream", u_read_be32(ptr)))
return -1;
break;
case OPT_ATT_DATA_RATE_DOWN:
if (len != 4)
goto inval;
- if (rad_packet_add_int(pack, "ADSL-Forum", "Attainable-Data-Rate-Downstream", ntohl(*(uint32_t *)ptr)))
+ if (rad_packet_add_int(pack, "ADSL-Forum", "Attainable-Data-Rate-Downstream", u_read_be32(ptr)))
return -1;
break;
case OPT_MAX_DATA_RATE_UP:
if (len != 4)
goto inval;
- if (rad_packet_add_int(pack, "ADSL-Forum", "Maximum-Data-Rate-Upstream", ntohl(*(uint32_t *)ptr)))
+ if (rad_packet_add_int(pack, "ADSL-Forum", "Maximum-Data-Rate-Upstream", u_read_be32(ptr)))
return -1;
break;
case OPT_MAX_DATA_RATE_DOWN:
if (len != 4)
goto inval;
- if (rad_packet_add_int(pack, "ADSL-Forum", "Maximum-Data-Rate-Downstream", ntohl(*(uint32_t *)ptr)))
+ if (rad_packet_add_int(pack, "ADSL-Forum", "Maximum-Data-Rate-Downstream", u_read_be32(ptr)))
return -1;
break;
case OPT_MIN_DATA_RATE_UP_LP:
if (len != 4)
goto inval;
- if (rad_packet_add_int(pack, "ADSL-Forum", "Minimum-Data-Rate-Upstream-Low-Power", ntohl(*(uint32_t *)ptr)))
+ if (rad_packet_add_int(pack, "ADSL-Forum", "Minimum-Data-Rate-Upstream-Low-Power", u_read_be32(ptr)))
return -1;
break;
case OPT_MIN_DATA_RATE_DOWN_LP:
if (len != 4)
goto inval;
- if (rad_packet_add_int(pack, "ADSL-Forum", "Minimum-Data-Rate-Downstream-Low-Power", ntohl(*(uint32_t *)ptr)))
+ if (rad_packet_add_int(pack, "ADSL-Forum", "Minimum-Data-Rate-Downstream-Low-Power", u_read_be32(ptr)))
return -1;
break;
case OPT_MAX_INTERL_DELAY_UP:
if (len != 4)
goto inval;
- if (rad_packet_add_int(pack, "ADSL-Forum", "Maximum-Interleaving-Delay-Upstream", ntohl(*(uint32_t *)ptr)))
+ if (rad_packet_add_int(pack, "ADSL-Forum", "Maximum-Interleaving-Delay-Upstream", u_read_be32(ptr)))
return -1;
break;
case OPT_ACTUAL_INTERL_DELAY_UP:
if (len != 4)
goto inval;
- if (rad_packet_add_int(pack, "ADSL-Forum", "Actual-Interleaving-Delay-Upstream", ntohl(*(uint32_t *)ptr)))
+ if (rad_packet_add_int(pack, "ADSL-Forum", "Actual-Interleaving-Delay-Upstream", u_read_be32(ptr)))
return -1;
break;
case OPT_MAX_INTER_DELAY_DOWN:
if (len != 4)
goto inval;
- if (rad_packet_add_int(pack, "ADSL-Forum", "Maximum-Interleaving-Delay-Downstream", ntohl(*(uint32_t *)ptr)))
+ if (rad_packet_add_int(pack, "ADSL-Forum", "Maximum-Interleaving-Delay-Downstream", u_read_be32(ptr)))
return -1;
break;
case OPT_ACTUAL_INTER_DELAY_DOWN:
if (len != 4)
goto inval;
- if (rad_packet_add_int(pack, "ADSL-Forum", "Actual-Interleaving-Delay-Downstream", ntohl(*(uint32_t *)ptr)))
+ if (rad_packet_add_int(pack, "ADSL-Forum", "Actual-Interleaving-Delay-Downstream", u_read_be32(ptr)))
return -1;
break;
case ACCESS_LOOP_ENCAP:
diff --git a/accel-pppd/extra/ippool.c b/accel-pppd/extra/ippool.c
index e935bb4c..28aecd95 100644
--- a/accel-pppd/extra/ippool.c
+++ b/accel-pppd/extra/ippool.c
@@ -736,10 +736,10 @@ static int session_restore(struct ap_session *ses, struct backup_mod *m)
list_for_each_entry(tag, &m->tag_list, entry) {
switch (tag->id) {
case SES_TAG_IPV4_ADDR:
- addr = *(in_addr_t *)tag->data;
+ memcpy(&addr, tag->data, sizeof(addr));
break;
case SES_TAG_IPV4_PEER_ADDR:
- peer_addr = *(in_addr_t *)tag->data;
+ memcpy(&peer_addr, tag->data, sizeof(peer_addr));
break;
}
}
diff --git a/accel-pppd/extra/ipv6pool.c b/accel-pppd/extra/ipv6pool.c
index 9a763445..05b84fe8 100644
--- a/accel-pppd/extra/ipv6pool.c
+++ b/accel-pppd/extra/ipv6pool.c
@@ -293,11 +293,18 @@ static void add_prefix(struct ip6_pool *pool, const char *_val)
/* end = start | hostmask(mask) (matches the original generator) */
memcpy(&end, &start, sizeof(end));
- if (mask > 64)
- *(uint64_t *)(end.s6_addr + 8) = htobe64(be64toh(*(uint64_t *)(end.s6_addr + 8)) | ((1llu << (128 - mask)) - 1));
+ if (mask > 64) {
+ uint64_t value;
+ memcpy(&value, end.s6_addr + 8, sizeof(value));
+ value = htobe64(be64toh(value) | ((1llu << (128 - mask)) - 1));
+ memcpy(end.s6_addr + 8, &value, sizeof(value));
+ }
else {
+ uint64_t value;
memset(end.s6_addr + 8, 0xff, 8);
- *(uint64_t *)end.s6_addr = htobe64(be64toh(*(uint64_t *)end.s6_addr) | ((1llu << (64 - mask)) - 1));
+ memcpy(&value, end.s6_addr, sizeof(value));
+ value = htobe64(be64toh(value) | ((1llu << (64 - mask)) - 1));
+ memcpy(end.s6_addr, &value, sizeof(value));
}
{
diff --git a/accel-pppd/ifcfg.c b/accel-pppd/ifcfg.c
index 4e4a381a..66f5cc6b 100644
--- a/accel-pppd/ifcfg.c
+++ b/accel-pppd/ifcfg.c
@@ -225,7 +225,7 @@ void __export ap_session_ifdown(struct ap_session *ses)
if (ses->ctrl->ppp) {
ifr6.ifr6_addr.s6_addr32[0] = htonl(0xfe800000);
- *(uint64_t *)(ifr6.ifr6_addr.s6_addr + 8) = ses->ipv6->intf_id;
+ memcpy(ifr6.ifr6_addr.s6_addr + 8, &ses->ipv6->intf_id, sizeof(ses->ipv6->intf_id));
ifr6.ifr6_prefixlen = 64;
net->sock6_ioctl(SIOCDIFADDR, &ifr6);
}
@@ -376,4 +376,4 @@ int __export ap_session_vrf(struct ap_session *ses, const char *vrf_name, int le
return 0;
}
-#endif \ No newline at end of file
+#endif
diff --git a/accel-pppd/ipdb.c b/accel-pppd/ipdb.c
index 8fc08063..264f67b3 100644
--- a/accel-pppd/ipdb.c
+++ b/accel-pppd/ipdb.c
@@ -75,18 +75,23 @@ void __export ipdb_put_ipv6_prefix(struct ap_session *ses, struct ipv6db_prefix_
void __export build_ip6_addr(struct ipv6db_addr_t *a, uint64_t intf_id, struct in6_addr *addr)
{
+ uint64_t value;
+
memcpy(addr, &a->addr, sizeof(*addr));
if (a->prefix_len == 128)
return;
if (a->prefix_len <= 64)
- *(uint64_t *)(addr->s6_addr + 8) = intf_id;
- else
+ memcpy(addr->s6_addr + 8, &intf_id, sizeof(intf_id));
+ else {
/* prefix_len 65..127 means a shift of up to 63 bits: a plain
* int literal 1 is undefined behavior for shifts >= 31, so the
* host bits mask must be built from a 64-bit constant */
- *(uint64_t *)(addr->s6_addr + 8) |= intf_id & htobe64((UINT64_C(1) << (128 - a->prefix_len)) - 1);
+ memcpy(&value, addr->s6_addr + 8, sizeof(value));
+ value |= intf_id & htobe64((UINT64_C(1) << (128 - a->prefix_len)) - 1);
+ memcpy(addr->s6_addr + 8, &value, sizeof(value));
+ }
}
diff --git a/accel-pppd/ipv6/dhcpv6.c b/accel-pppd/ipv6/dhcpv6.c
index 4a80bdb9..a0b159cf 100644
--- a/accel-pppd/ipv6/dhcpv6.c
+++ b/accel-pppd/ipv6/dhcpv6.c
@@ -23,6 +23,7 @@
#include "ipv6_dns.h"
#include "events.h"
#include "iputils.h"
+#include "utils.h"
#include "dhcpv6.h"
@@ -222,25 +223,28 @@ static void insert_oro(struct dhcpv6_packet *reply, struct dhcpv6_option *opt)
{
struct dhcpv6_option *opt1;
int i, j, dns_count;
- uint16_t *ptr;
- struct in6_addr addr, *addr_ptr;
+ uint8_t *ptr;
+ uint16_t code;
+ struct in6_addr addr;
+ uint8_t *addr_ptr;
struct in6_addr dns[MAX_DNS_COUNT];
- for (i = ntohs(opt->hdr->len) / 2, ptr = (uint16_t *)opt->hdr->data; i; i--, ptr++) {
- if (ntohs(*ptr) == D6_OPTION_DNS_SERVERS) {
+ for (i = ntohs(opt->hdr->len) / 2, ptr = opt->hdr->data; i; i--, ptr += sizeof(code)) {
+ code = u_read_be16(ptr);
+ if (code == D6_OPTION_DNS_SERVERS) {
dns_count = ipv6_dns_get(reply->ses, conf_dns, conf_dns_count,
dns, MAX_DNS_COUNT);
if (dns_count) {
opt1 = dhcpv6_option_alloc(reply, D6_OPTION_DNS_SERVERS, dns_count * sizeof(addr));
- for (j = 0, addr_ptr = (struct in6_addr *)opt1->hdr->data; j < dns_count; j++, addr_ptr++)
+ for (j = 0, addr_ptr = opt1->hdr->data; j < dns_count; j++, addr_ptr += sizeof(addr))
memcpy(addr_ptr, dns + j, sizeof(addr));
}
- } else if (ntohs(*ptr) == D6_OPTION_DOMAIN_LIST) {
+ } else if (code == D6_OPTION_DOMAIN_LIST) {
if (conf_dnssl_size) {
opt1 = dhcpv6_option_alloc(reply, D6_OPTION_DOMAIN_LIST, conf_dnssl_size);
memcpy(opt1->hdr->data, conf_dnssl, conf_dnssl_size);
}
- } else if (ntohs(*ptr) == D6_OPTION_AFTR_NAME) {
+ } else if (code == D6_OPTION_AFTR_NAME) {
if (conf_aftr_gw_size) {
opt1 = dhcpv6_option_alloc(reply, D6_OPTION_AFTR_NAME, conf_aftr_gw_size);
memcpy(opt1->hdr->data, conf_aftr_gw, conf_aftr_gw_size);
diff --git a/accel-pppd/ipv6/dhcpv6_packet.c b/accel-pppd/ipv6/dhcpv6_packet.c
index c0c7bc81..f1c168b6 100644
--- a/accel-pppd/ipv6/dhcpv6_packet.c
+++ b/accel-pppd/ipv6/dhcpv6_packet.c
@@ -4,6 +4,7 @@
#include "log.h"
#include "memdebug.h"
+#include "utils.h"
#include "dhcpv6.h"
@@ -13,7 +14,8 @@ struct dict_option {
int code;
const char *name;
int recv;
- int len;
+ int min_len;
+ int nested;
void (*print)(struct dhcpv6_option *, void (*)(const char *fmt, ...));
};
@@ -34,30 +36,30 @@ static void print_ia_prefix(struct dhcpv6_option *opt, void (*print)(const char
static void print_aftr_gw(struct dhcpv6_option *opt, void (*print)(const char *fmt, ...));
static struct dict_option known_options[] = {
- { D6_OPTION_CLIENTID, "Client-ID", 1, 0, print_clientid },
- { D6_OPTION_SERVERID, "Server-ID", 0, 0, print_clientid },
- { D6_OPTION_IA_NA, "IA-NA", 1, sizeof(struct dhcpv6_opt_ia_na), print_ia_na },
- { D6_OPTION_IA_TA, "IA-TA", 1, sizeof(struct dhcpv6_opt_ia_ta), print_ia_ta },
- { D6_OPTION_IAADDR, "IA-Addr", 1, sizeof(struct dhcpv6_opt_ia_addr), print_ia_addr },
- { D6_OPTION_ORO, "Option-Request", 1, 0, print_oro },
- { D6_OPTION_PREFERENCE, "Preference", 0, 0, print_uint8 },
- { D6_OPTION_ELAPSED_TIME, "Elapsed-Time", 1, 0, print_time },
- { D6_OPTION_RELAY_MSG, "Relay-Message", 1, 0 },
- { D6_OPTION_AUTH, "Auth", 1, 0 },
- { D6_OPTION_PREFERENCE, "Server-Unicast", 0, 0, print_ipv6addr },
- { D6_OPTION_STATUS_CODE, "Status", 0, 0, print_status },
- { D6_OPTION_RAPID_COMMIT, "Rapid-Commit", 1, 0 },
- { D6_OPTION_USER_CLASS, "User-Class", 1, 0 },
- { D6_OPTION_VENDOR_CLASS, "Vendor-Class", 1, 0, print_hex_array },
- { D6_OPTION_VENDOR_SPECIFIC, "Vendor-Specific", 1, 0, print_hex_array },
- { D6_OPTION_INTERFACE_ID, "Interface-ID", 1, 0, print_hex_array },
- { D6_OPTION_RECONF_MSG, "Reconfigure", 0, 0, print_reconf },
- { D6_OPTION_RECONF_ACCEPT, "Reconfigure-Accept", 1, 0 },
- { D6_OPTION_DNS_SERVERS, "DNS", 1, 0, print_ipv6addr_array },
- { D6_OPTION_DOMAIN_LIST, "DNSSL", 1, 0, print_dnssl },
- { D6_OPTION_IA_PD, "IA-PD", 1, sizeof(struct dhcpv6_opt_ia_na), print_ia_na },
- { D6_OPTION_IAPREFIX, "IA-Prefix", 1, sizeof(struct dhcpv6_opt_ia_prefix), print_ia_prefix },
- { D6_OPTION_AFTR_NAME, "AFTR-Name", 1, 0, print_aftr_gw },
+ { D6_OPTION_CLIENTID, "Client-ID", 1, sizeof(uint16_t), 0, print_clientid },
+ { D6_OPTION_SERVERID, "Server-ID", 0, sizeof(uint16_t), 0, print_clientid },
+ { D6_OPTION_IA_NA, "IA-NA", 1, sizeof(struct dhcpv6_opt_ia_na) - sizeof(struct dhcpv6_opt_hdr), 1, print_ia_na },
+ { D6_OPTION_IA_TA, "IA-TA", 1, sizeof(struct dhcpv6_opt_ia_ta) - sizeof(struct dhcpv6_opt_hdr), 1, print_ia_ta },
+ { D6_OPTION_IAADDR, "IA-Addr", 1, sizeof(struct dhcpv6_opt_ia_addr) - sizeof(struct dhcpv6_opt_hdr), 1, print_ia_addr },
+ { D6_OPTION_ORO, "Option-Request", 1, 0, 0, print_oro },
+ { D6_OPTION_PREFERENCE, "Preference", 0, sizeof(uint8_t), 0, print_uint8 },
+ { D6_OPTION_ELAPSED_TIME, "Elapsed-Time", 1, sizeof(uint16_t), 0, print_time },
+ { D6_OPTION_RELAY_MSG, "Relay-Message", 1, sizeof(struct dhcpv6_msg_hdr), 0 },
+ { D6_OPTION_AUTH, "Auth", 1, 0, 0 },
+ { D6_OPTION_UNICAST, "Server-Unicast", 0, sizeof(struct in6_addr), 0, print_ipv6addr },
+ { D6_OPTION_STATUS_CODE, "Status", 0, sizeof(uint16_t), 0, print_status },
+ { D6_OPTION_RAPID_COMMIT, "Rapid-Commit", 1, 0, 0 },
+ { D6_OPTION_USER_CLASS, "User-Class", 1, 0, 0 },
+ { D6_OPTION_VENDOR_CLASS, "Vendor-Class", 1, 0, 0, print_hex_array },
+ { D6_OPTION_VENDOR_SPECIFIC, "Vendor-Specific", 1, 0, 0, print_hex_array },
+ { D6_OPTION_INTERFACE_ID, "Interface-ID", 1, 0, 0, print_hex_array },
+ { D6_OPTION_RECONF_MSG, "Reconfigure", 0, sizeof(uint8_t), 0, print_reconf },
+ { D6_OPTION_RECONF_ACCEPT, "Reconfigure-Accept", 1, 0, 0 },
+ { D6_OPTION_DNS_SERVERS, "DNS", 1, 0, 0, print_ipv6addr_array },
+ { D6_OPTION_DOMAIN_LIST, "DNSSL", 1, 0, 0, print_dnssl },
+ { D6_OPTION_IA_PD, "IA-PD", 1, sizeof(struct dhcpv6_opt_ia_na) - sizeof(struct dhcpv6_opt_hdr), 1, print_ia_na },
+ { D6_OPTION_IAPREFIX, "IA-Prefix", 1, sizeof(struct dhcpv6_opt_ia_prefix) - sizeof(struct dhcpv6_opt_hdr), 1, print_ia_prefix },
+ { D6_OPTION_AFTR_NAME, "AFTR-Name", 1, 0, 0, print_aftr_gw },
{ 0 }
};
@@ -89,9 +91,14 @@ static void *parse_option(void *ptr, void *endptr, struct list_head *opt_list)
break;
}
- if (dopt->len) {
+ if (ntohs(opth->len) < dopt->min_len) {
+ log_warn("dhcpv6: invalid packet received\n");
+ return NULL;
+ }
+
+ if (dopt->nested) {
endptr = ptr + sizeof(*opth) + ntohs(opth->len);
- ptr += dopt->len;
+ ptr += sizeof(*opth) + dopt->min_len;
while (ptr < endptr) {
ptr = parse_option(ptr, endptr, &opt->opt_list);
if (!ptr)
@@ -109,7 +116,8 @@ struct dhcpv6_packet *dhcpv6_packet_parse(const void *buf, size_t size)
struct dhcpv6_opt_hdr *opth;
struct dhcpv6_relay *rel;
struct dhcpv6_relay_hdr *rhdr;
- void *ptr, *endptr;
+ struct dhcpv6_msg_hdr *inner_hdr;
+ void *ptr, *endptr, *relay_end, *inner_end;
if (size < sizeof(struct dhcpv6_msg_hdr)) {
if (conf_verbose)
@@ -133,8 +141,6 @@ struct dhcpv6_packet *dhcpv6_packet_parse(const void *buf, size_t size)
endptr = ((void *)pkt->hdr) + size;
while (pkt->hdr->type == D6_RELAY_FORW) {
- struct dhcpv6_msg_hdr *prev_hdr = pkt->hdr;
-
rhdr = (struct dhcpv6_relay_hdr *)pkt->hdr;
if (((void *)rhdr) + sizeof(*rhdr) > endptr) {
log_warn("dhcpv6: invalid packet received\n");
@@ -153,27 +159,37 @@ struct dhcpv6_packet *dhcpv6_packet_parse(const void *buf, size_t size)
list_add_tail(&rel->entry, &pkt->relay_list);
+ inner_hdr = NULL;
+ inner_end = NULL;
+ relay_end = endptr;
ptr = rhdr->data;
- while (ptr < endptr) {
+ while (ptr < relay_end) {
opth = ptr;
- if (ptr + sizeof(*opth) > endptr ||
- ptr + sizeof(*opth) + ntohs(opth->len) > endptr) {
+ if (ptr + sizeof(*opth) > relay_end ||
+ ptr + sizeof(*opth) + ntohs(opth->len) > relay_end) {
log_warn("dhcpv6: invalid packet received\n");
goto error;
}
if (opth->code == htons(D6_OPTION_RELAY_MSG)) {
- pkt->hdr = (struct dhcpv6_msg_hdr *)opth->data;
- endptr = opth->data + ntohs(opth->len);
+ if (inner_hdr || ntohs(opth->len) < sizeof(*inner_hdr)) {
+ log_warn("dhcpv6: invalid packet received\n");
+ goto error;
+ }
+ inner_hdr = (struct dhcpv6_msg_hdr *)opth->data;
+ inner_end = opth->data + ntohs(opth->len);
}
ptr += sizeof(*opth) + ntohs(opth->len);
}
- if (pkt->hdr == prev_hdr) {
+ if (!inner_hdr) {
log_warn("dhcpv6: invalid packet received\n");
goto error;
}
+
+ pkt->hdr = inner_hdr;
+ endptr = inner_end;
}
ptr = pkt->hdr->data;
@@ -462,26 +478,28 @@ static void print_ia_addr(struct dhcpv6_option *opt, void (*print)(const char *f
static void print_oro(struct dhcpv6_option *opt, void (*print)(const char *fmt, ...))
{
- uint16_t *ptr = (uint16_t *)opt->hdr->data;
- uint16_t *end_ptr = ptr + ntohs(opt->hdr->len)/2;
+ uint8_t *ptr = opt->hdr->data;
+ uint8_t *end_ptr = ptr + ntohs(opt->hdr->len) / 2 * sizeof(uint16_t);
struct dict_option *dopt;
+ uint16_t code;
int f = 0;
- for (; ptr < end_ptr; ptr++) {
+ for (; ptr < end_ptr; ptr += sizeof(uint16_t)) {
if (f)
print(",");
else
print(" ");
+ code = u_read_be16(ptr);
for (dopt = known_options; dopt->code; dopt++) {
- if (ntohs(*ptr) == dopt->code)
+ if (code == dopt->code)
break;
}
if (dopt->code)
print("%s", dopt->name);
else
- print("%i", ntohs(*ptr));
+ print("%i", code);
f = 1;
}
@@ -506,13 +524,10 @@ static void print_uint8(struct dhcpv6_option *opt, void (*print)(const char *fmt
static void print_time(struct dhcpv6_option *opt, void (*print)(const char *fmt, ...))
{
- uint16_t val;
-
- if (ntohs(opt->hdr->len) < sizeof(val))
+ if (ntohs(opt->hdr->len) < sizeof(uint16_t))
return;
- memcpy(&val, opt->hdr->data, sizeof(val));
- print(" %u", ntohs(val));
+ print(" %u", u_read_be16(opt->hdr->data));
}
static void print_ipv6addr(struct dhcpv6_option *opt, void (*print)(const char *fmt, ...))
@@ -529,9 +544,9 @@ static void print_ipv6addr_array(struct dhcpv6_option *opt, void (*print)(const
char str[INET6_ADDRSTRLEN];
int i;
int f = 0;
- struct in6_addr *addr = (struct in6_addr *)opt->hdr->data;
+ uint8_t *addr = opt->hdr->data;
- for (i = ntohs(opt->hdr->len) / sizeof(*addr); i; i--, addr++) {
+ for (i = ntohs(opt->hdr->len) / sizeof(struct in6_addr); i; i--, addr += sizeof(struct in6_addr)) {
inet_ntop(AF_INET6, addr, str, sizeof(str));
print("%c%s", f ? ',' : ' ', str);
f = 1;
diff --git a/accel-pppd/memdebug.c b/accel-pppd/memdebug.c
index 5353e572..b3488aaa 100644
--- a/accel-pppd/memdebug.c
+++ b/accel-pppd/memdebug.c
@@ -42,6 +42,19 @@ struct mem_t
static LIST_HEAD(mem_list);
static spinlock_t mem_list_lock;
+static uint64_t get_tail_magic(const struct mem_t *mem)
+{
+ uint64_t magic;
+
+ memcpy(&magic, mem->data + mem->size, sizeof(magic));
+ return magic;
+}
+
+static void set_tail_magic(struct mem_t *mem)
+{
+ memcpy(mem->data + mem->size, &mem->magic2, sizeof(mem->magic2));
+}
+
static struct mem_t *_md_malloc(size_t size, const char *fname, int line)
{
struct mem_t *mem = malloc(sizeof(*mem) + size + 8);
@@ -54,7 +67,7 @@ static struct mem_t *_md_malloc(size_t size, const char *fname, int line)
mem->size = size;
mem->magic1 = MAGIC1;
mem->magic2 = (uint64_t)random() * (uint64_t)random();
- *(uint64_t*)(mem->data + size) = mem->magic2;
+ set_tail_magic(mem);
spin_lock(&mem_list_lock);
list_add_tail(&mem->entry, &mem_list);
@@ -84,7 +97,7 @@ void __export md_free(void *ptr, const char *fname, int line)
abort();
}
- if (mem->magic2 != *(uint64_t*)(mem->data + mem->size)) {
+ if (mem->magic2 != get_tail_magic(mem)) {
printf("memory corruption:\nmalloc(%zu) at %s:%i\nfree at %s:%i\n",
mem->size, mem->fname, mem->line, fname, line);
abort();
@@ -113,7 +126,7 @@ void __export *md_realloc(void *ptr, size_t size, const char *fname, int line)
abort();
}
- if (mem->magic2 != *(uint64_t*)(mem->data + mem->size)) {
+ if (mem->magic2 != get_tail_magic(mem)) {
printf("memory corruption:\nmalloc(%zu) at %s:%i\nfree at %s:%i\n",
mem->size, mem->fname, mem->line, fname, line);
abort();
@@ -217,7 +230,7 @@ static void siginfo2(int num)
spin_lock(&mem_list_lock);
list_for_each_entry(mem, &mem_list, entry) {
- if (mem->magic1 != MAGIC1 || mem->magic2 != *(uint64_t*)(mem->data + mem->size))
+ if (mem->magic1 != MAGIC1 || mem->magic2 != get_tail_magic(mem))
printf("%s:%i %lu\n", mem->fname, mem->line, (long unsigned)mem->size);
}
spin_unlock(&mem_list_lock);
@@ -233,7 +246,7 @@ void __export md_check(void *ptr)
if (mem->magic1 != MAGIC1)
abort();
- if (mem->magic2 != *(uint64_t*)(mem->data + mem->size))
+ if (mem->magic2 != get_tail_magic(mem))
abort();
}
diff --git a/accel-pppd/ppp/ccp_mppe.c b/accel-pppd/ppp/ccp_mppe.c
index cb41c0da..5042c8a0 100644
--- a/accel-pppd/ppp/ccp_mppe.c
+++ b/accel-pppd/ppp/ccp_mppe.c
@@ -10,6 +10,7 @@
#include "ppp_ccp.h"
#include "log.h"
#include "events.h"
+#include "utils.h"
#include "memdebug.h"
@@ -106,7 +107,7 @@ static int setup_mppe_key(int fd, int transmit, uint8_t *key)
memset(buf, 0, sizeof(buf));
buf[0] = CI_MPPE;
buf[1] = 6;
- *(uint32_t*)(buf + 2) = htonl(MPPE_S | MPPE_H);
+ u_write_be32(buf + 2, MPPE_S | MPPE_H);
if (key)
memcpy(buf + 6, key, 16);
diff --git a/accel-pppd/ppp/ipv6cp_opt_intfid.c b/accel-pppd/ppp/ipv6cp_opt_intfid.c
index cb33f024..5de88932 100644
--- a/accel-pppd/ppp/ipv6cp_opt_intfid.c
+++ b/accel-pppd/ppp/ipv6cp_opt_intfid.c
@@ -284,12 +284,14 @@ static void ipaddr_print(void (*print)(const char *fmt,...), struct ipv6cp_optio
{
struct ipaddr_option_t *ipaddr_opt = container_of(opt, typeof(*ipaddr_opt), opt);
struct ipv6cp_opt64_t *opt64 = (struct ipv6cp_opt64_t *)ptr;
- struct in6_addr a;
+ struct in6_addr a = {};
+ uint64_t intf_id;
if (ptr)
- *(uint64_t *)(a.s6_addr + 8) = opt64->val;
+ intf_id = opt64->val;
else
- *(uint64_t *)(a.s6_addr + 8) = ipaddr_opt->ppp->ses.ipv6->intf_id;
+ intf_id = ipaddr_opt->ppp->ses.ipv6->intf_id;
+ memcpy(a.s6_addr + 8, &intf_id, sizeof(intf_id));
print("<addr %x:%x:%x:%x>", ntohs(a.s6_addr16[4]), ntohs(a.s6_addr16[5]), ntohs(a.s6_addr16[6]), ntohs(a.s6_addr16[7]));
}
@@ -376,4 +378,3 @@ static void init()
}
DEFINE_INIT(5, init);
-
diff --git a/accel-pppd/ppp/ppp_ccp.c b/accel-pppd/ppp/ppp_ccp.c
index f9e05e89..2082ca3f 100644
--- a/accel-pppd/ppp/ppp_ccp.c
+++ b/accel-pppd/ppp/ppp_ccp.c
@@ -387,10 +387,18 @@ static int ccp_recv_conf_req(struct ppp_ccp_t *ccp, uint8_t *data, int size)
ccp->ropt_len = size;
while (size > 0) {
+ if (size < sizeof(*hdr)) {
+ log_ppp_warn("CCP: ConfReq: truncated option header (%i bytes left)\n", size);
+ return CCP_OPT_FAIL;
+ }
+
hdr = (struct ccp_opt_hdr_t *)data;
- if (!hdr->len || hdr->len > size)
- break;
+ if (hdr->len < sizeof(*hdr) || hdr->len > size) {
+ log_ppp_warn("CCP: ConfReq: invalid length %i of option %i (%i bytes left)\n",
+ hdr->len, hdr->id, size);
+ return CCP_OPT_FAIL;
+ }
ropt = _malloc(sizeof(*ropt));
memset(ropt, 0, sizeof(*ropt));
@@ -482,10 +490,17 @@ static int ccp_recv_conf_rej(struct ppp_ccp_t *ccp, uint8_t *data, int size)
}*/
while (size > 0) {
+ if (size < sizeof(*hdr)) {
+ res = -1;
+ break;
+ }
+
hdr = (struct ccp_opt_hdr_t *)data;
- if (!hdr->len || hdr->len > size)
+ if (hdr->len < sizeof(*hdr) || hdr->len > size) {
+ res = -1;
break;
+ }
list_for_each_entry(lopt, &ccp->options, entry) {
if (lopt->id == hdr->id) {
@@ -523,10 +538,17 @@ static int ccp_recv_conf_nak(struct ppp_ccp_t *ccp, uint8_t *data, int size)
}*/
while (size > 0) {
+ if (size < sizeof(*hdr)) {
+ res = -1;
+ break;
+ }
+
hdr = (struct ccp_opt_hdr_t *)data;
- if (!hdr->len || hdr->len > size)
+ if (hdr->len < sizeof(*hdr) || hdr->len > size) {
+ res = -1;
break;
+ }
list_for_each_entry(lopt, &ccp->options, entry) {
if (lopt->id == hdr->id) {
@@ -566,10 +588,17 @@ static int ccp_recv_conf_ack(struct ppp_ccp_t *ccp, uint8_t *data, int size)
}*/
while (size > 0) {
+ if (size < sizeof(*hdr)) {
+ res = -1;
+ break;
+ }
+
hdr = (struct ccp_opt_hdr_t *)data;
- if (!hdr->len || hdr->len > size)
+ if (hdr->len < sizeof(*hdr) || hdr->len > size) {
+ res = -1;
break;
+ }
list_for_each_entry(lopt, &ccp->options, entry) {
if (lopt->id == hdr->id) {
@@ -647,7 +676,7 @@ static void ccp_recv(struct ppp_handler_t*h)
}
hdr = (struct ccp_hdr_t *)ccp->ppp->buf;
- if (ntohs(hdr->len) < PPP_HEADERLEN) {
+ if (ntohs(hdr->len) < PPP_HEADERLEN || ntohs(hdr->len) > ccp->ppp->buf_size - 2) {
log_ppp_warn("CCP: short packet received\n");
return;
}
@@ -695,8 +724,10 @@ static void ccp_recv(struct ppp_handler_t*h)
ppp_fsm_recv_conf_ack(&ccp->fsm);
break;
case CONFNAK:
- ccp_recv_conf_nak(ccp, (uint8_t*)(hdr + 1), ntohs(hdr->len) - PPP_HDRLEN);
- ppp_fsm_recv_conf_rej(&ccp->fsm);
+ if (ccp_recv_conf_nak(ccp, (uint8_t*)(hdr + 1), ntohs(hdr->len) - PPP_HDRLEN))
+ ap_session_terminate(&ccp->ppp->ses, TERM_USER_ERROR, 0);
+ else
+ ppp_fsm_recv_conf_rej(&ccp->fsm);
break;
case CONFREJ:
if (ccp_recv_conf_rej(ccp, (uint8_t*)(hdr + 1),ntohs(hdr->len) - PPP_HDRLEN))
diff --git a/accel-pppd/ppp/ppp_ipcp.c b/accel-pppd/ppp/ppp_ipcp.c
index 416fba93..2f75542a 100644
--- a/accel-pppd/ppp/ppp_ipcp.c
+++ b/accel-pppd/ppp/ppp_ipcp.c
@@ -391,10 +391,18 @@ static int ipcp_recv_conf_req(struct ppp_ipcp_t *ipcp, uint8_t *data, int size)
ipcp->ropt_len = size;
while (size > 0) {
+ if (size < sizeof(*hdr)) {
+ log_ppp_warn("IPCP: ConfReq: truncated option header (%i bytes left)\n", size);
+ return IPCP_OPT_FAIL;
+ }
+
hdr = (struct ipcp_opt_hdr_t *)data;
- if (!hdr->len || hdr->len > size)
- break;
+ if (hdr->len < sizeof(*hdr) || hdr->len > size) {
+ log_ppp_warn("IPCP: ConfReq: invalid length %i of option %i (%i bytes left)\n",
+ hdr->len, hdr->id, size);
+ return IPCP_OPT_FAIL;
+ }
ropt = _malloc(sizeof(*ropt));
memset(ropt, 0, sizeof(*ropt));
@@ -503,10 +511,17 @@ static int ipcp_recv_conf_rej(struct ppp_ipcp_t *ipcp, uint8_t *data, int size)
}*/
while (size > 0) {
+ if (size < sizeof(*hdr)) {
+ res = -1;
+ break;
+ }
+
hdr = (struct ipcp_opt_hdr_t *)data;
- if (!hdr->len || hdr->len > size)
+ if (hdr->len < sizeof(*hdr) || hdr->len > size) {
+ res = -1;
break;
+ }
list_for_each_entry(lopt, &ipcp->options, entry) {
if (lopt->id == hdr->id) {
@@ -544,10 +559,17 @@ static int ipcp_recv_conf_nak(struct ppp_ipcp_t *ipcp, uint8_t *data, int size)
}*/
while (size > 0) {
+ if (size < sizeof(*hdr)) {
+ res = -1;
+ break;
+ }
+
hdr = (struct ipcp_opt_hdr_t *)data;
- if (!hdr->len || hdr->len > size)
+ if (hdr->len < sizeof(*hdr) || hdr->len > size) {
+ res = -1;
break;
+ }
list_for_each_entry(lopt, &ipcp->options, entry) {
if (lopt->id == hdr->id) {
@@ -587,10 +609,17 @@ static int ipcp_recv_conf_ack(struct ppp_ipcp_t *ipcp, uint8_t *data, int size)
}*/
while (size > 0) {
+ if (size < sizeof(*hdr)) {
+ res = -1;
+ break;
+ }
+
hdr = (struct ipcp_opt_hdr_t *)data;
- if (!hdr->len || hdr->len > size)
+ if (hdr->len < sizeof(*hdr) || hdr->len > size) {
+ res = -1;
break;
+ }
list_for_each_entry(lopt, &ipcp->options, entry) {
if (lopt->id == hdr->id) {
@@ -671,7 +700,7 @@ static void ipcp_recv(struct ppp_handler_t*h)
}
hdr = (struct ipcp_hdr_t *)ipcp->ppp->buf;
- if (ntohs(hdr->len) < PPP_HEADERLEN) {
+ if (ntohs(hdr->len) < PPP_HEADERLEN || ntohs(hdr->len) > ipcp->ppp->buf_size - 2) {
log_ppp_warn("IPCP: short packet received\n");
return;
}
@@ -725,8 +754,10 @@ static void ipcp_recv(struct ppp_handler_t*h)
ppp_fsm_recv_conf_ack(&ipcp->fsm);
break;
case CONFNAK:
- ipcp_recv_conf_nak(ipcp,(uint8_t*)(hdr + 1), ntohs(hdr->len) - PPP_HDRLEN);
- ppp_fsm_recv_conf_rej(&ipcp->fsm);
+ if (ipcp_recv_conf_nak(ipcp,(uint8_t*)(hdr + 1), ntohs(hdr->len) - PPP_HDRLEN))
+ ap_session_terminate(&ipcp->ppp->ses, TERM_USER_ERROR, 0);
+ else
+ ppp_fsm_recv_conf_rej(&ipcp->fsm);
break;
case CONFREJ:
if (ipcp_recv_conf_rej(ipcp, (uint8_t*)(hdr + 1), ntohs(hdr->len) - PPP_HDRLEN))
diff --git a/accel-pppd/ppp/ppp_ipv6cp.c b/accel-pppd/ppp/ppp_ipv6cp.c
index 7f278daa..370f1d55 100644
--- a/accel-pppd/ppp/ppp_ipv6cp.c
+++ b/accel-pppd/ppp/ppp_ipv6cp.c
@@ -395,10 +395,18 @@ static int ipv6cp_recv_conf_req(struct ppp_ipv6cp_t *ipv6cp, uint8_t *data, int
ipv6cp->ropt_len = size;
while (size > 0) {
+ if (size < sizeof(*hdr)) {
+ log_ppp_warn("IPV6CP: ConfReq: truncated option header (%i bytes left)\n", size);
+ return IPV6CP_OPT_FAIL;
+ }
+
hdr = (struct ipv6cp_opt_hdr_t *)data;
- if (!hdr->len || hdr->len > size)
- break;
+ if (hdr->len < sizeof(*hdr) || hdr->len > size) {
+ log_ppp_warn("IPV6CP: ConfReq: invalid length %i of option %i (%i bytes left)\n",
+ hdr->len, hdr->id, size);
+ return IPV6CP_OPT_FAIL;
+ }
ropt = _malloc(sizeof(*ropt));
memset(ropt, 0, sizeof(*ropt));
@@ -507,10 +515,17 @@ static int ipv6cp_recv_conf_rej(struct ppp_ipv6cp_t *ipv6cp, uint8_t *data, int
}*/
while (size > 0) {
+ if (size < sizeof(*hdr)) {
+ res = -1;
+ break;
+ }
+
hdr = (struct ipv6cp_opt_hdr_t *)data;
- if (!hdr->len || hdr->len > size)
+ if (hdr->len < sizeof(*hdr) || hdr->len > size) {
+ res = -1;
break;
+ }
list_for_each_entry(lopt, &ipv6cp->options, entry) {
if (lopt->id == hdr->id) {
@@ -548,10 +563,17 @@ static int ipv6cp_recv_conf_nak(struct ppp_ipv6cp_t *ipv6cp, uint8_t *data, int
}*/
while (size > 0) {
+ if (size < sizeof(*hdr)) {
+ res = -1;
+ break;
+ }
+
hdr = (struct ipv6cp_opt_hdr_t *)data;
- if (!hdr->len || hdr->len > size)
+ if (hdr->len < sizeof(*hdr) || hdr->len > size) {
+ res = -1;
break;
+ }
list_for_each_entry(lopt, &ipv6cp->options, entry) {
if (lopt->id == hdr->id) {
@@ -591,10 +613,17 @@ static int ipv6cp_recv_conf_ack(struct ppp_ipv6cp_t *ipv6cp, uint8_t *data, int
}*/
while (size > 0) {
+ if (size < sizeof(*hdr)) {
+ res = -1;
+ break;
+ }
+
hdr = (struct ipv6cp_opt_hdr_t *)data;
- if (!hdr->len || hdr->len > size)
+ if (hdr->len < sizeof(*hdr) || hdr->len > size) {
+ res = -1;
break;
+ }
list_for_each_entry(lopt, &ipv6cp->options, entry) {
if (lopt->id == hdr->id) {
@@ -675,7 +704,7 @@ static void ipv6cp_recv(struct ppp_handler_t*h)
}
hdr = (struct ipv6cp_hdr_t *)ipv6cp->ppp->buf;
- if (ntohs(hdr->len) < PPP_HEADERLEN) {
+ if (ntohs(hdr->len) < PPP_HEADERLEN || ntohs(hdr->len) > ipv6cp->ppp->buf_size - 2) {
log_ppp_warn("IPV6CP: short packet received\n");
return;
}
@@ -729,8 +758,10 @@ static void ipv6cp_recv(struct ppp_handler_t*h)
ppp_fsm_recv_conf_ack(&ipv6cp->fsm);
break;
case CONFNAK:
- ipv6cp_recv_conf_nak(ipv6cp,(uint8_t*)(hdr + 1), ntohs(hdr->len) - PPP_HDRLEN);
- ppp_fsm_recv_conf_rej(&ipv6cp->fsm);
+ if (ipv6cp_recv_conf_nak(ipv6cp,(uint8_t*)(hdr + 1), ntohs(hdr->len) - PPP_HDRLEN))
+ ap_session_terminate(&ipv6cp->ppp->ses, TERM_USER_ERROR, 0);
+ else
+ ppp_fsm_recv_conf_rej(&ipv6cp->fsm);
break;
case CONFREJ:
if (ipv6cp_recv_conf_rej(ipv6cp, (uint8_t*)(hdr + 1), ntohs(hdr->len) - PPP_HDRLEN))
diff --git a/accel-pppd/ppp/ppp_lcp.c b/accel-pppd/ppp/ppp_lcp.c
index ed085b3b..2424ca94 100644
--- a/accel-pppd/ppp/ppp_lcp.c
+++ b/accel-pppd/ppp/ppp_lcp.c
@@ -370,10 +370,18 @@ static int lcp_recv_conf_req(struct ppp_lcp_t *lcp, uint8_t *data, int size)
lcp->ropt_len = size;
while (size > 0) {
+ if (size < sizeof(*hdr)) {
+ log_ppp_warn("LCP: ConfReq: truncated option header (%i bytes left)\n", size);
+ return LCP_OPT_FAIL;
+ }
+
hdr = (struct lcp_opt_hdr_t *)data;
- if (!hdr->len || hdr->len > size)
- break;
+ if (hdr->len < sizeof(*hdr) || hdr->len > size) {
+ log_ppp_warn("LCP: ConfReq: invalid length %i of option %i (%i bytes left)\n",
+ hdr->len, hdr->id, size);
+ return LCP_OPT_FAIL;
+ }
ropt = _malloc(sizeof(*ropt));
memset(ropt, 0, sizeof(*ropt));
@@ -462,10 +470,17 @@ static int lcp_recv_conf_rej(struct ppp_lcp_t *lcp, uint8_t *data, int size)
}
while (size > 0) {
+ if (size < sizeof(*hdr)) {
+ res = -1;
+ break;
+ }
+
hdr = (struct lcp_opt_hdr_t *)data;
- if (!hdr->len || hdr->len > size)
+ if (hdr->len < sizeof(*hdr) || hdr->len > size) {
+ res = -1;
break;
+ }
list_for_each_entry(lopt, &lcp->options, entry) {
if (lopt->id == hdr->id) {
@@ -507,10 +522,17 @@ static int lcp_recv_conf_nak(struct ppp_lcp_t *lcp, uint8_t *data, int size)
}
while (size > 0) {
+ if (size < sizeof(*hdr)) {
+ res = -1;
+ break;
+ }
+
hdr = (struct lcp_opt_hdr_t *)data;
- if (!hdr->len || hdr->len > size)
+ if (hdr->len < sizeof(*hdr) || hdr->len > size) {
+ res = -1;
break;
+ }
list_for_each_entry(lopt,&lcp->options,entry) {
if (lopt->id == hdr->id) {
@@ -550,10 +572,17 @@ static int lcp_recv_conf_ack(struct ppp_lcp_t *lcp, uint8_t *data, int size)
}
while (size > 0) {
+ if (size < sizeof(*hdr)) {
+ res = -1;
+ break;
+ }
+
hdr = (struct lcp_opt_hdr_t *)data;
- if (!hdr->len || hdr->len > size)
+ if (hdr->len < sizeof(*hdr) || hdr->len > size) {
+ res = -1;
break;
+ }
list_for_each_entry(lopt, &lcp->options, entry) {
if (lopt->id == hdr->id) {
@@ -587,7 +616,7 @@ static void lcp_recv_echo_repl(struct ppp_lcp_t *lcp, uint8_t *data, int size)
if (conf_ppp_verbose)
log_ppp_debug("recv [LCP EchoRep id=%x]\n", lcp->fsm.recv_id);
} else {
- magic = ntohl(*(uint32_t *)data);
+ magic = u_read_be32(data);
if (conf_ppp_verbose)
log_ppp_debug("recv [LCP EchoRep id=%x <magic %08x>]\n", lcp->fsm.recv_id, magic);
@@ -746,7 +775,7 @@ static void lcp_recv(struct ppp_handler_t*h)
hdr = (struct lcp_hdr_t *)lcp->ppp->buf;
len = ntohs(hdr->len);
buf_len = lcp->ppp->buf_size;
- if (len < PPP_HEADERLEN) {
+ if (len < PPP_HEADERLEN || len > lcp->ppp->buf_size - 2) {
log_ppp_warn("LCP: short packet received\n");
return;
}
@@ -802,7 +831,10 @@ static void lcp_recv(struct ppp_handler_t*h)
}
break;
case CONFNAK:
- lcp_recv_conf_nak(lcp, (uint8_t*)(hdr + 1), ntohs(hdr->len) - PPP_HDRLEN);
+ if (lcp_recv_conf_nak(lcp, (uint8_t*)(hdr + 1), ntohs(hdr->len) - PPP_HDRLEN)) {
+ ap_session_terminate(&lcp->ppp->ses, TERM_USER_ERROR, 0);
+ break;
+ }
if (lcp->fsm.recv_id != lcp->fsm.id)
break;
ppp_fsm_recv_conf_rej(&lcp->fsm);
@@ -838,7 +870,7 @@ static void lcp_recv(struct ppp_handler_t*h)
break;
}
if (conf_ppp_verbose)
- log_ppp_debug("recv [LCP EchoReq id=%x <magic %08x>]\n", hdr->id, ntohl(*(uint32_t*)(hdr + 1)));
+ log_ppp_debug("recv [LCP EchoReq id=%x <magic %08x>]\n", hdr->id, u_read_be32(hdr + 1));
send_echo_reply(lcp);
break;
case ECHOREP:
@@ -854,11 +886,11 @@ static void lcp_recv(struct ppp_handler_t*h)
log_ppp_warn("LCP: short ProtoRej received\n");
break;
}
- log_ppp_info2("recv [LCP ProtoRej id=%x <%04x>]\n", hdr->id, ntohs(*(uint16_t*)(hdr + 1)));
+ log_ppp_info2("recv [LCP ProtoRej id=%x <%04x>]\n", hdr->id, u_read_be16(hdr + 1));
}
if (len < PPP_HDRLEN + 2 || buf_len < (int)(sizeof(*hdr) + 2))
break;
- ppp_recv_proto_rej(lcp->ppp, ntohs(*(uint16_t *)(hdr + 1)));
+ ppp_recv_proto_rej(lcp->ppp, u_read_be16(hdr + 1));
break;
case DISCARDREQ:
if (conf_ppp_verbose) {
@@ -866,7 +898,7 @@ static void lcp_recv(struct ppp_handler_t*h)
log_ppp_warn("LCP: short DiscardReq received\n");
break;
}
- log_ppp_info2("recv [LCP DiscardReq id=%x <magic %08x>]\n", hdr->id, ntohl(*(uint32_t*)(hdr + 1)));
+ log_ppp_info2("recv [LCP DiscardReq id=%x <magic %08x>]\n", hdr->id, u_read_be32(hdr + 1));
}
break;
case IDENT:
diff --git a/accel-pppd/radius/backup.c b/accel-pppd/radius/backup.c
index 6d4db636..bfca0e49 100644
--- a/accel-pppd/radius/backup.c
+++ b/accel-pppd/radius/backup.c
@@ -6,6 +6,7 @@
#include "log.h"
#include "memdebug.h"
+#include "utils.h"
#include "backup.h"
#include "ap_session_backup.h"
@@ -22,6 +23,7 @@
#define RAD_TAG_ACCT_SERVER_ADDR 9
#define RAD_TAG_ACCT_SERVER_PORT 10
#define RAD_TAG_IDLE_TIMEOUT 11
+
#define RAD_TAG_ACCT_USERNAME 12
@@ -94,10 +96,10 @@ static void restore_ipv4_addr(struct ap_session *ses)
list_for_each_entry(tag, &m->tag_list, entry) {
switch (tag->id) {
case SES_TAG_IPV4_ADDR:
- ses->ipv4->addr = *(in_addr_t *)tag->data;
+ ses->ipv4->addr = u_read_native32(tag->data);
break;
case SES_TAG_IPV4_PEER_ADDR:
- ses->ipv4->peer_addr = *(in_addr_t *)tag->data;
+ ses->ipv4->peer_addr = u_read_native32(tag->data);
break;
}
}
@@ -121,16 +123,16 @@ void radius_restore_session(struct ap_session *ses, struct radius_pd_t *rpd)
list_for_each_entry(tag, &m->tag_list, entry) {
switch (tag->id) {
case RAD_TAG_INTERIM_INTERVAL:
- rpd->acct_interim_interval = *(uint32_t *)tag->data;
+ rpd->acct_interim_interval = u_read_native32(tag->data);
break;
case RAD_TAG_INTERIM_JITTER:
- rpd->acct_interim_jitter = *(uint32_t *)tag->data;
+ rpd->acct_interim_jitter = u_read_native32(tag->data);
break;
case RAD_TAG_SESSION_TIMEOUT:
- rpd->session_timeout.expire_tv.tv_sec = *(uint64_t *)tag->data - ses->start_time;
+ rpd->session_timeout.expire_tv.tv_sec = u_read_native64(tag->data) - ses->start_time;
break;
case RAD_TAG_IDLE_TIMEOUT:
- rpd->idle_timeout.period = (*(uint32_t *)tag->data) * 1000;
+ rpd->idle_timeout.period = u_read_native32(tag->data) * 1000;
break;
case RAD_TAG_IPV4_ADDR:
ses->ipv4 = &rpd->ipv4_addr;
@@ -150,16 +152,16 @@ void radius_restore_session(struct ap_session *ses, struct radius_pd_t *rpd)
rpd->attr_state_len = tag->size;
break;
case RAD_TAG_TERMINATION_ACTION:
- rpd->termination_action = *(uint32_t *)tag->data;
+ rpd->termination_action = u_read_native32(tag->data);
break;
case RAD_TAG_ACCT_USERNAME:
rpd->acct_username = _strndup(tag->data, tag->size);
break;
case RAD_TAG_ACCT_SERVER_ADDR:
- acct_addr = *(in_addr_t *)tag->data;
+ acct_addr = u_read_native32(tag->data);
break;
case RAD_TAG_ACCT_SERVER_PORT:
- acct_port = *(uint16_t *)tag->data;
+ acct_port = u_read_native16(tag->data);
break;
}
}
@@ -182,4 +184,3 @@ static void init(void)
}
DEFINE_INIT(100, init);
-
diff --git a/accel-pppd/radius/packet.c b/accel-pppd/radius/packet.c
index c7e91349..4a0ab244 100644
--- a/accel-pppd/radius/packet.c
+++ b/accel-pppd/radius/packet.c
@@ -24,6 +24,7 @@
#include "mempool.h"
#include "radius_p.h"
#include "attr_defs.h"
+#include "utils.h"
#include "memdebug.h"
@@ -111,20 +112,20 @@ int rad_packet_build(struct rad_packet_t *pack, uint8_t *RA)
*ptr = pack->code; ptr++;
*ptr = pack->id; ptr++;
- *(uint16_t*)ptr = htons(pack->len); ptr+= 2;
+ u_write_be16(ptr, pack->len); ptr += 2;
memcpy(ptr, RA, 16); ptr+=16;
list_for_each_entry(attr, &pack->attrs, entry) {
if (attr->vendor) {
*ptr = 26; ptr++;
*ptr = attr->len + 2 + 6; ptr++;
- *(uint32_t *)ptr = htonl(attr->vendor->id); ptr+=4;
+ u_write_be32(ptr, attr->vendor->id); ptr += 4;
}
*ptr = attr->attr->id; ptr++;
*ptr = attr->len + 2; ptr++;
switch(attr->attr->type) {
case ATTR_TYPE_INTEGER:
- *(uint32_t*)ptr = htonl(attr->val.integer);
+ u_write_be32(ptr, attr->val.integer);
break;
case ATTR_TYPE_OCTETS:
case ATTR_TYPE_STRING:
@@ -136,7 +137,7 @@ int rad_packet_build(struct rad_packet_t *pack, uint8_t *RA)
memcpy(ptr, &attr->val, attr->len);
break;
case ATTR_TYPE_DATE:
- *(uint32_t*)ptr = htonl(attr->val.date);
+ u_write_be32(ptr, attr->val.date);
break;
case ATTR_TYPE_IPV6PREFIX:
ptr[0] = 0;
@@ -204,17 +205,22 @@ int rad_packet_recv(int fd, struct rad_packet_t **p, struct sockaddr_in *addr)
pack->code = *ptr; ptr++;
pack->id = *ptr; ptr++;
- pack->len = ntohs(*(uint16_t*)ptr); ptr += 2;
+ pack->len = u_read_be16(ptr); ptr += 2;
- if (pack->len > n) {
+ if (pack->len < 20 || pack->len > n) {
log_ppp_warn("radius:packet: short packet received %i, expected %i\n", pack->len, n);
goto out_err;
}
ptr += 16;
- n -= 20;
+ n = pack->len - 20;
while (n>0) {
+ if (n < 2) {
+ log_ppp_warn("radius:packet: truncated attribute header received\n");
+ goto out_err;
+ }
+
id = *ptr; ptr++;
len = *ptr - 2; ptr++;
if (len < 0) {
@@ -230,7 +236,7 @@ int rad_packet_recv(int fd, struct rad_packet_t **p, struct sockaddr_in *addr)
log_ppp_warn("radius:packet: vendor attribute too short (%i)\n", len);
goto out_err;
}
- vendor_id = ntohl(*(uint32_t *)ptr);
+ vendor_id = u_read_be32(ptr);
vendor = rad_dict_find_vendor_id(vendor_id);
if (vendor) {
if (len < 4 + vendor->tag + vendor->len) {
@@ -240,14 +246,14 @@ int rad_packet_recv(int fd, struct rad_packet_t **p, struct sockaddr_in *addr)
ptr += 4;
if (vendor->tag == 2)
- id = (uint16_t)ntohs(*(uint16_t *)ptr);
+ id = u_read_be16(ptr);
else
id = *ptr;
ptr += vendor->tag;
if (vendor->len == 2)
- len = (uint16_t)ntohs(*(uint16_t *)ptr);
+ len = u_read_be16(ptr);
else
len = *ptr;
@@ -300,15 +306,15 @@ int rad_packet_recv(int fd, struct rad_packet_t **p, struct sockaddr_in *addr)
break;
}
if (len == 4)
- attr->val.integer = ntohl(*(uint32_t*)ptr);
+ attr->val.integer = u_read_be32(ptr);
else if (len == 2)
- attr->val.integer = ntohs(*(uint16_t*)ptr);
+ attr->val.integer = u_read_be16(ptr);
else if (len == 1)
attr->val.integer = *ptr;
break;
case ATTR_TYPE_DATE:
if (len == 4)
- attr->val.integer = ntohl(*(uint32_t*)ptr);
+ attr->val.integer = u_read_be32(ptr);
else
log_ppp_warn("radius:packet: attribute %s has invalid length %i (must be 4)\n", da->name, len);
break;
diff --git a/accel-pppd/session_backup.c b/accel-pppd/session_backup.c
index dea5b600..2873136f 100644
--- a/accel-pppd/session_backup.c
+++ b/accel-pppd/session_backup.c
@@ -59,6 +59,8 @@ static int session_save(struct ap_session *ses, struct backup_mod *m)
static int session_restore(struct ap_session *ses, struct backup_mod *m)
{
struct backup_tag *t;
+ time_t start_time;
+ uint32_t ifindex;
list_for_each_entry(t, &m->tag_list, entry) {
switch(t->id) {
@@ -79,11 +81,14 @@ static int session_restore(struct ap_session *ses, struct backup_mod *m)
ses->ifname[t->size] = 0;
break;
case SES_TAG_START_TIME:
- ses->start_time = *(time_t *)t->data;
+ memcpy(&start_time, t->data, sizeof(start_time));
+ ses->start_time = start_time;
break;
case SES_TAG_IFINDEX:
- if (ses->backup->internal)
- ses->ifindex = *(uint32_t *)t->data;
+ if (ses->backup->internal) {
+ memcpy(&ifindex, t->data, sizeof(ifindex));
+ ses->ifindex = ifindex;
+ }
break;
/*case PPP_TAG_FD:
ses->fd = *(int *)t->data;
diff --git a/accel-pppd/utils.h b/accel-pppd/utils.h
index 63c1db0d..7c62422c 100644
--- a/accel-pppd/utils.h
+++ b/accel-pppd/utils.h
@@ -1,13 +1,86 @@
#ifndef __UTILS_H
#define __UTILS_H
+#include <endian.h>
#include <netinet/in.h>
#include <stdint.h>
+#include <string.h>
#ifndef min
#define min(x, y) ((x) < (y) ? (x) : (y))
#endif
+/*
+ * Fixed-size memcpy() lets the compiler emit efficient unaligned accesses on
+ * architectures that support them without imposing alignment or aliasing
+ * requirements on callers.
+ */
+static inline uint16_t u_read_be16(const void *ptr)
+{
+ uint16_t value;
+
+ memcpy(&value, ptr, sizeof(value));
+ return ntohs(value);
+}
+
+static inline uint32_t u_read_be32(const void *ptr)
+{
+ uint32_t value;
+
+ memcpy(&value, ptr, sizeof(value));
+ return ntohl(value);
+}
+
+static inline uint64_t u_read_be64(const void *ptr)
+{
+ uint64_t value;
+
+ memcpy(&value, ptr, sizeof(value));
+ return be64toh(value);
+}
+
+static inline void u_write_be16(void *ptr, uint16_t value)
+{
+ value = htons(value);
+ memcpy(ptr, &value, sizeof(value));
+}
+
+static inline void u_write_be32(void *ptr, uint32_t value)
+{
+ value = htonl(value);
+ memcpy(ptr, &value, sizeof(value));
+}
+
+static inline void u_write_be64(void *ptr, uint64_t value)
+{
+ value = htobe64(value);
+ memcpy(ptr, &value, sizeof(value));
+}
+
+static inline uint16_t u_read_native16(const void *ptr)
+{
+ uint16_t value;
+
+ memcpy(&value, ptr, sizeof(value));
+ return value;
+}
+
+static inline uint32_t u_read_native32(const void *ptr)
+{
+ uint32_t value;
+
+ memcpy(&value, ptr, sizeof(value));
+ return value;
+}
+
+static inline uint64_t u_read_native64(const void *ptr)
+{
+ uint64_t value;
+
+ memcpy(&value, ptr, sizeof(value));
+ return value;
+}
+
char *u_ip6str(const struct in6_addr *addr, char *buf);
char *u_ip4str(const struct in_addr *addr, char *buf);
diff --git a/tests/accel-pppd/pppoe/test_pppoe_session_wo_auth.py b/tests/accel-pppd/pppoe/test_pppoe_session_wo_auth.py
index 960b7c94..b4cccc81 100644
--- a/tests/accel-pppd/pppoe/test_pppoe_session_wo_auth.py
+++ b/tests/accel-pppd/pppoe/test_pppoe_session_wo_auth.py
@@ -26,6 +26,9 @@ def accel_pppd_config(veth_pair_netns):
[auth]
any-login=1
+ [ppp]
+ mppe=prefer
+
[ip-pool]
gw-ip-address=192.0.2.1
192.0.2.2-255