NLnetLabs / ldns

LDNS is a DNS library that facilitates DNS tool programming

Home Page:https://nlnetlabs.nl/ldns

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

GCC (mis)catches a use-after-free condition in parse.c

khorben opened this issue · comments

When compiling with -Wuse-after-free=2, GCC catches the following problem in parse.c from the 1.8.3 release:

--- parse.o ---
contrib/ldns/parse.c: In function 'ldns_fget_token_l_st':
contrib/ldns/parse.c:151:57: error: pointer may be used after 'realloc' [-Werror=use-after-free]
  151 |                                         t = *token + (t - old_token);
      |                                                      ~~~^~~~~~~~~~~~
In file included from contrib/ldns/ldns/ldns.h:95,
                 from contrib/ldns/parse.c:11:
contrib/ldns/ldns/util.h:58:19: note: call to 'realloc' here
   58 |         ((type *) realloc((ptr), (count) * sizeof(type)))
      |                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
contrib/ldns/parse.c:144:42: note: in expansion of macro 'LDNS_XREALLOC'
  144 |                                 *token = LDNS_XREALLOC(*token, char, *limit + 1);
      |                                          ^~~~~~~~~~~~~
contrib/ldns/parse.c:185:49: error: pointer 'old_token' may be used after 'realloc' [-Werror=use-after-free]
  185 |                                 t = *token + (t - old_token);
      |                                              ~~~^~~~~~~~~~~~
contrib/ldns/ldns/util.h:58:19: note: call to 'realloc' here
   58 |         ((type *) realloc((ptr), (count) * sizeof(type)))
      |                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
contrib/ldns/parse.c:178:34: note: in expansion of macro 'LDNS_XREALLOC'
  178 |                         *token = LDNS_XREALLOC(*token, char, *limit + 1);
      |                                  ^~~~~~~~~~~~~

After reading it, I believe the corresponding code is harmless, since it never actually dereferences old_token. It is however very inelegant in the way it performs pointer arithmetic to keep track of t, and should probably be modified to use an array index instead.

The warning is technically correct. However, this is a common pattern, and in practice I'm not aware of this being a problem with current toolchains. What is definitely a problem is doing something along the lines of:

q = realloc(p, ...);
foo = foo + (q - p);

because that doesn't give foo the right provenance, and that's something that the recently-added _FORTIFY_SOURCE=3 in GCC supposedly catches, as does CHERI. But the code isn't doing that, the provenance is correct, the issue is just that, strictly, the value of the pointer given to realloc is now indeterminate^1, which isn't particularly helpful, nor is it really necessary to be specified like that. In this case, one could trivially address the issue by hoisting the t - old_token calculation before the realloc (and remove the now-obsolete old_token), and let the compiler decide to sink it back to its use, which it will surely do. I would expect identical code to be generated.

^1 C99 6.2.4p2: "The value of a pointer becomes indeterminate when the object it points to reaches the end of its lifetime."