resolv: Fix endless loop in __res_context_query

Starting with commit 40c0add7d4
"resolve: Remove __res_context_query alloca usage"
there is an endless loop in __res_context_query if
__res_context_mkquery fails e.g. if type is invalid.  Then the
scratch buffer is resized to MAXPACKET size and it is retried again.

Before the mentioned commit, it was retried only once and with the
mentioned commit, there is no check and it retries in an endless loop.

This is observable with xtest resolv/tst-resolv-qtypes which times out
after 300s.

This patch retries mkquery only once as before the mentioned commit.
Furthermore, scratch_buffer_set_array_size is now only called with
nelem=2 if type is T_QUERY_A_AND_AAAA (also see mentioned commit).
The test tst-resolv-qtypes is also adjusted to verify that <func>
is really returning with -1 in case of an invalid type.
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
This commit is contained in:
Stefan Liebler 2024-01-11 14:01:18 +01:00
parent c0c259c3bd
commit 0aabf15a35
2 changed files with 8 additions and 4 deletions

View File

@ -81,6 +81,7 @@
#include <string.h> #include <string.h>
#include <shlib-compat.h> #include <shlib-compat.h>
#include <scratch_buffer.h> #include <scratch_buffer.h>
#include <stdbool.h>
#if PACKETSZ > 65536 #if PACKETSZ > 65536
#define MAXPACKET PACKETSZ #define MAXPACKET PACKETSZ
@ -116,6 +117,7 @@ __res_context_query (struct resolv_context *ctx, const char *name,
UHEADER *hp = (UHEADER *) answer; UHEADER *hp = (UHEADER *) answer;
UHEADER *hp2; UHEADER *hp2;
int n; int n;
bool retried = false;
/* It requires 2 times QUERYSIZE for type == T_QUERY_A_AND_AAAA. */ /* It requires 2 times QUERYSIZE for type == T_QUERY_A_AND_AAAA. */
struct scratch_buffer buf; struct scratch_buffer buf;
@ -182,13 +184,15 @@ __res_context_query (struct resolv_context *ctx, const char *name,
nquery1 = n; nquery1 = n;
} }
if (__glibc_unlikely (n <= 0)) { if (__glibc_unlikely (n <= 0) && !retried) {
/* Retry just in case res_nmkquery failed because of too /* Retry just in case res_nmkquery failed because of too
short buffer. Shouldn't happen. */ short buffer. Shouldn't happen. */
if (scratch_buffer_set_array_size (&buf, if (scratch_buffer_set_array_size (&buf,
T_QUERY_A_AND_AAAA ? 2 : 1, (type == T_QUERY_A_AND_AAAA)
? 2 : 1,
MAXPACKET)) { MAXPACKET)) {
query1 = buf.data; query1 = buf.data;
retried = true;
goto again; goto again;
} }
} }

View File

@ -154,8 +154,8 @@ test_function (const char *fname,
} }
} }
TEST_VERIFY (func (-1, buf, sizeof (buf) == -1)); TEST_VERIFY (func (-1, buf, sizeof (buf)) == -1);
TEST_VERIFY (func (65536, buf, sizeof (buf) == -1)); TEST_VERIFY (func (65536, buf, sizeof (buf)) == -1);
} }
static int static int