summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Fedoryshchenko <denys.f@collabora.com>2026-09-01 08:50:12 +0300
committerDenys Fedoryshchenko <denys.f@collabora.com>2026-09-01 08:55:54 +0300
commite0c63e6259bb4a75468e5680fb2d10934c2d035b (patch)
tree7ca552fcf0a1de421dad6037a49410600468bc2a
parent6c4593a87e689a83d7308efb0913a8dd9182051b (diff)
downloadaccel-ppp-e0c63e6259bb4a75468e5680fb2d10934c2d035b.tar.gz
accel-ppp-e0c63e6259bb4a75468e5680fb2d10934c2d035b.zip
radius: harden packet integer decoding
Serialize integer fields via memcpy, restrict attribute parsing to the RADIUS header's declared packet length, reject undersized packet lengths, and reject truncated attribute headers.
-rw-r--r--accel-pppd/radius/packet.c59
1 files changed, 46 insertions, 13 deletions
diff --git a/accel-pppd/radius/packet.c b/accel-pppd/radius/packet.c
index c7e91349..782ecffe 100644
--- a/accel-pppd/radius/packet.c
+++ b/accel-pppd/radius/packet.c
@@ -35,6 +35,34 @@ static mempool_t packet_pool;
static mempool_t attr_pool;
static mempool_t buf_pool;
+static uint16_t radius_read_u16(const void *ptr)
+{
+ uint16_t value;
+
+ memcpy(&value, ptr, sizeof(value));
+ return ntohs(value);
+}
+
+static uint32_t radius_read_u32(const void *ptr)
+{
+ uint32_t value;
+
+ memcpy(&value, ptr, sizeof(value));
+ return ntohl(value);
+}
+
+static void radius_write_u16(void *ptr, uint16_t value)
+{
+ value = htons(value);
+ memcpy(ptr, &value, sizeof(value));
+}
+
+static void radius_write_u32(void *ptr, uint32_t value)
+{
+ value = htonl(value);
+ memcpy(ptr, &value, sizeof(value));
+}
+
struct rad_packet_t *rad_packet_alloc(int code)
{
struct rad_packet_t *pack;
@@ -111,20 +139,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;
+ radius_write_u16(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;
+ radius_write_u32(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);
+ radius_write_u32(ptr, attr->val.integer);
break;
case ATTR_TYPE_OCTETS:
case ATTR_TYPE_STRING:
@@ -136,7 +164,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);
+ radius_write_u32(ptr, attr->val.date);
break;
case ATTR_TYPE_IPV6PREFIX:
ptr[0] = 0;
@@ -204,17 +232,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 = radius_read_u16(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 +263,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 = radius_read_u32(ptr);
vendor = rad_dict_find_vendor_id(vendor_id);
if (vendor) {
if (len < 4 + vendor->tag + vendor->len) {
@@ -240,14 +273,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 = radius_read_u16(ptr);
else
id = *ptr;
ptr += vendor->tag;
if (vendor->len == 2)
- len = (uint16_t)ntohs(*(uint16_t *)ptr);
+ len = radius_read_u16(ptr);
else
len = *ptr;
@@ -300,15 +333,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 = radius_read_u32(ptr);
else if (len == 2)
- attr->val.integer = ntohs(*(uint16_t*)ptr);
+ attr->val.integer = radius_read_u16(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 = radius_read_u32(ptr);
else
log_ppp_warn("radius:packet: attribute %s has invalid length %i (must be 4)\n", da->name, len);
break;