NLnetLabs / ldns

LDNS is a DNS library that facilitates DNS tool programming
https://nlnetlabs.nl/ldns
BSD 3-Clause "New" or "Revised" License
280 stars 95 forks source link

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

Open khorben opened 1 year ago

khorben commented 1 year ago

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.

jrtc27 commented 1 year ago

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."