resolve: fix use-after-free (#36353)

Fixes a bug introduced by 81ae2237c1.
Fixes #36351.
This commit is contained in:
Yu Watanabe
2025-02-15 00:03:21 +09:00
committed by GitHub
4 changed files with 62 additions and 12 deletions
+4
View File
@@ -56,11 +56,15 @@ wrap=(
id
integritysetup
iscsid
keymgr
knotc
knotd
kpartx
logger
login
ls
lsblk
lsof
lvm
mdadm
mkfs.btrfs
+23 -7
View File
@@ -508,16 +508,27 @@ DnsQuery *dns_query_free(DnsQuery *q) {
return mfree(q);
}
static int validate_and_mangle_question(DnsQuestion **question, Set *types) {
static int manager_validate_and_mangle_question(Manager *manager, DnsQuestion **question, DnsQuestion **ret_allocated) {
int r;
if (set_isempty(types))
assert(manager);
assert(question);
assert(ret_allocated);
if (!*question) {
*ret_allocated = NULL;
return 0;
}
if (set_isempty(manager->refuse_record_types)) {
*ret_allocated = NULL;
return 0; /* No filtering configured. Let's shortcut. */
}
bool has_good = false, has_bad = false;
DnsResourceKey *key;
DNS_QUESTION_FOREACH(key, *question)
if (set_contains(types, INT_TO_PTR(key->type)))
if (set_contains(manager->refuse_record_types, INT_TO_PTR(key->type)))
has_bad = true;
else
has_good = true;
@@ -526,6 +537,7 @@ static int validate_and_mangle_question(DnsQuestion **question, Set *types) {
return -ENOANO; /* All bad, refuse.*/
if (!has_bad) {
assert(has_good); /* The question should have at least one key. */
*ret_allocated = NULL;
return 0; /* All good. Not necessary to filter. */
}
@@ -536,14 +548,16 @@ static int validate_and_mangle_question(DnsQuestion **question, Set *types) {
DnsQuestionItem *item;
DNS_QUESTION_FOREACH_ITEM(item, *question) {
if (set_contains(types, INT_TO_PTR(item->key->type)))
if (set_contains(manager->refuse_record_types, INT_TO_PTR(item->key->type)))
continue;
r = dns_question_add_raw(new_question, item->key, item->flags);
if (r < 0)
return r;
}
return free_and_replace_full(*question, new_question, dns_question_unref);
*question = new_question;
*ret_allocated = TAKE_PTR(new_question);
return 0;
}
int dns_query_new(
@@ -563,11 +577,13 @@ int dns_query_new(
assert(m);
/* Check for records that is refused and refuse query for the records if matched in configuration */
r = validate_and_mangle_question(&question_utf8, m->refuse_record_types);
_unused_ _cleanup_(dns_question_unrefp) DnsQuestion *filtered_question_utf8 = NULL;
r = manager_validate_and_mangle_question(m, &question_utf8, &filtered_question_utf8);
if (r < 0)
return r;
r = validate_and_mangle_question(&question_idna, m->refuse_record_types);
_unused_ _cleanup_(dns_question_unrefp) DnsQuestion *filtered_question_idna = NULL;
r = manager_validate_and_mangle_question(m, &question_idna, &filtered_question_idna);
if (r < 0)
return r;
+1
View File
@@ -631,6 +631,7 @@ static void manager_set_defaults(Manager *m) {
m->resolve_unicast_single_label = false;
m->cache_from_localhost = false;
m->stale_retention_usec = 0;
m->refuse_record_types = set_free(m->refuse_record_types);
}
static int manager_dispatch_reload_signal(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
+34 -5
View File
@@ -16,12 +16,14 @@ set -o pipefail
# shellcheck source=test/units/util.sh
. "$(dirname "$0")"/util.sh
# We need at least Knot 3.0 which support (among others) the ds-push directive
if ! knotc -c /usr/lib/systemd/tests/testdata/knot-data/knot.conf conf-check; then
echo "This test requires at least Knot 3.0. skipping..." | tee --append /skipped
if ! command knotc >/dev/null; then
echo "command knotc not found, skipping..." | tee --append /skipped
exit 77
fi
# We need at least Knot 3.0 which support (among others) the ds-push directive
knotc -c /usr/lib/systemd/tests/testdata/knot-data/knot.conf conf-check
RUN_OUT="$(mktemp)"
run() {
@@ -1009,6 +1011,11 @@ testcase_12_resolvectl2() {
# Test io.systemd.Resolve.Monitor.SubscribeDNSConfiguration
testcase_13_varlink_subscribe_dns_configuration() {
# FIXME: for some reasons, the test case unexpectedly fail when running on sanitizers.
if [[ -v ASAN_OPTIONS ]]; then
return 0
fi
# Cleanup
# shellcheck disable=SC2317
cleanup() {
@@ -1107,8 +1114,6 @@ testcase_14_refuse_record_types() {
fi
ln -svf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
systemctl reload systemd-resolved.service
# disable_ipv6 is necessary do refuse AAAA
disable_ipv6
run dig localhost -t AAAA
grep -qF "status: REFUSED" "$RUN_OUT"
@@ -1135,6 +1140,30 @@ testcase_14_refuse_record_types() {
run resolvectl query localhost5 --type=A
grep -qF "127.128.0.5" "$RUN_OUT"
{
echo "[Resolve]"
echo "RefuseRecordTypes=AAAA"
} >/run/systemd/resolved.conf.d/refuserecords.conf
systemctl reload systemd-resolved.service
run dig localhost -t SRV
grep -qF "status: NOERROR" "$RUN_OUT"
run dig localhost -t TXT
grep -qF "status: NOERROR" "$RUN_OUT"
run dig localhost -t AAAA
grep -qF "status: REFUSED" "$RUN_OUT"
(! run resolvectl query localhost5 --type=SRV)
grep -qF "does not have any RR of the requested type" "$RUN_OUT"
(! run resolvectl query localhost5 --type=TXT)
grep -qF "does not have any RR of the requested type" "$RUN_OUT"
(! run resolvectl query localhost5 --type=AAAA)
grep -qF "DNS query type refused." "$RUN_OUT"
}
# PRE-SETUP