ndisc: reject non-zero ICMPv6 codes in parsers

NDisc packets received through the socket path are filtered before
parser dispatch, but parser entry points should still reject malformed
packet bytes instead of asserting on them. Return EBADMSG for non-zero
ICMPv6 code values in RA, NA, and Redirect messages.

Follow-up for c34cb1d645
Follow-up for 696eb2b8de
Follow-up for 44e8cf303b
This commit is contained in:
Luca Boccassi
2026-07-11 17:07:53 +01:00
parent ad0996191d
commit 8baed40298
4 changed files with 65 additions and 3 deletions
+3 -1
View File
@@ -52,7 +52,9 @@ int ndisc_neighbor_parse(sd_ndisc *nd, sd_ndisc_neighbor *na) {
/* Neighbor advertisement packets are neatly aligned to 64-bit boundaries, hence we can access them directly */
const struct nd_neighbor_advert *a = (const struct nd_neighbor_advert*) na->packet->raw_packet;
assert(a->nd_na_type == ND_NEIGHBOR_ADVERT);
assert(a->nd_na_code == 0);
if (a->nd_na_code != 0)
return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
"Received Neighbor Advertisement with non-zero code, ignoring datagram.");
na->flags = a->nd_na_flags_reserved; /* the first 3 bits */
na->target_address = a->nd_na_target;
+3 -1
View File
@@ -52,7 +52,9 @@ int ndisc_redirect_parse(sd_ndisc *nd, sd_ndisc_redirect *rd) {
const struct nd_redirect *a = (const struct nd_redirect*) rd->packet->raw_packet;
assert(a->nd_rd_type == ND_REDIRECT);
assert(a->nd_rd_code == 0);
if (a->nd_rd_code != 0)
return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
"Received Redirect message with non-zero code, ignoring datagram.");
rd->target_address = a->nd_rd_target;
rd->destination_address = a->nd_rd_dst;
+3 -1
View File
@@ -108,7 +108,9 @@ int ndisc_router_parse(sd_ndisc *nd, sd_ndisc_router *rt) {
a = (const struct nd_router_advert*) rt->packet->raw_packet;
assert(a->nd_ra_type == ND_ROUTER_ADVERT);
assert(a->nd_ra_code == 0);
if (a->nd_ra_code != 0)
return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
"Received Router Advertisement with non-zero code, ignoring.");
rt->hop_limit = a->nd_ra_curhoplimit;
rt->flags = a->nd_ra_flags_reserved; /* the first 8 bits */
+56
View File
@@ -15,6 +15,9 @@
#include "icmp6-test-util.h"
#include "in-addr-util.h"
#include "ndisc-internal.h"
#include "ndisc-neighbor-internal.h"
#include "ndisc-redirect-internal.h"
#include "ndisc-router-internal.h"
#include "strv.h"
#include "tests.h"
@@ -22,6 +25,59 @@ static struct ether_addr mac_addr = {
.ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
};
static ICMP6Packet* make_packet(const void *raw, size_t size) {
ICMP6Packet *packet;
assert(raw);
packet = malloc0(offsetof(ICMP6Packet, raw_packet) + size);
ASSERT_NOT_NULL(packet);
packet->n_ref = 1;
packet->raw_size = size;
memcpy(packet->raw_packet, raw, size);
return packet;
}
TEST(parse_rejects_nonzero_code) {
static const struct nd_router_advert router_advertisement = {
.nd_ra_type = ND_ROUTER_ADVERT,
.nd_ra_code = 1,
};
static const struct nd_neighbor_advert neighbor_advertisement = {
.nd_na_type = ND_NEIGHBOR_ADVERT,
.nd_na_code = 1,
};
static const struct nd_redirect redirect = {
.nd_rd_type = ND_REDIRECT,
.nd_rd_code = 1,
};
_cleanup_(icmp6_packet_unrefp) ICMP6Packet *packet =
make_packet(&router_advertisement, sizeof(router_advertisement));
_cleanup_(sd_ndisc_router_unrefp) sd_ndisc_router *router =
ASSERT_PTR(ndisc_router_new(packet));
ASSERT_ERROR(ndisc_router_parse(/* nd= */ NULL, router), EBADMSG);
router = sd_ndisc_router_unref(router);
packet = icmp6_packet_unref(packet);
packet = make_packet(&neighbor_advertisement, sizeof(neighbor_advertisement));
_cleanup_(sd_ndisc_neighbor_unrefp) sd_ndisc_neighbor *neighbor =
ASSERT_PTR(ndisc_neighbor_new(packet));
ASSERT_ERROR(ndisc_neighbor_parse(/* nd= */ NULL, neighbor), EBADMSG);
neighbor = sd_ndisc_neighbor_unref(neighbor);
packet = icmp6_packet_unref(packet);
packet = make_packet(&redirect, sizeof(redirect));
_cleanup_(sd_ndisc_redirect_unrefp) sd_ndisc_redirect *rd =
ASSERT_PTR(ndisc_redirect_new(packet));
ASSERT_ERROR(ndisc_redirect_parse(/* nd= */ NULL, rd), EBADMSG);
}
static void router_dump(sd_ndisc_router *rt) {
struct in6_addr addr;
uint8_t hop_limit;