mirror of
https://sourceware.org/git/glibc.git
synced 2024-12-23 03:10:05 +00:00
f120cda607
The resolv/res_debug.c function p_secstodate (which is a public function exported from libresolv, taking an unsigned long argument) does: struct tm timebuf; time = __gmtime_r(&clock, &timebuf); time->tm_year += 1900; time->tm_mon += 1; sprintf(output, "%04d%02d%02d%02d%02d%02d", time->tm_year, time->tm_mon, time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec); If __gmtime_r returns NULL (because the year overflows the range of int), this will dereference a null pointer. Otherwise, if the computed year does not fit in four characters, this will cause a buffer overrun of the fixed-size 15-byte buffer. With current GCC mainline, there is a compilation failure because of the possible buffer overrun. I couldn't find a specification for how this function is meant to behave, but Paul pointed to RFC 4034 as relevant to the cases where this function is called from within glibc. The function's interface is inherently problematic when dates beyond Y2038 might be involved, because of the ambiguity in how to interpret 32-bit timestamps as such dates (the RFC suggests interpreting times as being within 68 years of the present date, which would mean some kind of interface whose behavior depends on the present date). This patch works on the basis of making a minimal fix in preparation for obsoleting the function. The function is made to handle times in the interval [0, 0x7fffffff] only, on all platforms, with <overflow> used as the output string in other cases (and errno set to EOVERFLOW in such cases). This seems to be a reasonable state for the function to be in when made a compat symbol by a future patch, being compatible with any existing uses for existing timestamps without trying to work for later timestamps. Results independent of the range of time_t also simplify the testcase. I couldn't persuade GCC to recognize the ranges of the struct tm fields by adding explicit range checks with a call to __builtin_unreachable if outside the range (this looks similar to <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80776>), so having added a range check on the input, this patch then disables the -Wformat-overflow= warning for the sprintf call (I prefer that to the use of strftime, as being more transparently correct without knowing what each of %m and %M etc. is). I do not know why this build failure should be new with mainline GCC (that is, I don't know what GCC change might have introduced it, when the basic functionality for such warnings was already in GCC 7). I do not know if this is a security issue (that is, if there are plausible ways in which a date before -999 or after 9999 from an untrusted source might end up in this function). The system clock is arguably an untrusted source (in that e.g. NTP is insecure), but probably not to that extent (NTP can't communicate such wild timestamps), and uses from within glibc are limited to 32-bit inputs. Tested with build-many-glibcs.py that this restores the build for arm with yesterday's mainline GCC. Also tested for x86_64 and x86. [BZ #22463] * resolv/res_debug.c: Include <libc-diag.h>. (p_secstodate): Assert time_t at least as wide as u_long. On overflow, use integer seconds since the epoch as output, or use "<overflow>" as output and set errno to EOVERFLOW if integer seconds since the epoch would be 14 or more characters. (p_secstodate) [__GNUC_PREREQ (7, 0)]: Disable -Wformat-overflow= for sprintf call. * resolv/tst-p_secstodate.c: New file. * resolv/Makefile (tests): Add tst-p_secstodate. ($(objpfx)tst-p_secstodate): Depend on $(objpfx)libresolv.so. |
||
---|---|---|
.. | ||
arpa | ||
bits/types | ||
nss_dns | ||
rpc | ||
sys | ||
base64.c | ||
compat-gethnamaddr.c | ||
compat-hooks.c | ||
Depend | ||
gai_cancel.c | ||
gai_error.c | ||
gai_misc.c | ||
gai_misc.h | ||
gai_notify.c | ||
gai_sigqueue.c | ||
gai_suspend.c | ||
getaddrinfo_a.c | ||
herror.c | ||
inet_addr.c | ||
inet_net_ntop.c | ||
inet_net_pton.c | ||
inet_neta.c | ||
inet_ntop.c | ||
inet_pton.c | ||
Makefile | ||
mapv4v6addr.h | ||
mapv4v6hostent.h | ||
netdb.h | ||
ns_date.c | ||
ns_name.c | ||
ns_netint.c | ||
ns_parse.c | ||
ns_print.c | ||
ns_samedomain.c | ||
ns_ttl.c | ||
nsap_addr.c | ||
README | ||
res_comp.c | ||
res_data.c | ||
res_debug.c | ||
res_hconf.c | ||
res_hconf.h | ||
res_init.c | ||
res_libc.c | ||
res_mkquery.c | ||
res_query.c | ||
res_randomid.c | ||
res_send.c | ||
res_use_inet6.h | ||
res-close.c | ||
res-state.c | ||
resolv_conf.c | ||
resolv_conf.h | ||
resolv_context.c | ||
resolv_context.h | ||
resolv-internal.h | ||
resolv.h | ||
tst-aton.c | ||
tst-bug18665-tcp.c | ||
tst-bug18665.c | ||
tst-inet_ntop.c | ||
tst-inet_pton.c | ||
tst-leaks2.c | ||
tst-leaks.c | ||
tst-ns_name_compress.c | ||
tst-ns_name_pton.c | ||
tst-ns_name.c | ||
tst-ns_name.data | ||
tst-p_secstodate.c | ||
tst-res_hconf_reorder.c | ||
tst-res_hnok.c | ||
tst-res_use_inet6.c | ||
tst-resolv-basic.c | ||
tst-resolv-canonname.c | ||
tst-resolv-edns.c | ||
tst-resolv-network.c | ||
tst-resolv-qtypes.c | ||
tst-resolv-res_init-multi.c | ||
tst-resolv-res_init-skeleton.c | ||
tst-resolv-res_init-thread.c | ||
tst-resolv-res_init.c | ||
tst-resolv-res_ninit.c | ||
tst-resolv-rotate.c | ||
tst-resolv-search.c | ||
tst-resolv-threads.c | ||
Versions |
The resolver in the GNU C Library ********************************* Starting with version 2.2, the resolver in the GNU C Library comes from BIND 8. Only a subset of the src/lib/resolv part of libbind is included here; basically the parts that are needed to provide the functionality present in the resolver from BIND 4.9.7 that was included in the previous release of the GNU C Library, augmented by the parts needed to provide thread-safety. This means that support for things as dynamic DNS updates and TSIG keys isn't included. If you need those facilities, please take a look at the full BIND distribution. Differences =========== The resolver in the GNU C Library still differs from what's in BIND 8.2.3-T5B: * The RES_DEBUG option (`options debug' in /etc/resolv.conf) has been disabled. * The resolver in glibc allows underscores in domain names. * The <resolv.h> header in glibc includes <netinet/in.h> and <arpa/nameser.h> to make it self-contained. * The `res_close' function in glibc only tries to close open files referenced through `_res' if the RES_INIT bit is set in `_res.options'. This fixes a potential security bug with programs that bogusly call `res_close' without initialising the resolver state first. Note that the thread-safe `res_nclose' still doesn't check the RES_INIT bit. By the way, you're not really supposed to call `res_close/res_nclose' directly. * The resolver in glibc can connect to a nameserver over IPv6. Just specify the IPv6 address in /etc/resolv.conf. You cannot change the address of an IPv6 nameserver dynamically in your program though. Using the resolver in multi-threaded code ========================================= The traditional resolver interfaces `res_query', `res_search', `res_mkquery', `res_send' and `res_init', used a static (global) resolver state stored in the `_res' structure. Therefore, these interfaces are not thread-safe. Therefore, BIND 8.2 introduced a set of "new" interfaces `res_nquery', `res_nsearch', `res_nmkquery', `res_nsend' and `res_ninit' that take a `res_state' as their first argument, so you can use a per-thread resolver state. In glibc, when you link with -lpthread, such a per-thread resolver state is already present. It can be accessed using `_res', which has been redefined as a macro, in a similar way to what has been done for the `errno' and `h_errno' variables. This per-thread resolver state is also used for the `gethostby*' family of functions, which means that for example `gethostbyname_r' is now fully thread-safe and re-entrant. The traditional resolver interfaces however, continue to use a single resolver state and are therefore still thread-unsafe. The resolver state is the same resolver state that is used for the initial ("main") thread. This has the following consequences for existing binaries and source code: * Single-threaded programs will continue to work. There should be no user-visible changes when you recompile them. * Multi-threaded programs that use the traditional resolver interfaces in the "main" thread should continue to work, except that they no longer see any changes in the global resolver state caused by calls to, for example, `gethostbyname' in other threads. Again there should be no user-visible changes when you recompile these programs. * Multi-threaded programs that use the traditional resolver interfaces in more than one thread should be just as buggy as before (there are no problems if you use proper locking of course). If you recompile these programs, manipulating the _res structure in threads other than the "main" thread will seem to have no effect though. * In Multi-threaded that manipulate the _res structure, calls to functions like `gethostbyname' in threads other than the "main" thread won't be influenced by the those changes anymore. We recommend to use the new thread-safe interfaces in new code, since the traditional interfaces have been deprecated by the BIND folks. For compatibility with other (older) systems you might want to continue to use those interfaces though. Using the resolver in C++ code ============================== There resolver contains some hooks which will allow the user to install some callback functions that make it possible to filter DNS requests and responses. Although we do not encourage you to make use of this facility at all, C++ developers should realise that it isn't safe to throw exceptions from such callback functions. Source code =========== The following files come from the BIND distribution (currently version 8.2.3-T5B): src/include/ arpa/nameser.h arpa/nameser_compat.h resolv.h src/lib/resolv/ herror.c res_comp.c res_data.c res_debug.c res_init.c res_mkquery.c res_query.c res_send.c src/lib/nameser/ ns_name.c ns_netint.c ns_parse.c ns_print.c ns_samedomain.c ns_ttl.c src/lib/inet/ inet_addr.c inet_net_ntop.c inet_net_pton.c inet_neta.c inet_ntop.c inet_pton.c nsap_addr.c src/lib/isc/ base64.c Some of these files have been optimised a bit, and adaptations have been made to make them fit in with the rest of glibc. res_libc.c is home-brewn, although parts of it are taken from res_data.c. res_hconf.c and res_hconf.h were contributed by David Mosberger, and do not come from BIND. The files gethnamaddr.c, mapv4v6addr.h and mapv4v6hostent.h are leftovers from BIND 4.9.7.