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 forc34cb1d645Follow-up for696eb2b8deFollow-up for44e8cf303b
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user