From c6068befe92b8a57c14895fce91c3f9f484112ae Mon Sep 17 00:00:00 2001 From: delphij Date: Wed, 27 Jan 2016 07:41:31 +0000 Subject: Fix multiple vulnerabilities of ntp. [SA-16:09] Fix Linux compatibility layer issetugid(2) system call vulnerability. [SA-16:10] Security: FreeBSD-SA-16:09.ntp Security: FreeBSD-SA-16:10.linux Approved by: so --- contrib/ntp/libntp/Makefile.am | 1 + contrib/ntp/libntp/Makefile.in | 56 ++++++++-------- contrib/ntp/libntp/authkeys.c | 105 ++++++++++++++++++++++++++---- contrib/ntp/libntp/authreadkeys.c | 51 ++++++++++++++- contrib/ntp/libntp/authusekey.c | 2 +- contrib/ntp/libntp/is_ip_address.c | 129 +++++++++++++++++++++++++++++++++++++ contrib/ntp/libntp/ntp_worker.c | 27 ++++++++ contrib/ntp/libntp/systime.c | 15 ++++- contrib/ntp/libntp/work_thread.c | 74 ++++++++++++++++----- 9 files changed, 397 insertions(+), 63 deletions(-) create mode 100644 contrib/ntp/libntp/is_ip_address.c (limited to 'contrib/ntp/libntp') diff --git a/contrib/ntp/libntp/Makefile.am b/contrib/ntp/libntp/Makefile.am index 914badb..a3b50e1 100644 --- a/contrib/ntp/libntp/Makefile.am +++ b/contrib/ntp/libntp/Makefile.am @@ -70,6 +70,7 @@ libntp_a_SRCS = \ humandate.c \ icom.c \ iosignal.c \ + is_ip_address.c \ lib_strbuf.c \ machines.c \ mktime.c \ diff --git a/contrib/ntp/libntp/Makefile.in b/contrib/ntp/libntp/Makefile.in index 6e40cd4..5cf5703 100644 --- a/contrib/ntp/libntp/Makefile.in +++ b/contrib/ntp/libntp/Makefile.in @@ -150,12 +150,12 @@ am__libntp_a_SOURCES_DIST = systime.c a_md5encrypt.c adjtime.c \ calyearstart.c clocktime.c clocktypes.c decodenetnum.c \ dofptoa.c dolfptoa.c emalloc.c findconfig.c getopt.c \ hextoint.c hextolfp.c humandate.c icom.c iosignal.c \ - lib_strbuf.c machines.c mktime.c modetoa.c mstolfp.c msyslog.c \ - netof.c ntp_calendar.c ntp_crypto_rnd.c ntp_intres.c \ - ntp_libopts.c ntp_lineedit.c ntp_random.c ntp_rfc2553.c \ - ntp_worker.c numtoa.c numtohost.c octtoint.c prettydate.c \ - refidsmear.c recvbuff.c refnumtoa.c snprintf.c socket.c \ - socktoa.c socktohost.c ssl_init.c statestr.c strdup.c \ + is_ip_address.c lib_strbuf.c machines.c mktime.c modetoa.c \ + mstolfp.c msyslog.c netof.c ntp_calendar.c ntp_crypto_rnd.c \ + ntp_intres.c ntp_libopts.c ntp_lineedit.c ntp_random.c \ + ntp_rfc2553.c ntp_worker.c numtoa.c numtohost.c octtoint.c \ + prettydate.c refidsmear.c recvbuff.c refnumtoa.c snprintf.c \ + socket.c socktoa.c socktohost.c ssl_init.c statestr.c strdup.c \ strl_obsd.c syssignal.c timetoa.c timevalops.c uglydate.c \ vint64ops.c work_fork.c work_thread.c ymd2yd.c \ $(srcdir)/../lib/isc/assertions.c \ @@ -207,21 +207,21 @@ am__objects_4 = a_md5encrypt.$(OBJEXT) adjtime.$(OBJEXT) \ dolfptoa.$(OBJEXT) emalloc.$(OBJEXT) findconfig.$(OBJEXT) \ getopt.$(OBJEXT) hextoint.$(OBJEXT) hextolfp.$(OBJEXT) \ humandate.$(OBJEXT) icom.$(OBJEXT) iosignal.$(OBJEXT) \ - lib_strbuf.$(OBJEXT) machines.$(OBJEXT) mktime.$(OBJEXT) \ - modetoa.$(OBJEXT) mstolfp.$(OBJEXT) msyslog.$(OBJEXT) \ - netof.$(OBJEXT) ntp_calendar.$(OBJEXT) \ - ntp_crypto_rnd.$(OBJEXT) ntp_intres.$(OBJEXT) \ - ntp_libopts.$(OBJEXT) ntp_lineedit.$(OBJEXT) \ - ntp_random.$(OBJEXT) ntp_rfc2553.$(OBJEXT) \ - ntp_worker.$(OBJEXT) numtoa.$(OBJEXT) numtohost.$(OBJEXT) \ - octtoint.$(OBJEXT) prettydate.$(OBJEXT) refidsmear.$(OBJEXT) \ - recvbuff.$(OBJEXT) refnumtoa.$(OBJEXT) snprintf.$(OBJEXT) \ - socket.$(OBJEXT) socktoa.$(OBJEXT) socktohost.$(OBJEXT) \ - ssl_init.$(OBJEXT) statestr.$(OBJEXT) strdup.$(OBJEXT) \ - strl_obsd.$(OBJEXT) syssignal.$(OBJEXT) timetoa.$(OBJEXT) \ - timevalops.$(OBJEXT) uglydate.$(OBJEXT) vint64ops.$(OBJEXT) \ - work_fork.$(OBJEXT) work_thread.$(OBJEXT) ymd2yd.$(OBJEXT) \ - $(am__objects_3) $(am__objects_1) + is_ip_address.$(OBJEXT) lib_strbuf.$(OBJEXT) \ + machines.$(OBJEXT) mktime.$(OBJEXT) modetoa.$(OBJEXT) \ + mstolfp.$(OBJEXT) msyslog.$(OBJEXT) netof.$(OBJEXT) \ + ntp_calendar.$(OBJEXT) ntp_crypto_rnd.$(OBJEXT) \ + ntp_intres.$(OBJEXT) ntp_libopts.$(OBJEXT) \ + ntp_lineedit.$(OBJEXT) ntp_random.$(OBJEXT) \ + ntp_rfc2553.$(OBJEXT) ntp_worker.$(OBJEXT) numtoa.$(OBJEXT) \ + numtohost.$(OBJEXT) octtoint.$(OBJEXT) prettydate.$(OBJEXT) \ + refidsmear.$(OBJEXT) recvbuff.$(OBJEXT) refnumtoa.$(OBJEXT) \ + snprintf.$(OBJEXT) socket.$(OBJEXT) socktoa.$(OBJEXT) \ + socktohost.$(OBJEXT) ssl_init.$(OBJEXT) statestr.$(OBJEXT) \ + strdup.$(OBJEXT) strl_obsd.$(OBJEXT) syssignal.$(OBJEXT) \ + timetoa.$(OBJEXT) timevalops.$(OBJEXT) uglydate.$(OBJEXT) \ + vint64ops.$(OBJEXT) work_fork.$(OBJEXT) work_thread.$(OBJEXT) \ + ymd2yd.$(OBJEXT) $(am__objects_3) $(am__objects_1) am_libntp_a_OBJECTS = systime.$(OBJEXT) $(am__objects_4) libntp_a_OBJECTS = $(am_libntp_a_OBJECTS) libntpsim_a_AR = $(AR) $(ARFLAGS) @@ -232,12 +232,12 @@ am__libntpsim_a_SOURCES_DIST = systime_s.c a_md5encrypt.c adjtime.c \ calyearstart.c clocktime.c clocktypes.c decodenetnum.c \ dofptoa.c dolfptoa.c emalloc.c findconfig.c getopt.c \ hextoint.c hextolfp.c humandate.c icom.c iosignal.c \ - lib_strbuf.c machines.c mktime.c modetoa.c mstolfp.c msyslog.c \ - netof.c ntp_calendar.c ntp_crypto_rnd.c ntp_intres.c \ - ntp_libopts.c ntp_lineedit.c ntp_random.c ntp_rfc2553.c \ - ntp_worker.c numtoa.c numtohost.c octtoint.c prettydate.c \ - refidsmear.c recvbuff.c refnumtoa.c snprintf.c socket.c \ - socktoa.c socktohost.c ssl_init.c statestr.c strdup.c \ + is_ip_address.c lib_strbuf.c machines.c mktime.c modetoa.c \ + mstolfp.c msyslog.c netof.c ntp_calendar.c ntp_crypto_rnd.c \ + ntp_intres.c ntp_libopts.c ntp_lineedit.c ntp_random.c \ + ntp_rfc2553.c ntp_worker.c numtoa.c numtohost.c octtoint.c \ + prettydate.c refidsmear.c recvbuff.c refnumtoa.c snprintf.c \ + socket.c socktoa.c socktohost.c ssl_init.c statestr.c strdup.c \ strl_obsd.c syssignal.c timetoa.c timevalops.c uglydate.c \ vint64ops.c work_fork.c work_thread.c ymd2yd.c \ $(srcdir)/../lib/isc/assertions.c \ @@ -660,6 +660,7 @@ libntp_a_SRCS = \ humandate.c \ icom.c \ iosignal.c \ + is_ip_address.c \ lib_strbuf.c \ machines.c \ mktime.c \ @@ -806,6 +807,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/inet_pton.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interfaceiter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iosignal.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/is_ip_address.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib_strbuf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@ diff --git a/contrib/ntp/libntp/authkeys.c b/contrib/ntp/libntp/authkeys.c index f7462a2..36fdd8b 100644 --- a/contrib/ntp/libntp/authkeys.c +++ b/contrib/ntp/libntp/authkeys.c @@ -15,6 +15,7 @@ #include "ntp_string.h" #include "ntp_malloc.h" #include "ntp_stdlib.h" +#include "ntp_keyacc.h" /* * Structure to store keys in in the hash table. @@ -25,6 +26,7 @@ struct savekey { symkey * hlink; /* next in hash bucket */ DECL_DLIST_LINK(symkey, llink); /* for overall & free lists */ u_char * secret; /* shared secret */ + KeyAccT * keyacclist; /* Private key access list */ u_long lifetime; /* remaining lifetime */ keyid_t keyid; /* key identifier */ u_short type; /* OpenSSL digest NID */ @@ -48,13 +50,13 @@ struct symkey_alloc_tag { symkey_alloc * authallocs; #endif /* DEBUG */ -static inline u_short auth_log2(double x); -static void auth_resize_hashtable(void); -static void allocsymkey(symkey **, keyid_t, u_short, - u_short, u_long, u_short, u_char *); -static void freesymkey(symkey *, symkey **); +static u_short auth_log2(size_t); +static void auth_resize_hashtable(void); +static void allocsymkey(symkey **, keyid_t, u_short, u_short, + u_long, u_short, u_char *, KeyAccT *); +static void freesymkey(symkey *, symkey **); #ifdef DEBUG -static void free_auth_mem(void); +static void free_auth_mem(void); #endif symkey key_listhead; /* list of all in-use keys */; @@ -97,6 +99,7 @@ u_char *cache_secret; /* secret */ u_short cache_secretsize; /* secret length */ int cache_type; /* OpenSSL digest NID */ u_short cache_flags; /* flags that wave */ +KeyAccT *cache_keyacclist; /* key access list */ /* @@ -142,6 +145,7 @@ free_auth_mem(void) key_hash = NULL; cache_keyid = 0; cache_flags = 0; + cache_keyacclist = NULL; for (alloc = authallocs; alloc != NULL; alloc = next_alloc) { next_alloc = alloc->link; free(alloc->mem); @@ -210,10 +214,33 @@ auth_prealloc_symkeys( } -static inline u_short -auth_log2(double x) +static u_short +auth_log2(size_t x) { - return (u_short)(log10(x) / log10(2)); + /* + ** bithack to calculate floor(log2(x)) + ** + ** This assumes + ** - (sizeof(size_t) is a power of two + ** - CHAR_BITS is a power of two + ** - returning zero for arguments <= 0 is OK. + ** + ** Does only shifts, masks and sums in integer arithmetic in + ** log2(CHAR_BIT*sizeof(size_t)) steps. (that is, 5/6 steps for + ** 32bit/64bit size_t) + */ + int s; + int r = 0; + size_t m = ~(size_t)0; + + for (s = sizeof(size_t) / 2 * CHAR_BIT; s != 0; s >>= 1) { + m <<= s; + if (x & m) + r += s; + else + x <<= s; + } + return (u_short)r; } @@ -234,7 +261,7 @@ auth_resize_hashtable(void) symkey * sk; totalkeys = authnumkeys + authnumfreekeys; - hashbits = auth_log2(totalkeys / 4.0) + 1; + hashbits = auth_log2(totalkeys / 4) + 1; hashbits = max(4, hashbits); hashbits = min(15, hashbits); @@ -267,7 +294,8 @@ allocsymkey( u_short type, u_long lifetime, u_short secretsize, - u_char * secret + u_char * secret, + KeyAccT * ka ) { symkey * sk; @@ -281,6 +309,7 @@ allocsymkey( sk->type = type; sk->secretsize = secretsize; sk->secret = secret; + sk->keyacclist = ka; sk->lifetime = lifetime; LINK_SLIST(*bucket, sk, hlink); LINK_TAIL_DLIST(key_listhead, sk, llink); @@ -412,6 +441,7 @@ authhavekey( cache_flags = sk->flags; cache_secret = sk->secret; cache_secretsize = sk->secretsize; + cache_keyacclist = sk->keyacclist; return TRUE; } @@ -451,6 +481,7 @@ authtrust( if (cache_keyid == id) { cache_flags = 0; cache_keyid = 0; + cache_keyacclist = NULL; } /* @@ -480,7 +511,7 @@ authtrust( } else { lifetime = 0; } - allocsymkey(bucket, id, KEY_TRUSTED, 0, lifetime, 0, NULL); + allocsymkey(bucket, id, KEY_TRUSTED, 0, lifetime, 0, NULL, NULL); } @@ -511,6 +542,49 @@ authistrusted( return TRUE; } + +/* + * authistrustedip - determine if the IP is OK for the keyid + */ + int + authistrustedip( + keyid_t keyno, + sockaddr_u * sau + ) +{ + symkey * sk; + symkey ** bucket; + KeyAccT * kal; + KeyAccT * k; + + if (keyno == cache_keyid) + kal = cache_keyacclist; + else { + authkeyuncached++; + bucket = &key_hash[KEYHASH(keyno)]; + for (sk = *bucket; sk != NULL; sk = sk->hlink) { + if (keyno == sk->keyid) + break; + } + if (NULL == sk || !(KEY_TRUSTED & sk->flags)) { + INSIST(!"authistrustedip: keyid not found/trusted!"); + return FALSE; + } + kal = sk->keyacclist; + } + + if (NULL == kal) + return TRUE; + + for (k = kal; k; k = k->next) { + if (SOCK_EQ(&k->addr, sau)) + return TRUE; + } + + return FALSE; +} + + /* Note: There are two locations below where 'strncpy()' is used. While * this function is a hazard by itself, it's essential that it is used * here. Bug 1243 involved that the secret was filled with NUL bytes @@ -527,7 +601,8 @@ MD5auth_setkey( keyid_t keyno, int keytype, const u_char *key, - size_t len + size_t len, + KeyAccT *ka ) { symkey * sk; @@ -553,6 +628,7 @@ MD5auth_setkey( sk->type = (u_short)keytype; secretsize = len; sk->secretsize = (u_short)secretsize; + sk->keyacclist = ka; #ifndef DISABLE_BUG1243_FIX memcpy(sk->secret, key, secretsize); #else @@ -563,6 +639,7 @@ MD5auth_setkey( if (cache_keyid == keyno) { cache_flags = 0; cache_keyid = 0; + cache_keyacclist = NULL; } return; } @@ -580,7 +657,7 @@ MD5auth_setkey( strncpy((char *)secret, (const char *)key, secretsize); #endif allocsymkey(bucket, keyno, 0, (u_short)keytype, 0, - (u_short)secretsize, secret); + (u_short)secretsize, secret, ka); #ifdef DEBUG if (debug >= 4) { size_t j; diff --git a/contrib/ntp/libntp/authreadkeys.c b/contrib/ntp/libntp/authreadkeys.c index 95a357a..1d4ee30 100644 --- a/contrib/ntp/libntp/authreadkeys.c +++ b/contrib/ntp/libntp/authreadkeys.c @@ -5,10 +5,12 @@ #include #include +#include "ntpd.h" /* Only for DPRINTF */ #include "ntp_fp.h" #include "ntp.h" #include "ntp_syslog.h" #include "ntp_stdlib.h" +#include "ntp_keyacc.h" #ifdef OPENSSL #include "openssl/objects.h" @@ -85,6 +87,7 @@ static void log_maybe(u_int*, const char*, ...) NTP_PRINTF(2, 3); typedef struct keydata KeyDataT; struct keydata { KeyDataT *next; /* queue/stack link */ + KeyAccT *keyacclist; /* key access list */ keyid_t keyid; /* stored key ID */ u_short keytype; /* stored key type */ u_short seclen; /* length of secret */ @@ -228,6 +231,7 @@ authreadkeys( len = strlen(token); if (len <= 20) { /* Bug 2537 */ next = emalloc(sizeof(KeyDataT) + len); + next->keyacclist = NULL; next->keyid = keyno; next->keytype = keytype; next->seclen = len; @@ -257,11 +261,48 @@ authreadkeys( } len = jlim/2; /* hmmmm.... what about odd length?!? */ next = emalloc(sizeof(KeyDataT) + len); + next->keyacclist = NULL; next->keyid = keyno; next->keytype = keytype; next->seclen = len; memcpy(next->secbuf, keystr, len); } + + token = nexttok(&line); +DPRINTF(0, ("authreadkeys: full access list <%s>\n", (token) ? token : "NULL")); + if (token != NULL) { /* A comma-separated IP access list */ + char *tp = token; + + while (tp) { + char *i; + KeyAccT ka; + + i = strchr(tp, (int)','); + if (i) + *i = '\0'; +DPRINTF(0, ("authreadkeys: access list: <%s>\n", tp)); + + if (is_ip_address(tp, AF_UNSPEC, &ka.addr)) { + KeyAccT *kap; + + kap = emalloc(sizeof(KeyAccT)); + memcpy(kap, &ka, sizeof ka); + kap->next = next->keyacclist; + next->keyacclist = kap; + } else { + log_maybe(&nerr, + "authreadkeys: invalid IP address <%s> for key %d", + tp, keyno); + } + + if (i) { + tp = i + 1; + } else { + tp = 0; + } + } + } + INSIST(NULL != next); next->next = list; list = next; @@ -286,7 +327,7 @@ authreadkeys( while (NULL != (next = list)) { list = next->next; MD5auth_setkey(next->keyid, next->keytype, - next->secbuf, next->seclen); + next->secbuf, next->seclen, next->keyacclist); /* purge secrets from memory before free()ing it */ memset(next, 0, sizeof(*next) + next->seclen); free(next); @@ -297,6 +338,14 @@ authreadkeys( /* Mop up temporary storage before bailing out. */ while (NULL != (next = list)) { list = next->next; + + while (next->keyacclist) { + KeyAccT *kap = next->keyacclist; + + next->keyacclist = kap->next; + free(kap); + } + /* purge secrets from memory before free()ing it */ memset(next, 0, sizeof(*next) + next->seclen); free(next); diff --git a/contrib/ntp/libntp/authusekey.c b/contrib/ntp/libntp/authusekey.c index 0ccf522..ff449d3 100644 --- a/contrib/ntp/libntp/authusekey.c +++ b/contrib/ntp/libntp/authusekey.c @@ -29,6 +29,6 @@ authusekey( if (0 == len) return 0; - MD5auth_setkey(keyno, keytype, str, len); + MD5auth_setkey(keyno, keytype, str, len, NULL); return 1; } diff --git a/contrib/ntp/libntp/is_ip_address.c b/contrib/ntp/libntp/is_ip_address.c new file mode 100644 index 0000000..1f21376 --- /dev/null +++ b/contrib/ntp/libntp/is_ip_address.c @@ -0,0 +1,129 @@ +/* + * is_ip_address + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if 0 +#include +#include +#ifdef HAVE_FNMATCH_H +# include +# if !defined(FNM_CASEFOLD) && defined(FNM_IGNORECASE) +# define FNM_CASEFOLD FNM_IGNORECASE +# endif +#endif +#ifdef HAVE_SYS_PARAM_H +# include +#endif +#ifdef HAVE_SYS_IOCTL_H +# include +#endif +#ifdef HAVE_SYS_SOCKIO_H /* UXPV: SIOC* #defines (Frank Vance ) */ +# include +#endif +#ifdef HAVE_SYS_UIO_H +# include +#endif +#endif + +#include "ntp_assert.h" +#include "ntp_stdlib.h" +#include "safecast.h" + +#if 0 +#include "ntp_machine.h" +#include "ntpd.h" +#include "ntp_io.h" +#include "iosignal.h" +#include "ntp_lists.h" +#include "ntp_refclock.h" +#include "ntp_worker.h" +#include "ntp_request.h" +#include "timevalops.h" +#include "timespecops.h" +#include "ntpd-opts.h" +#endif + +/* Don't include ISC's version of IPv6 variables and structures */ +#define ISC_IPV6_H 1 +#include +#include +#include +#include +#include + + +/* + * Code to tell if we have an IP address + * If we have then return the sockaddr structure + * and set the return value + * see the bind9/getaddresses.c for details + */ +int +is_ip_address( + const char * host, + u_short af, + sockaddr_u * addr + ) +{ + struct in_addr in4; + struct addrinfo hints; + struct addrinfo *result; + struct sockaddr_in6 *resaddr6; + char tmpbuf[128]; + char *pch; + + REQUIRE(host != NULL); + REQUIRE(addr != NULL); + + ZERO_SOCK(addr); + + /* + * Try IPv4, then IPv6. In order to handle the extended format + * for IPv6 scoped addresses (address%scope_ID), we'll use a local + * working buffer of 128 bytes. The length is an ad-hoc value, but + * should be enough for this purpose; the buffer can contain a string + * of at least 80 bytes for scope_ID in addition to any IPv6 numeric + * addresses (up to 46 bytes), the delimiter character and the + * terminating NULL character. + */ + if (AF_UNSPEC == af || AF_INET == af) + if (inet_pton(AF_INET, host, &in4) == 1) { + AF(addr) = AF_INET; + SET_ADDR4N(addr, in4.s_addr); + + return TRUE; + } + + if (AF_UNSPEC == af || AF_INET6 == af) + if (sizeof(tmpbuf) > strlen(host)) { + if ('[' == host[0]) { + strlcpy(tmpbuf, &host[1], sizeof(tmpbuf)); + pch = strchr(tmpbuf, ']'); + if (pch != NULL) + *pch = '\0'; + } else { + strlcpy(tmpbuf, host, sizeof(tmpbuf)); + } + ZERO(hints); + hints.ai_family = AF_INET6; + hints.ai_flags |= AI_NUMERICHOST; + if (getaddrinfo(tmpbuf, NULL, &hints, &result) == 0) { + AF(addr) = AF_INET6; + resaddr6 = UA_PTR(struct sockaddr_in6, result->ai_addr); + SET_ADDR6N(addr, resaddr6->sin6_addr); + SET_SCOPE(addr, resaddr6->sin6_scope_id); + + freeaddrinfo(result); + return TRUE; + } + } + /* + * If we got here it was not an IP address + */ + return FALSE; +} diff --git a/contrib/ntp/libntp/ntp_worker.c b/contrib/ntp/libntp/ntp_worker.c index f5642e1..087f06c 100644 --- a/contrib/ntp/libntp/ntp_worker.c +++ b/contrib/ntp/libntp/ntp_worker.c @@ -27,6 +27,8 @@ blocking_child ** blocking_children; size_t blocking_children_alloc; int worker_per_query; /* boolean */ int intres_req_pending; +volatile u_int blocking_child_ready_seen; +volatile u_int blocking_child_ready_done; #ifndef HAVE_IO_COMPLETION_PORT @@ -262,6 +264,31 @@ process_blocking_resp( req_child_exit(c); } +void +harvest_blocking_responses(void) +{ + int idx; + blocking_child* cp; + u_int scseen, scdone; + + scseen = blocking_child_ready_seen; + scdone = blocking_child_ready_done; + if (scdone != scseen) { + blocking_child_ready_done = scseen; + for (idx = 0; idx < blocking_children_alloc; idx++) { + cp = blocking_children[idx]; + if (NULL == cp) + continue; + scseen = cp->resp_ready_seen; + scdone = cp->resp_ready_done; + if (scdone != scseen) { + cp->resp_ready_done = scseen; + process_blocking_resp(cp); + } + } + } +} + /* * blocking_child_common runs as a forked child or a thread diff --git a/contrib/ntp/libntp/systime.c b/contrib/ntp/libntp/systime.c index c89d157..29f1e86 100644 --- a/contrib/ntp/libntp/systime.c +++ b/contrib/ntp/libntp/systime.c @@ -323,9 +323,18 @@ adj_systime( else quant = 1e-6; ticks = (long)(dtemp / quant + .5); - adjtv.tv_usec = (long)(ticks * quant * 1e6); - dtemp -= adjtv.tv_usec / 1e6; - sys_residual = dtemp; + adjtv.tv_usec = (long)(ticks * quant * 1.e6 + .5); + /* The rounding in the conversions could us push over the + * limits: make sure the result is properly normalised! + * note: sign comes later, all numbers non-negative here. + */ + if (adjtv.tv_usec >= 1000000) { + adjtv.tv_sec += 1; + adjtv.tv_usec -= 1000000; + dtemp -= 1.; + } + /* set the new residual with leftover from correction */ + sys_residual = dtemp - adjtv.tv_usec * 1.e-6; /* * Convert to signed seconds and microseconds for the Unix diff --git a/contrib/ntp/libntp/work_thread.c b/contrib/ntp/libntp/work_thread.c index 49e90c1..11e3267 100644 --- a/contrib/ntp/libntp/work_thread.c +++ b/contrib/ntp/libntp/work_thread.c @@ -25,13 +25,38 @@ #define CHILD_EXIT_REQ ((blocking_pipe_header *)(intptr_t)-1) #define CHILD_GONE_RESP CHILD_EXIT_REQ +/* Queue size increments: + * The request queue grows a bit faster than the response queue -- the + * deamon can push requests and pull results faster on avarage than the + * worker can process requests and push results... If this really pays + * off is debatable. + */ #define WORKITEMS_ALLOC_INC 16 #define RESPONSES_ALLOC_INC 4 +/* Fiddle with min/max stack sizes. 64kB minimum seems to work, so we + * set the maximum to 256kB. If the minimum goes below the + * system-defined minimum stack size, we have to adjust accordingly. + */ #ifndef THREAD_MINSTACKSIZE -#define THREAD_MINSTACKSIZE (64U * 1024) +# define THREAD_MINSTACKSIZE (64U * 1024) +#endif +#ifndef __sun +#if defined(PTHREAD_STACK_MIN) && THREAD_MINSTACKSIZE < PTHREAD_STACK_MIN +# undef THREAD_MINSTACKSIZE +# define THREAD_MINSTACKSIZE PTHREAD_STACK_MIN +#endif #endif +#ifndef THREAD_MAXSTACKSIZE +# define THREAD_MAXSTACKSIZE (256U * 1024) +#endif +#if THREAD_MAXSTACKSIZE < THREAD_MINSTACKSIZE +# undef THREAD_MAXSTACKSIZE +# define THREAD_MAXSTACKSIZE THREAD_MINSTACKSIZE +#endif + + #ifdef SYS_WINNT # define thread_exit(c) _endthreadex(c) @@ -148,15 +173,19 @@ ensure_workitems_empty_slot( size_t new_alloc; size_t slots_used; + size_t sidx; slots_used = c->head_workitem - c->tail_workitem; if (slots_used >= c->workitems_alloc) { new_alloc = c->workitems_alloc + WORKITEMS_ALLOC_INC; c->workitems = erealloc(c->workitems, new_alloc * each); + for (sidx = c->workitems_alloc; sidx < new_alloc; ++sidx) + c->workitems[sidx] = NULL; c->tail_workitem = 0; c->head_workitem = c->workitems_alloc; c->workitems_alloc = new_alloc; } + INSIST(NULL == c->workitems[c->head_workitem % c->workitems_alloc]); return (0 == slots_used); } @@ -180,15 +209,19 @@ ensure_workresp_empty_slot( size_t new_alloc; size_t slots_used; + size_t sidx; slots_used = c->head_response - c->tail_response; if (slots_used >= c->responses_alloc) { new_alloc = c->responses_alloc + RESPONSES_ALLOC_INC; c->responses = erealloc(c->responses, new_alloc * each); + for (sidx = c->responses_alloc; sidx < new_alloc; ++sidx) + c->responses[sidx] = NULL; c->tail_response = 0; c->head_response = c->responses_alloc; c->responses_alloc = new_alloc; } + INSIST(NULL == c->responses[c->head_response % c->responses_alloc]); return (0 == slots_used); } @@ -478,11 +511,11 @@ start_blocking_thread_internal( # endif pthread_attr_t thr_attr; int rc; - int saved_errno; int pipe_ends[2]; /* read then write */ int is_pipe; int flags; - size_t stacksize; + size_t ostacksize; + size_t nstacksize; sigset_t saved_sig_mask; c->thread_ref = NULL; @@ -522,21 +555,29 @@ start_blocking_thread_internal( pthread_attr_setdetachstate(&thr_attr, PTHREAD_CREATE_DETACHED); #if defined(HAVE_PTHREAD_ATTR_GETSTACKSIZE) && \ defined(HAVE_PTHREAD_ATTR_SETSTACKSIZE) - rc = pthread_attr_getstacksize(&thr_attr, &stacksize); - if (-1 == rc) { + rc = pthread_attr_getstacksize(&thr_attr, &ostacksize); + if (0 != rc) { msyslog(LOG_ERR, - "start_blocking_thread: pthread_attr_getstacksize %m"); - } else if (stacksize < THREAD_MINSTACKSIZE) { - rc = pthread_attr_setstacksize(&thr_attr, - THREAD_MINSTACKSIZE); - if (-1 == rc) + "start_blocking_thread: pthread_attr_getstacksize() -> %s", + strerror(rc)); + } else { + if (ostacksize < THREAD_MINSTACKSIZE) + nstacksize = THREAD_MINSTACKSIZE; + else if (ostacksize > THREAD_MAXSTACKSIZE) + nstacksize = THREAD_MAXSTACKSIZE; + else + nstacksize = ostacksize; + if (nstacksize != ostacksize) + rc = pthread_attr_setstacksize(&thr_attr, nstacksize); + if (0 != rc) msyslog(LOG_ERR, - "start_blocking_thread: pthread_attr_setstacksize(0x%lx -> 0x%lx) %m", - (u_long)stacksize, - (u_long)THREAD_MINSTACKSIZE); + "start_blocking_thread: pthread_attr_setstacksize(0x%lx -> 0x%lx) -> %s", + (u_long)ostacksize, (u_long)nstacksize, + strerror(rc)); } #else - UNUSED_ARG(stacksize); + UNUSED_ARG(nstacksize); + UNUSED_ARG(ostacksize); #endif #if defined(PTHREAD_SCOPE_SYSTEM) && defined(NEED_PTHREAD_SCOPE_SYSTEM) pthread_attr_setscope(&thr_attr, PTHREAD_SCOPE_SYSTEM); @@ -545,12 +586,11 @@ start_blocking_thread_internal( block_thread_signals(&saved_sig_mask); rc = pthread_create(&c->thr_table[0], &thr_attr, &blocking_thread, c); - saved_errno = errno; pthread_sigmask(SIG_SETMASK, &saved_sig_mask, NULL); pthread_attr_destroy(&thr_attr); if (0 != rc) { - errno = saved_errno; - msyslog(LOG_ERR, "pthread_create() blocking child: %m"); + msyslog(LOG_ERR, "start_blocking_thread: pthread_create() -> %s", + strerror(rc)); exit(1); } c->thread_ref = &c->thr_table[0]; -- cgit v1.1