mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-11 02:59:59 -04:00
Process dig -x reverse octets iteratively
reverse_octets() recursed once per dot, with depth bounded only by ARG_MAX (~2 MiB on Linux), so feeding dig -x a deep input like '1.1.1.…1' busted the call stack and crashed the tool with SIGSEGV instead of a structured error. The transformation it performs is purely textual (split on '.', emit components in reverse), so the recursion was never load-bearing. Walk the input once into a fixed-size array of label slices, capped at DNS_NAME_MAXLABELS (which is the most we could ever fit into the result buffer anyway), then iterate the array in reverse to write the output. Inputs with more than DNS_NAME_MAXLABELS labels now return DNS_R_NAMETOOLONG, which dig.c surfaces as 'Invalid IP address' and exit 1. Drop the unnecessary (int) casts on ptrdiff_t/size_t lengths while at it. Assisted-by: Claude:claude-opus-4-7
This commit is contained in:
parent
688e8667a3
commit
f1ec5e1809
2 changed files with 40 additions and 9 deletions
|
|
@ -288,16 +288,33 @@ append(const char *text, size_t len, char **p, char *end) {
|
|||
|
||||
static isc_result_t
|
||||
reverse_octets(const char *in, char **p, char *end) {
|
||||
const char *dot = strchr(in, '.');
|
||||
size_t len;
|
||||
if (dot != NULL) {
|
||||
RETERR(reverse_octets(dot + 1, p, end));
|
||||
RETERR(append(".", 1, p, end));
|
||||
len = (int)(dot - in);
|
||||
} else {
|
||||
len = (int)strlen(in);
|
||||
const char *parts[DNS_NAME_MAXLABELS];
|
||||
size_t lens[DNS_NAME_MAXLABELS];
|
||||
size_t n = 0;
|
||||
const char *cursor = in;
|
||||
|
||||
while (true) {
|
||||
const char *dot = strchr(cursor, '.');
|
||||
if (n >= DNS_NAME_MAXLABELS) {
|
||||
return DNS_R_NAMETOOLONG;
|
||||
}
|
||||
parts[n] = cursor;
|
||||
lens[n] = (dot != NULL) ? (size_t)(dot - cursor)
|
||||
: strlen(cursor);
|
||||
n++;
|
||||
if (dot == NULL) {
|
||||
break;
|
||||
}
|
||||
cursor = dot + 1;
|
||||
}
|
||||
return append(in, len, p, end);
|
||||
|
||||
for (size_t i = n; i-- > 0;) {
|
||||
if (i + 1 < n) {
|
||||
RETERR(append(".", 1, p, end));
|
||||
}
|
||||
RETERR(append(parts[i], lens[i], p, end));
|
||||
}
|
||||
return ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
|
|
|
|||
|
|
@ -148,6 +148,20 @@ if [ -x "$DIG" ]; then
|
|||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "checking dig -x rejects deeply nested input cleanly ($n)"
|
||||
ret=0
|
||||
longinput="$(printf '1.%.0s' $(seq 1 6400))1"
|
||||
# Pre-fix: SIGSEGV (139) or ASan abort (134) from unbounded recursion in
|
||||
# reverse_octets() on the dots. Post-fix: structured rejection via
|
||||
# DNS_R_NAMETOOLONG -> "Invalid IP address" -> exit 1.
|
||||
rc=0
|
||||
dig_with_opts -x "$longinput" >dig.out.test$n 2>&1 || rc=$?
|
||||
[ $rc -ge 128 ] && ret=1
|
||||
grep "Invalid IP address" dig.out.test$n >/dev/null || ret=1
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "checking dig over TCP works ($n)"
|
||||
ret=0
|
||||
|
|
|
|||
Loading…
Reference in a new issue