fix: dev: use proper flexible arrays in rrl

The single-element array hack can trip newer sanitizers or fortification levels.

Found with UBSAN triggering the RRL system test with meson.

Merge branch 'aydin/rrl-flex-array' into 'main'

See merge request isc-projects/bind9!10509
This commit is contained in:
Aydın Mercan 2025-05-30 11:18:08 +00:00
commit e8f3ce70aa
3 changed files with 36 additions and 27 deletions

View file

@ -19,6 +19,9 @@
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <isc/attributes.h>
#include <dns/fixedname.h>
#include <dns/rdata.h>
@ -157,7 +160,7 @@ struct dns_rrl_hash {
isc_stdtime_t check_time;
unsigned int gen : DNS_RRL_HASH_GEN_BITS;
int length;
dns_rrl_bin_t bins[1];
dns_rrl_bin_t bins[] ISC_ATTR_COUNTED_BY(length);
};
/*
@ -166,8 +169,8 @@ struct dns_rrl_hash {
typedef struct dns_rrl_block dns_rrl_block_t;
struct dns_rrl_block {
ISC_LINK(dns_rrl_block_t) link;
int size;
dns_rrl_entry_t entries[1];
uint32_t count;
dns_rrl_entry_t entries[] ISC_ATTR_COUNTED_BY(count);
};
/*

View file

@ -205,7 +205,6 @@ set_age(dns_rrl_t *rrl, dns_rrl_entry_t *e, isc_stdtime_t now) {
static isc_result_t
expand_entries(dns_rrl_t *rrl, int newsize) {
unsigned int bsize;
dns_rrl_block_t *b;
dns_rrl_entry_t *e;
double rate;
@ -237,10 +236,11 @@ expand_entries(dns_rrl_t *rrl, int newsize) {
rrl->hash->length, rate);
}
bsize = sizeof(dns_rrl_block_t) +
ISC_CHECKED_MUL((newsize - 1), sizeof(dns_rrl_entry_t));
b = isc_mem_cget(rrl->mctx, 1, bsize);
b->size = bsize;
b = isc_mem_cget(rrl->mctx, 1, STRUCT_FLEX_SIZE(b, entries, newsize));
*b = (dns_rrl_block_t){
.link = ISC_LINK_INITIALIZER,
.count = newsize,
};
e = b->entries;
for (i = 0; i < newsize; ++i, ++e) {
@ -274,16 +274,14 @@ free_old_hash(dns_rrl_t *rrl) {
}
isc_mem_put(rrl->mctx, old_hash,
sizeof(*old_hash) +
ISC_CHECKED_MUL((old_hash->length - 1),
sizeof(old_hash->bins[0])));
STRUCT_FLEX_SIZE(old_hash, bins, old_hash->length));
rrl->old_hash = NULL;
}
static isc_result_t
expand_rrl_hash(dns_rrl_t *rrl, isc_stdtime_t now) {
dns_rrl_hash_t *hash;
int old_bins, new_bins, hsize;
int old_bins, new_bins;
double rate;
if (rrl->old_hash != NULL) {
@ -301,12 +299,13 @@ expand_rrl_hash(dns_rrl_t *rrl, isc_stdtime_t now) {
}
new_bins = hash_divisor(new_bins);
hsize = sizeof(dns_rrl_hash_t) +
ISC_CHECKED_MUL((new_bins - 1), sizeof(hash->bins[0]));
hash = isc_mem_cget(rrl->mctx, 1, hsize);
hash->length = new_bins;
rrl->hash_gen ^= 1;
hash->gen = rrl->hash_gen;
hash = isc_mem_cget(rrl->mctx, 1,
STRUCT_FLEX_SIZE(hash, bins, new_bins));
*hash = (dns_rrl_hash_t){
.length = new_bins,
.gen = rrl->hash_gen,
};
if (isc_log_wouldlog(DNS_RRL_LOG_DROP) && old_bins != 0) {
rate = rrl->probes;
@ -1283,21 +1282,18 @@ dns_rrl_view_destroy(dns_view_t *view) {
ISC_LIST_FOREACH (rrl->blocks, b, link) {
ISC_LIST_UNLINK(rrl->blocks, b, link);
isc_mem_put(rrl->mctx, b, b->size);
isc_mem_put(rrl->mctx, b,
STRUCT_FLEX_SIZE(b, entries, b->count));
}
h = rrl->hash;
if (h != NULL) {
isc_mem_put(rrl->mctx, h,
sizeof(*h) + ISC_CHECKED_MUL((h->length - 1),
sizeof(h->bins[0])));
isc_mem_put(rrl->mctx, h, STRUCT_FLEX_SIZE(h, bins, h->length));
}
h = rrl->old_hash;
if (h != NULL) {
isc_mem_put(rrl->mctx, h,
sizeof(*h) + ISC_CHECKED_MUL((h->length - 1),
sizeof(h->bins[0])));
isc_mem_put(rrl->mctx, h, STRUCT_FLEX_SIZE(h, bins, h->length));
}
isc_mem_putanddetach(&rrl->mctx, rrl, sizeof(*rrl));

View file

@ -14,12 +14,16 @@
#pragma once
/***
*** Clang Compatibility Macros
*** Attribute Compatibility Macros
***/
#if !defined(__has_c_attribute)
#ifndef __has_c_attribute
#define __has_c_attribute(x) 0
#endif /* if !defined(__has_c_attribute) */
#endif /* __has_c_attribute */
#ifndef __has_attribute
#define __has_attribute(x) 0
#endif /* __has_attribute */
#if __has_c_attribute(noreturn) && __STDC_VERSION__ >= 202311L
#define ISC_NORETURN [[noreturn]]
@ -102,3 +106,9 @@
#else
#define ISC_ATTR_UNUSED __attribute__((__unused__))
#endif
#if __has_attribute(__counted_by__)
#define ISC_ATTR_COUNTED_BY(x) __attribute__((__counted_by__(x)))
#else
#define ISC_ATTR_COUNTED_BY(x)
#endif