Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package haproxy for openSUSE:Factory checked in at 2021-04-06 17:29:34 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/haproxy (Old) and /work/SRC/openSUSE:Factory/.haproxy.new.2401 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "haproxy" Tue Apr 6 17:29:34 2021 rev:101 rq:882208 version:2.3.9+git1.afb63bc04 Changes: -------- --- /work/SRC/openSUSE:Factory/haproxy/haproxy.changes 2021-03-19 16:39:46.257839889 +0100 +++ /work/SRC/openSUSE:Factory/.haproxy.new.2401/haproxy.changes 2021-04-06 17:30:52.555198029 +0200 @@ -1,0 +2,40 @@ +Tue Mar 30 17:35:22 UTC 2021 - [email protected] + +- Update to version 2.3.9+git1.afb63bc04: + * BUILD: backend: fix build breakage in idle conn locking fix + * [RELEASE] Released version 2.3.9 + * BUG/MEDIUM: time: make sure to always initialize the global tick + * BUG/MINOR: stats: Apply proper styles in HTML status page. + * BUG/MINOR: payload: Wait for more data if buffer is empty in payload/payload_lv + * MEDIUM: backend: use a trylock to grab a connection on high FD counts as well + * BUG/MEDIUM: mux-h1: make h1_shutw_conn() idempotent + +------------------------------------------------------------------- +Thu Mar 25 15:51:22 UTC 2021 - [email protected] + +- Update to version 2.3.8+git0.e572195c7: + * [RELEASE] Released version 2.3.8 + * BUG/MINOR: http_fetch: make hdr_ip() reject trailing characters + * MINOR: tools: make url2ipv4 return the exact number of bytes parsed + * BUG/MEDIUM: thread: Fix a deadlock if an isolated thread is marked as harmless + * BUG/MEDIUM: fd: Take the fd_mig_lock when closing if no DWCAS is available. + * CLEANUP: fd: remove unused fd_set_running_excl() + * BUG/MEDIUM: fd: do not wait on FD removal in fd_delete() + * MINOR: fd: remove the unneeded running bit from fd_insert() + * MINOR: fd: make fd_clr_running() return the remaining running mask + * BUG/MEDIUM: lua: Always init the lua stack before referencing the context + * BUG/MEDIUM: debug/lua: Use internal hlua function to dump the lua traceback + * MINOR: lua: Slightly improve function dumping the lua traceback + * BUILD: ssl: guard ecdh functions with SSL_CTX_set_tmp_ecdh macro + * BUG/MINOR: ssl: Prevent disk access when using "add ssl crt-list" + * BUG/MEDIUM: debug/lua: Don't dump the lua stack if not dumpable + * MEDIUM: lua: Use a per-thread counter to track some non-reentrant parts of lua + * MINOR/BUG: mworker/cli: do not use the unix_bind prefix for the master CLI socket + * BUG/MINOR: protocol: add missing support of dgram unix socket. + * BUG/MEDIUM: freq_ctr/threads: use the global_now_ms variable + * MINOR: time: also provide a global, monotonic global_now_ms timer + * BUG/MEDIUM: mux-fcgi: Fix locking of idle_conns lock in the FCGI I/O callback + * BUG/MINOR: freq_ctr/threads: make use of the last updated global time + * MINOR: time: export the global_now variable + +------------------------------------------------------------------- Old: ---- haproxy-2.3.7+git0.2d39ce334.tar.gz New: ---- haproxy-2.3.9+git1.afb63bc04.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ haproxy.spec ++++++ --- /var/tmp/diff_new_pack.1wa2Eb/_old 2021-04-06 17:30:53.247198812 +0200 +++ /var/tmp/diff_new_pack.1wa2Eb/_new 2021-04-06 17:30:53.251198816 +0200 @@ -53,7 +53,7 @@ %endif Name: haproxy -Version: 2.3.7+git0.2d39ce334 +Version: 2.3.9+git1.afb63bc04 Release: 0 # # ++++++ _service ++++++ --- /var/tmp/diff_new_pack.1wa2Eb/_old 2021-04-06 17:30:53.291198862 +0200 +++ /var/tmp/diff_new_pack.1wa2Eb/_new 2021-04-06 17:30:53.295198866 +0200 @@ -6,7 +6,7 @@ <param name="versionformat">@PARENT_TAG@+git@TAG_OFFSET@.%h</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="versionrewrite-replacement">\1</param> - <param name="revision">v2.3.7</param> + <param name="revision">v2.3.9</param> <param name="changesgenerate">enable</param> </service> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.1wa2Eb/_old 2021-04-06 17:30:53.319198893 +0200 +++ /var/tmp/diff_new_pack.1wa2Eb/_new 2021-04-06 17:30:53.319198893 +0200 @@ -7,4 +7,4 @@ <param name="url">http://git.haproxy.org/git/haproxy-2.2.git</param> <param name="changesrevision">34b2b106689c8a017eb5726193b199ea96f2c9f7</param></service><service name="tar_scm"> <param name="url">http://git.haproxy.org/git/haproxy-2.3.git</param> - <param name="changesrevision">2d39ce334654fae7760f8708d50477150e7af87c</param></service></servicedata> \ No newline at end of file + <param name="changesrevision">afb63bc040ab53db7520eaef49b79970d2b636d9</param></service></servicedata> \ No newline at end of file ++++++ haproxy-2.3.7+git0.2d39ce334.tar.gz -> haproxy-2.3.9+git1.afb63bc04.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/CHANGELOG new/haproxy-2.3.9+git1.afb63bc04/CHANGELOG --- old/haproxy-2.3.7+git0.2d39ce334/CHANGELOG 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/CHANGELOG 2021-03-30 18:51:07.000000000 +0200 @@ -1,6 +1,37 @@ ChangeLog : =========== +2021/03/30 : 2.3.9 + - BUG/MEDIUM: mux-h1: make h1_shutw_conn() idempotent + - MEDIUM: backend: use a trylock to grab a connection on high FD counts as well + - BUG/MINOR: payload: Wait for more data if buffer is empty in payload/payload_lv + - BUG/MINOR: stats: Apply proper styles in HTML status page. + - BUG/MEDIUM: time: make sure to always initialize the global tick + +2021/03/25 : 2.3.8 + - MINOR: time: export the global_now variable + - BUG/MINOR: freq_ctr/threads: make use of the last updated global time + - BUG/MEDIUM: mux-fcgi: Fix locking of idle_conns lock in the FCGI I/O callback + - MINOR: time: also provide a global, monotonic global_now_ms timer + - BUG/MEDIUM: freq_ctr/threads: use the global_now_ms variable + - BUG/MINOR: protocol: add missing support of dgram unix socket. + - MINOR/BUG: mworker/cli: do not use the unix_bind prefix for the master CLI socket + - MEDIUM: lua: Use a per-thread counter to track some non-reentrant parts of lua + - BUG/MEDIUM: debug/lua: Don't dump the lua stack if not dumpable + - BUG/MINOR: ssl: Prevent disk access when using "add ssl crt-list" + - BUILD: ssl: guard ecdh functions with SSL_CTX_set_tmp_ecdh macro + - MINOR: lua: Slightly improve function dumping the lua traceback + - BUG/MEDIUM: debug/lua: Use internal hlua function to dump the lua traceback + - BUG/MEDIUM: lua: Always init the lua stack before referencing the context + - MINOR: fd: make fd_clr_running() return the remaining running mask + - MINOR: fd: remove the unneeded running bit from fd_insert() + - BUG/MEDIUM: fd: do not wait on FD removal in fd_delete() + - CLEANUP: fd: remove unused fd_set_running_excl() + - BUG/MEDIUM: fd: Take the fd_mig_lock when closing if no DWCAS is available. + - BUG/MEDIUM: thread: Fix a deadlock if an isolated thread is marked as harmless + - MINOR: tools: make url2ipv4 return the exact number of bytes parsed + - BUG/MINOR: http_fetch: make hdr_ip() reject trailing characters + 2021/03/16 : 2.3.7 - BUG/MINOR: backend: fix condition for reuse on mode HTTP - BUG/MINOR: hlua: Don't strip last non-LWS char in hlua_pushstrippedstring() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/Makefile new/haproxy-2.3.9+git1.afb63bc04/Makefile --- old/haproxy-2.3.7+git0.2d39ce334/Makefile 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/Makefile 2021-03-30 18:51:07.000000000 +0200 @@ -857,7 +857,7 @@ src/ebimtree.o src/uri_auth.o src/freq_ctr.o src/ebsttree.o \ src/ebistree.o src/auth.o src/wdt.o src/http_acl.o \ src/hpack-enc.o src/hpack-huff.o src/ebtree.o src/base64.o \ - src/hash.o src/dgram.o src/version.o + src/hash.o src/dgram.o src/version.o src/proto_uxdg.o ifneq ($(TRACE),) OBJS += src/calltrace.o diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/VERDATE new/haproxy-2.3.9+git1.afb63bc04/VERDATE --- old/haproxy-2.3.7+git0.2d39ce334/VERDATE 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/VERDATE 2021-03-30 18:51:07.000000000 +0200 @@ -1,2 +1,2 @@ $Format:%ci$ -2021/03/16 +2021/03/30 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/VERSION new/haproxy-2.3.9+git1.afb63bc04/VERSION --- old/haproxy-2.3.7+git0.2d39ce334/VERSION 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/VERSION 2021-03-30 18:51:07.000000000 +0200 @@ -1 +1 @@ -2.3.7 +2.3.9 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/doc/configuration.txt new/haproxy-2.3.9+git1.afb63bc04/doc/configuration.txt --- old/haproxy-2.3.7+git0.2d39ce334/doc/configuration.txt 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/doc/configuration.txt 2021-03-30 18:51:07.000000000 +0200 @@ -4,7 +4,7 @@ ---------------------- version 2.3 willy tarreau - 2021/03/16 + 2021/03/30 This document covers the configuration language as implemented in the version @@ -18330,7 +18330,11 @@ This extracts the last occurrence of header <name> in an HTTP request, converts it to an IPv4 or IPv6 address and returns this address. When used with ACLs, all occurrences are checked, and if <name> is omitted, every value - of every header is checked. + of every header is checked. The parser strictly adheres to the format + described in RFC7239, with the extension that IPv4 addresses may optionally + be followed by a colon (':') and a valid decimal port number (0 to 65535), + which will be silently dropped. All other forms will not match and will + cause the address to be ignored. The <occ> parameter is processed as with req.hdr(). diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/include/haproxy/fd.h new/haproxy-2.3.9+git1.afb63bc04/include/haproxy/fd.h --- old/haproxy-2.3.7+git0.2d39ce334/include/haproxy/fd.h 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/include/haproxy/fd.h 2021-03-30 18:51:07.000000000 +0200 @@ -59,6 +59,7 @@ * The file descriptor is also closed. */ void fd_delete(int fd); +void _fd_delete_orphan(int fd); /* * Take over a FD belonging to another thread. @@ -340,17 +341,12 @@ #endif } -static inline void fd_set_running_excl(int fd) -{ - unsigned long old_mask = 0; - while (!_HA_ATOMIC_CAS(&fdtab[fd].running_mask, &old_mask, tid_bit)) - old_mask = 0; -} - - -static inline void fd_clr_running(int fd) +/* remove tid_bit from the fd's running mask and returns the bits that remain + * after the atomic operation. + */ +static inline long fd_clr_running(int fd) { - _HA_ATOMIC_AND(&fdtab[fd].running_mask, ~tid_bit); + return _HA_ATOMIC_AND(&fdtab[fd].running_mask, ~tid_bit); } /* Update events seen for FD <fd> and its state if needed. This should be @@ -411,7 +407,9 @@ if (fd_set_running(fd) == -1) return; fdtab[fd].iocb(fd); - fd_clr_running(fd); + if ((fdtab[fd].running_mask & tid_bit) && + fd_clr_running(fd) == 0 && !fdtab[fd].thread_mask) + _fd_delete_orphan(fd); } /* we had to stop this FD and it still must be stopped after the I/O @@ -430,11 +428,8 @@ /* Prepares <fd> for being polled */ static inline void fd_insert(int fd, void *owner, void (*iocb)(int fd), unsigned long thread_mask) { - int locked = fdtab[fd].running_mask != tid_bit; extern void conn_fd_handler(int); - if (locked) - fd_set_running_excl(fd); fdtab[fd].owner = owner; fdtab[fd].iocb = iocb; fdtab[fd].ev = 0; @@ -454,8 +449,7 @@ /* note: do not reset polled_mask here as it indicates which poller * still knows this FD from a possible previous round. */ - if (locked) - fd_clr_running(fd); + /* the two directions are ready until proven otherwise */ fd_may_both(fd); _HA_ATOMIC_ADD(&ha_used_fds, 1); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/include/haproxy/freq_ctr.h new/haproxy-2.3.9+git1.afb63bc04/include/haproxy/freq_ctr.h --- old/haproxy-2.3.7+git0.2d39ce334/include/haproxy/freq_ctr.h 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/include/haproxy/freq_ctr.h 2021-03-30 18:51:07.000000000 +0200 @@ -36,6 +36,7 @@ { int elapsed; unsigned int curr_sec; + uint32_t now_tmp; /* we manipulate curr_ctr using atomic ops out of the lock, since @@ -47,16 +48,17 @@ * same uncertainty as well. */ curr_sec = ctr->curr_sec; - if (curr_sec == (now.tv_sec & 0x7fffffff)) - return _HA_ATOMIC_ADD(&ctr->curr_ctr, inc); - do { + now_tmp = global_now >> 32; + if (curr_sec == (now_tmp & 0x7fffffff)) + return _HA_ATOMIC_ADD(&ctr->curr_ctr, inc); + /* remove the bit, used for the lock */ curr_sec &= 0x7fffffff; } while (!_HA_ATOMIC_CAS(&ctr->curr_sec, &curr_sec, curr_sec | 0x80000000)); __ha_barrier_atomic_store(); - elapsed = (now.tv_sec & 0x7fffffff)- curr_sec; + elapsed = (now_tmp & 0x7fffffff) - curr_sec; if (unlikely(elapsed > 0)) { ctr->prev_ctr = ctr->curr_ctr; _HA_ATOMIC_SUB(&ctr->curr_ctr, ctr->prev_ctr); @@ -64,7 +66,7 @@ /* we missed more than one second */ ctr->prev_ctr = 0; } - curr_sec = now.tv_sec; + curr_sec = now_tmp; } /* release the lock and update the time in case of rotate. */ @@ -82,25 +84,27 @@ unsigned int period, unsigned int inc) { unsigned int curr_tick; + uint32_t now_ms_tmp; curr_tick = ctr->curr_tick; - if (now_ms - curr_tick < period) - return _HA_ATOMIC_ADD(&ctr->curr_ctr, inc); - do { + now_ms_tmp = global_now_ms; + if (now_ms_tmp - curr_tick < period) + return _HA_ATOMIC_ADD(&ctr->curr_ctr, inc); + /* remove the bit, used for the lock */ curr_tick &= ~1; } while (!_HA_ATOMIC_CAS(&ctr->curr_tick, &curr_tick, curr_tick | 0x1)); __ha_barrier_atomic_store(); - if (now_ms - curr_tick >= period) { + if (now_ms_tmp - curr_tick >= period) { ctr->prev_ctr = ctr->curr_ctr; _HA_ATOMIC_SUB(&ctr->curr_ctr, ctr->prev_ctr); curr_tick += period; - if (likely(now_ms - curr_tick >= period)) { + if (likely(now_ms_tmp - curr_tick >= period)) { /* we missed at least two periods */ ctr->prev_ctr = 0; - curr_tick = now_ms; + curr_tick = now_ms_tmp; } curr_tick &= ~1; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/include/haproxy/hlua.h new/haproxy-2.3.9+git1.afb63bc04/include/haproxy/hlua.h --- old/haproxy-2.3.7+git0.2d39ce334/include/haproxy/hlua.h 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/include/haproxy/hlua.h 2021-03-30 18:51:07.000000000 +0200 @@ -43,6 +43,7 @@ #define HLUA_INIT(__hlua) do { (__hlua)->T = 0; } while(0) /* Lua HAProxy integration functions. */ +const char *hlua_traceback(lua_State *L, const char* sep); void hlua_ctx_destroy(struct hlua *lua); void hlua_init(); int hlua_post_init(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/include/haproxy/listener-t.h new/haproxy-2.3.9+git1.afb63bc04/include/haproxy/listener-t.h --- old/haproxy-2.3.7+git0.2d39ce334/include/haproxy/listener-t.h 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/include/haproxy/listener-t.h 2021-03-30 18:51:07.000000000 +0200 @@ -239,7 +239,7 @@ }; struct ssl_bind_kw { const char *kw; - int (*parse)(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err); + int (*parse)(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err); int skip; /* nb of args to skip */ }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/include/haproxy/ssl_crtlist.h new/haproxy-2.3.9+git1.afb63bc04/include/haproxy/ssl_crtlist.h --- old/haproxy-2.3.7+git0.2d39ce334/include/haproxy/ssl_crtlist.h 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/include/haproxy/ssl_crtlist.h 2021-03-30 18:51:07.000000000 +0200 @@ -38,7 +38,7 @@ struct crtlist *crtlist_new(const char *filename, int unique); /* file loading */ -int crtlist_parse_line(char *line, char **crt_path, struct crtlist_entry *entry, const char *file, int linenum, char **err); +int crtlist_parse_line(char *line, char **crt_path, struct crtlist_entry *entry, const char *file, int linenum, int from_cli, char **err); int crtlist_parse_file(char *file, struct bind_conf *bind_conf, struct proxy *curproxy, struct crtlist **crtlist, char **err); int crtlist_load_cert_dir(char *path, struct bind_conf *bind_conf, struct crtlist **crtlist, char **err); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/include/haproxy/ssl_sock.h new/haproxy-2.3.9+git1.afb63bc04/include/haproxy/ssl_sock.h --- old/haproxy-2.3.7+git0.2d39ce334/include/haproxy/ssl_sock.h 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/include/haproxy/ssl_sock.h 2021-03-30 18:51:07.000000000 +0200 @@ -104,7 +104,7 @@ void ssl_free_global_issuers(void); int ssl_sock_load_cert_list_file(char *file, int dir, struct bind_conf *bind_conf, struct proxy *curproxy, char **err); int ssl_init_single_engine(const char *engine_id, const char *def_algorithms); -int ssl_store_load_locations_file(char *path); +int ssl_store_load_locations_file(char *path, int create_if_none); /* ssl shctx macro */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/include/haproxy/time.h new/haproxy-2.3.9+git1.afb63bc04/include/haproxy/time.h --- old/haproxy-2.3.7+git0.2d39ce334/include/haproxy/time.h 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/include/haproxy/time.h 2021-03-30 18:51:07.000000000 +0200 @@ -60,6 +60,8 @@ extern struct timeval start_date; /* the process's start date */ extern THREAD_LOCAL struct timeval before_poll; /* system date before calling poll() */ extern THREAD_LOCAL struct timeval after_poll; /* system date after leaving poll() */ +extern volatile unsigned long long global_now; +extern volatile unsigned int global_now_ms; /**** exported functions *************************************************/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/reg-tests/ssl/add_ssl_crt-list.vtc new/haproxy-2.3.9+git1.afb63bc04/reg-tests/ssl/add_ssl_crt-list.vtc --- old/haproxy-2.3.7+git0.2d39ce334/reg-tests/ssl/add_ssl_crt-list.vtc 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/reg-tests/ssl/add_ssl_crt-list.vtc 2021-03-30 18:51:07.000000000 +0200 @@ -93,3 +93,22 @@ rxresp expect resp.status == 200 } -run + + +# Try to add a new line that mentions an "unknown" CA file (not loaded yet). +# It should fail since no disk access are allowed during runtime. +shell { + printf "add ssl crt-list ${testdir}/localhost.crt-list/ <<\n${testdir}/ecdsa.pem [ca-file ${testdir}/ca-auth.crt] localhost\n\n" | socat "${tmpdir}/h1/stats" - | grep "unable to load ${testdir}/ca-auth.crt" +} +shell { + printf "add ssl crt-list ${testdir}/localhost.crt-list/ <<\n${testdir}/ecdsa.pem [ca-verify-file ${testdir}/ca-auth.crt] localhost\n\n" | socat "${tmpdir}/h1/stats" - | grep "unable to load ${testdir}/ca-auth.crt" +} +shell { + printf "add ssl crt-list ${testdir}/localhost.crt-list/ <<\n${testdir}/ecdsa.pem [crl-file ${testdir}/ca-auth.crt] localhost\n\n" | socat "${tmpdir}/h1/stats" - | grep "unable to load ${testdir}/ca-auth.crt" +} + +# Check that the new line was not added to the crt-list. +haproxy h1 -cli { + send "show ssl crt-list ${testdir}/localhost.crt-list//" + expect !~ ".*ca-file ${testdir}/ca-auth.crt" +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/backend.c new/haproxy-2.3.9+git1.afb63bc04/src/backend.c --- old/haproxy-2.3.7+git0.2d39ce334/src/backend.c 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/src/backend.c 2021-03-30 18:51:07.000000000 +0200 @@ -1358,7 +1358,9 @@ // see it possibly larger. ALREADY_CHECKED(i); - HA_SPIN_LOCK(OTHER_LOCK, &idle_conns[i].takeover_lock); + if (HA_SPIN_TRYLOCK(OTHER_LOCK, &idle_conns[i].takeover_lock) != 0) + continue; + tokill_conn = MT_LIST_POP(&srv->idle_conns[i], struct connection *, list); if (!tokill_conn) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/cfgparse-ssl.c new/haproxy-2.3.9+git1.afb63bc04/src/cfgparse-ssl.c --- old/haproxy-2.3.7+git0.2d39ce334/src/cfgparse-ssl.c 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/src/cfgparse-ssl.c 2021-03-30 18:51:07.000000000 +0200 @@ -530,7 +530,7 @@ /***************************** Bind keyword Parsing ********************************************/ /* for ca-file and ca-verify-file */ -static int ssl_bind_parse_ca_file_common(char **args, int cur_arg, char **ca_file_p, char **err) +static int ssl_bind_parse_ca_file_common(char **args, int cur_arg, char **ca_file_p, int from_cli, char **err) { if (!*args[cur_arg + 1]) { memprintf(err, "'%s' : missing CAfile path", args[cur_arg]); @@ -542,7 +542,7 @@ else memprintf(ca_file_p, "%s", args[cur_arg + 1]); - if (!ssl_store_load_locations_file(*ca_file_p)) { + if (!ssl_store_load_locations_file(*ca_file_p, !from_cli)) { memprintf(err, "'%s' : unable to load %s", args[cur_arg], *ca_file_p); return ERR_ALERT | ERR_FATAL; } @@ -550,23 +550,23 @@ } /* parse the "ca-file" bind keyword */ -static int ssl_bind_parse_ca_file(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err) +static int ssl_bind_parse_ca_file(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err) { - return ssl_bind_parse_ca_file_common(args, cur_arg, &conf->ca_file, err); + return ssl_bind_parse_ca_file_common(args, cur_arg, &conf->ca_file, from_cli, err); } static int bind_parse_ca_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) { - return ssl_bind_parse_ca_file(args, cur_arg, px, &conf->ssl_conf, err); + return ssl_bind_parse_ca_file(args, cur_arg, px, &conf->ssl_conf, 0, err); } /* parse the "ca-verify-file" bind keyword */ -static int ssl_bind_parse_ca_verify_file(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err) +static int ssl_bind_parse_ca_verify_file(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err) { - return ssl_bind_parse_ca_file_common(args, cur_arg, &conf->ca_verify_file, err); + return ssl_bind_parse_ca_file_common(args, cur_arg, &conf->ca_verify_file, from_cli, err); } static int bind_parse_ca_verify_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) { - return ssl_bind_parse_ca_verify_file(args, cur_arg, px, &conf->ssl_conf, err); + return ssl_bind_parse_ca_verify_file(args, cur_arg, px, &conf->ssl_conf, 0, err); } /* parse the "ca-sign-file" bind keyword */ @@ -597,7 +597,7 @@ } /* parse the "ciphers" bind keyword */ -static int ssl_bind_parse_ciphers(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err) +static int ssl_bind_parse_ciphers(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err) { if (!*args[cur_arg + 1]) { memprintf(err, "'%s' : missing cipher suite", args[cur_arg]); @@ -610,12 +610,12 @@ } static int bind_parse_ciphers(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) { - return ssl_bind_parse_ciphers(args, cur_arg, px, &conf->ssl_conf, err); + return ssl_bind_parse_ciphers(args, cur_arg, px, &conf->ssl_conf, 0, err); } #if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L) /* parse the "ciphersuites" bind keyword */ -static int ssl_bind_parse_ciphersuites(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err) +static int ssl_bind_parse_ciphersuites(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err) { if (!*args[cur_arg + 1]) { memprintf(err, "'%s' : missing cipher suite", args[cur_arg]); @@ -628,7 +628,7 @@ } static int bind_parse_ciphersuites(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) { - return ssl_bind_parse_ciphersuites(args, cur_arg, px, &conf->ssl_conf, err); + return ssl_bind_parse_ciphersuites(args, cur_arg, px, &conf->ssl_conf, 0, err); } #endif @@ -672,7 +672,7 @@ } /* parse the "crl-file" bind keyword */ -static int ssl_bind_parse_crl_file(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err) +static int ssl_bind_parse_crl_file(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err) { #ifndef X509_V_FLAG_CRL_CHECK memprintf(err, "'%s' : library does not support CRL verify", args[cur_arg]); @@ -688,7 +688,7 @@ else memprintf(&conf->crl_file, "%s", args[cur_arg + 1]); - if (!ssl_store_load_locations_file(conf->crl_file)) { + if (!ssl_store_load_locations_file(conf->crl_file, !from_cli)) { memprintf(err, "'%s' : unable to load %s", args[cur_arg], conf->crl_file); return ERR_ALERT | ERR_FATAL; } @@ -697,11 +697,11 @@ } static int bind_parse_crl_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) { - return ssl_bind_parse_crl_file(args, cur_arg, px, &conf->ssl_conf, err); + return ssl_bind_parse_crl_file(args, cur_arg, px, &conf->ssl_conf, 0, err); } /* parse the "curves" bind keyword keyword */ -static int ssl_bind_parse_curves(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err) +static int ssl_bind_parse_curves(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err) { #if defined(SSL_CTX_set1_curves_list) if (!*args[cur_arg + 1]) { @@ -717,13 +717,13 @@ } static int bind_parse_curves(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) { - return ssl_bind_parse_curves(args, cur_arg, px, &conf->ssl_conf, err); + return ssl_bind_parse_curves(args, cur_arg, px, &conf->ssl_conf, 0, err); } /* parse the "ecdhe" bind keyword keyword */ -static int ssl_bind_parse_ecdhe(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err) +static int ssl_bind_parse_ecdhe(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err) { -#if HA_OPENSSL_VERSION_NUMBER < 0x0090800fL +#if !defined(SSL_CTX_set_tmp_ecdh) memprintf(err, "'%s' : library does not support elliptic curve Diffie-Hellman (too old)", args[cur_arg]); return ERR_ALERT | ERR_FATAL; #elif defined(OPENSSL_NO_ECDH) @@ -742,7 +742,7 @@ } static int bind_parse_ecdhe(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) { - return ssl_bind_parse_ecdhe(args, cur_arg, px, &conf->ssl_conf, err); + return ssl_bind_parse_ecdhe(args, cur_arg, px, &conf->ssl_conf, 0, err); } /* parse the "crt-ignore-err" and "ca-ignore-err" bind keywords */ @@ -851,7 +851,7 @@ return 0; } -static int ssl_bind_parse_tls_method_minmax(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err) +static int ssl_bind_parse_tls_method_minmax(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err) { int ret; @@ -885,7 +885,7 @@ } /* parse the "allow-0rtt" bind keyword */ -static int ssl_bind_parse_allow_0rtt(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err) +static int ssl_bind_parse_allow_0rtt(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err) { conf->early_data = 1; return 0; @@ -898,7 +898,7 @@ } /* parse the "npn" bind keyword */ -static int ssl_bind_parse_npn(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err) +static int ssl_bind_parse_npn(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err) { #if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG) char *p1, *p2; @@ -949,7 +949,7 @@ static int bind_parse_npn(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) { - return ssl_bind_parse_npn(args, cur_arg, px, &conf->ssl_conf, err); + return ssl_bind_parse_npn(args, cur_arg, px, &conf->ssl_conf, 0, err); } @@ -1015,7 +1015,7 @@ } /* parse the "alpn" bind keyword */ -static int ssl_bind_parse_alpn(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err) +static int ssl_bind_parse_alpn(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err) { #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation int ret; @@ -1034,7 +1034,7 @@ static int bind_parse_alpn(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) { - return ssl_bind_parse_alpn(args, cur_arg, px, &conf->ssl_conf, err); + return ssl_bind_parse_alpn(args, cur_arg, px, &conf->ssl_conf, 0, err); } /* parse the "ssl" bind keyword */ @@ -1201,7 +1201,7 @@ } /* parse the "verify" bind keyword */ -static int ssl_bind_parse_verify(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err) +static int ssl_bind_parse_verify(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err) { if (!*args[cur_arg + 1]) { memprintf(err, "'%s' : missing verify method", args[cur_arg]); @@ -1224,18 +1224,18 @@ } static int bind_parse_verify(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) { - return ssl_bind_parse_verify(args, cur_arg, px, &conf->ssl_conf, err); + return ssl_bind_parse_verify(args, cur_arg, px, &conf->ssl_conf, 0, err); } /* parse the "no-ca-names" bind keyword */ -static int ssl_bind_parse_no_ca_names(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err) +static int ssl_bind_parse_no_ca_names(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err) { conf->no_ca_names = 1; return 0; } static int bind_parse_no_ca_names(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) { - return ssl_bind_parse_no_ca_names(args, cur_arg, px, &conf->ssl_conf, err); + return ssl_bind_parse_no_ca_names(args, cur_arg, px, &conf->ssl_conf, 0, err); } /***************************** "server" keywords Parsing ********************************************/ @@ -1333,7 +1333,7 @@ else memprintf(&newsrv->ssl_ctx.ca_file, "%s", args[*cur_arg + 1]); - if (!ssl_store_load_locations_file(newsrv->ssl_ctx.ca_file)) { + if (!ssl_store_load_locations_file(newsrv->ssl_ctx.ca_file, 1)) { memprintf(err, "'%s' : unable to load %s", args[*cur_arg], newsrv->ssl_ctx.ca_file); return ERR_ALERT | ERR_FATAL; } @@ -1422,7 +1422,7 @@ else memprintf(&newsrv->ssl_ctx.crl_file, "%s", args[*cur_arg + 1]); - if (!ssl_store_load_locations_file(newsrv->ssl_ctx.crl_file)) { + if (!ssl_store_load_locations_file(newsrv->ssl_ctx.crl_file, 1)) { memprintf(err, "'%s' : unable to load %s", args[*cur_arg], newsrv->ssl_ctx.crl_file); return ERR_ALERT | ERR_FATAL; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/cfgparse.c new/haproxy-2.3.9+git1.afb63bc04/src/cfgparse.c --- old/haproxy-2.3.7+git0.2d39ce334/src/cfgparse.c 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/src/cfgparse.c 2021-03-30 18:51:07.000000000 +0200 @@ -87,6 +87,8 @@ struct list postparsers = LIST_HEAD_INIT(postparsers); +extern struct proxy *mworker_proxy; + char *cursection = NULL; struct proxy defproxy = { }; /* fake proxy used to assign default values on all instances */ int cfg_maxpconn = 0; /* # of simultaneous connections per proxy (-N) */ @@ -128,7 +130,7 @@ } ss2 = str2sa_range(str, NULL, &port, &end, &fd, &proto, err, - curproxy == global.stats_fe ? NULL : global.unix_bind.prefix, + (curproxy == global.stats_fe || curproxy == mworker_proxy) ? NULL : global.unix_bind.prefix, NULL, PA_O_RESOLVE | PA_O_PORT_OK | PA_O_PORT_MAND | PA_O_PORT_RANGE | PA_O_SOCKET_FD | PA_O_STREAM | PA_O_XPRT); if (!ss2) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/cli.c new/haproxy-2.3.9+git1.afb63bc04/src/cli.c --- old/haproxy-2.3.7+git0.2d39ce334/src/cli.c 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/src/cli.c 2021-03-30 18:51:07.000000000 +0200 @@ -89,7 +89,7 @@ extern const char *stat_status_codes[]; -static struct proxy *mworker_proxy; /* CLI proxy of the master */ +struct proxy *mworker_proxy; /* CLI proxy of the master */ static char *cli_gen_usage_msg(struct appctx *appctx) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/debug.c new/haproxy-2.3.9+git1.afb63bc04/src/debug.c --- old/haproxy-2.3.7+git0.2d39ce334/src/debug.c 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/src/debug.c 2021-03-30 18:51:07.000000000 +0200 @@ -223,9 +223,9 @@ } if (hlua && hlua->T) { - luaL_traceback(hlua->T, hlua->T, NULL, 0); - if (!append_prefixed_str(buf, lua_tostring(hlua->T, -1), pfx, '\n', 1)) - b_putchr(buf, '\n'); + chunk_appendf(buf, "stack traceback:\n "); + append_prefixed_str(buf, hlua_traceback(hlua->T, "\n "), pfx, '\n', 0); + b_putchr(buf, '\n'); } else b_putchr(buf, '\n'); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/fd.c new/haproxy-2.3.9+git1.afb63bc04/src/fd.c --- old/haproxy-2.3.7+git0.2d39ce334/src/fd.c 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/src/fd.c 2021-03-30 18:51:07.000000000 +0200 @@ -294,23 +294,14 @@ #undef _GET_NEXT #undef _GET_PREV -/* Deletes an FD from the fdsets. - * The file descriptor is also closed. +/* deletes the FD once nobody uses it anymore, as detected by the caller by its + * thread_mask being zero and its running mask turning to zero. There is no + * protection against concurrent accesses, it's up to the caller to make sure + * only the last thread will call it. This is only for internal use, please use + * fd_delete() instead. */ -void fd_delete(int fd) +void _fd_delete_orphan(int fd) { - int locked = fdtab[fd].running_mask != tid_bit; - - /* We're just trying to protect against a concurrent fd_insert() - * here, not against fd_takeover(), because either we're called - * directly from the iocb(), and we're already locked, or we're - * called from the mux tasklet, but then the mux is responsible for - * making sure the tasklet does nothing, and the connection is never - * destroyed. - */ - if (locked) - fd_set_running_excl(fd); - if (fdtab[fd].linger_risk) { /* this is generally set when connecting to servers */ DISGUISE(setsockopt(fd, SOL_SOCKET, SO_LINGER, @@ -328,18 +319,51 @@ port_range_release_port(fdinfo[fd].port_range, fdinfo[fd].local_port); fdinfo[fd].port_range = NULL; fdtab[fd].owner = NULL; - fdtab[fd].thread_mask = 0; fdtab[fd].exported = 0; + /* perform the close() call last as it's what unlocks the instant reuse + * of this FD by any other thread. + */ close(fd); _HA_ATOMIC_SUB(&ha_used_fds, 1); - if (locked) - fd_clr_running(fd); } #ifndef HA_HAVE_CAS_DW __decl_thread(__decl_rwlock(fd_mig_lock)); #endif +/* Deletes an FD from the fdsets. The file descriptor is also closed, possibly + * asynchronously. Only the owning thread may do this. + */ +void fd_delete(int fd) +{ + /* we must postpone removal of an FD that may currently be in use + * by another thread. This can happend in the following two situations: + * - after a takeover, the owning thread closes the connection but + * the previous one just woke up from the poller and entered + * the FD handler iocb. That thread holds an entry in running_mask + * and requires removal protection. + * - multiple threads are accepting connections on a listener, and + * one of them (or even an separate one) decides to unbind the + * listener under the listener's lock while other ones still hold + * the running bit. + * In both situations the FD is marked as unused (thread_mask = 0) and + * will not take new bits in its running_mask so we have the guarantee + * that the last thread eliminating running_mask is the one allowed to + * safely delete the FD. Most of the time it will be the current thread. + */ + + HA_ATOMIC_OR(&fdtab[fd].running_mask, tid_bit); +#ifndef HA_HAVE_CAS_DW + HA_RWLOCK_WRLOCK(OTHER_LOCK, &fd_mig_lock); +#endif + HA_ATOMIC_STORE(&fdtab[fd].thread_mask, 0); +#ifndef HA_HAVE_CAS_DW + HA_RWLOCK_WRUNLOCK(OTHER_LOCK, &fd_mig_lock); +#endif + if (fd_clr_running(fd) == 0) + _fd_delete_orphan(fd); +} + /* * Take over a FD belonging to another thread. * unexpected_conn is the expected owner of the fd. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/freq_ctr.c new/haproxy-2.3.9+git1.afb63bc04/src/freq_ctr.c --- old/haproxy-2.3.7+git0.2d39ce334/src/freq_ctr.c 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/src/freq_ctr.c 2021-03-30 18:51:07.000000000 +0200 @@ -51,7 +51,7 @@ break; } - age = now.tv_sec - curr_sec; + age = (global_now >> 32) - curr_sec; if (unlikely(age > 1)) return 0; @@ -94,7 +94,7 @@ break; } - age = now.tv_sec - curr_sec; + age = (global_now >> 32) - curr_sec; if (unlikely(age > 1)) curr = 0; else { @@ -141,7 +141,7 @@ break; } - age = now.tv_sec - curr_sec; + age = (global_now >> 32) - curr_sec; if (unlikely(age > 1)) curr = 0; else { @@ -163,7 +163,7 @@ /* Reads a frequency counter taking history into account for missing time in * current period. The period has to be passed in number of ticks and must * match the one used to feed the counter. The counter value is reported for - * current date (now_ms). The return value has the same precision as one input + * current global date. The return value has the same precision as one input * data sample, so low rates over the period will be inaccurate but still * appropriate for max checking. One trick we use for low values is to specially * handle the case where the rate is between 0 and 1 in order to avoid flapping @@ -200,7 +200,7 @@ break; }; - remain = curr_tick + period - now_ms; + remain = curr_tick + period - global_now_ms; if (unlikely((int)remain < 0)) { /* We're past the first period, check if we can still report a * part of last period or if we're too far away. @@ -247,7 +247,7 @@ break; }; - remain = curr_tick + period - now_ms; + remain = curr_tick + period - global_now_ms; if (likely((int)remain < 0)) { /* We're past the first period, check if we can still report a * part of last period or if we're too far away. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/hlua.c new/haproxy-2.3.9+git1.afb63bc04/src/hlua.c --- old/haproxy-2.3.7+git0.2d39ce334/src/hlua.c 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/src/hlua.c 2021-03-30 18:51:07.000000000 +0200 @@ -283,19 +283,17 @@ return lua_tostring(L, -1); } -__LJMP static const char *hlua_traceback(lua_State *L) +__LJMP const char *hlua_traceback(lua_State *L, const char* sep) { lua_Debug ar; int level = 0; struct buffer *msg = get_trash_chunk(); - int filled = 0; while (lua_getstack(L, level++, &ar)) { /* Add separator */ - if (filled) - chunk_appendf(msg, ", "); - filled = 1; + if (b_data(msg)) + chunk_appendf(msg, "%s", sep); /* Fill fields: * 'S': fills in the fields source, short_src, linedefined, lastlinedefined, and what; @@ -307,9 +305,9 @@ /* Append code localisation */ if (ar.currentline > 0) - chunk_appendf(msg, "%s:%d ", ar.short_src, ar.currentline); + chunk_appendf(msg, "%s:%d: ", ar.short_src, ar.currentline); else - chunk_appendf(msg, "%s ", ar.short_src); + chunk_appendf(msg, "%s: ", ar.short_src); /* * Get function name @@ -319,13 +317,13 @@ * or "main" for main code. */ if (*ar.namewhat != '\0' && ar.name != NULL) /* is there a name from code? */ - chunk_appendf(msg, "%s '%s'", ar.namewhat, ar.name); /* use it */ + chunk_appendf(msg, "in %s '%s'", ar.namewhat, ar.name); /* use it */ else if (*ar.what == 'm') /* "main", the code is not executed in a function */ - chunk_appendf(msg, "main chunk"); + chunk_appendf(msg, "in main chunk"); else if (*ar.what != 'C') /* for Lua functions, use <file:line> */ - chunk_appendf(msg, "C function line %d", ar.linedefined); + chunk_appendf(msg, "in function line %d", ar.linedefined); else /* nothing left... */ chunk_appendf(msg, "?"); @@ -1271,7 +1269,7 @@ msg = lua_tostring(lua->T, -1); lua_settop(lua->T, 0); /* Empty the stack. */ lua_pop(lua->T, 1); - trace = hlua_traceback(lua->T); + trace = hlua_traceback(lua->T, ", "); if (msg) lua_pushfstring(lua->T, "runtime error: %s from %s", msg, trace); else @@ -6277,6 +6275,7 @@ hlua = pool_alloc(pool_head_hlua); if (!hlua) WILL_LJMP(luaL_error(L, "Lua out of memory error.")); + HLUA_INIT(hlua); task = task_new(MAX_THREADS_MASK); if (!task) @@ -6317,11 +6316,15 @@ * Lua initialization cause 5% performances loss. */ if (!stream->hlua) { - stream->hlua = pool_alloc(pool_head_hlua); - if (!stream->hlua) { + struct hlua *hlua; + + hlua = pool_alloc(pool_head_hlua); + if (!hlua) { SEND_ERR(stream->be, "Lua converter '%s': can't initialize Lua context.\n", fcn->name); return 0; } + HLUA_INIT(hlua); + stream->hlua = hlua; if (!hlua_ctx_init(stream->hlua, stream->task, 0)) { SEND_ERR(stream->be, "Lua converter '%s': can't initialize Lua context.\n", fcn->name); return 0; @@ -6450,11 +6453,15 @@ * Lua initialization cause 5% performances loss. */ if (!stream->hlua) { - stream->hlua = pool_alloc(pool_head_hlua); - if (!stream->hlua) { + struct hlua *hlua; + + hlua = pool_alloc(pool_head_hlua); + if (!hlua) { SEND_ERR(stream->be, "Lua sample-fetch '%s': can't initialize Lua context.\n", fcn->name); return 0; } + hlua->T = NULL; + stream->hlua = hlua; if (!hlua_ctx_init(stream->hlua, stream->task, 0)) { SEND_ERR(stream->be, "Lua sample-fetch '%s': can't initialize Lua context.\n", fcn->name); return 0; @@ -6745,12 +6752,16 @@ * Lua initialization cause 5% performances loss. */ if (!s->hlua) { - s->hlua = pool_alloc(pool_head_hlua); - if (!s->hlua) { + struct hlua *hlua; + + hlua = pool_alloc(pool_head_hlua); + if (!hlua) { SEND_ERR(px, "Lua action '%s': can't initialize Lua context.\n", rule->arg.hlua_rule->fcn.name); goto end; } + HLUA_INIT(hlua); + s->hlua = hlua; if (!hlua_ctx_init(s->hlua, s->task, 0)) { SEND_ERR(px, "Lua action '%s': can't initialize Lua context.\n", rule->arg.hlua_rule->fcn.name); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/http_fetch.c new/haproxy-2.3.9+git1.afb63bc04/src/http_fetch.c --- old/haproxy-2.3.7+git0.2d39ce334/src/http_fetch.c 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/src/http_fetch.c 2021-03-30 18:51:07.000000000 +0200 @@ -999,19 +999,30 @@ /* Fetch an HTTP header's IP value. takes a mandatory argument of type string * and an optional one of type int to designate a specific occurrence. - * It returns an IPv4 or IPv6 address. + * It returns an IPv4 or IPv6 address. Addresses surrounded by invalid chars + * are rejected. However IPv4 addresses may be followed with a colon and a + * valid port number. */ static int smp_fetch_hdr_ip(const struct arg *args, struct sample *smp, const char *kw, void *private) { - int ret; struct buffer *temp = get_trash_chunk(); + int ret, len; + int port; while ((ret = smp_fetch_hdr(args, smp, kw, private)) > 0) { if (smp->data.u.str.data < temp->size - 1) { memcpy(temp->area, smp->data.u.str.area, smp->data.u.str.data); temp->area[smp->data.u.str.data] = '\0'; - if (url2ipv4((char *) temp->area, &smp->data.u.ipv4)) { + len = url2ipv4((char *) temp->area, &smp->data.u.ipv4); + if (len == smp->data.u.str.data) { + /* plain IPv4 address */ + smp->data.type = SMP_T_IPV4; + break; + } else if (len > 0 && temp->area[len] == ':' && + strl2irc(temp->area + len + 1, smp->data.u.str.data - len - 1, &port) == 0 && + port >= 0 && port <= 65535) { + /* IPv4 address suffixed with ':' followed by a valid port number */ smp->data.type = SMP_T_IPV4; break; } else if (inet_pton(AF_INET6, temp->area, &smp->data.u.ipv6)) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/mux_fcgi.c new/haproxy-2.3.9+git1.afb63bc04/src/mux_fcgi.c --- old/haproxy-2.3.7+git0.2d39ce334/src/mux_fcgi.c 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/src/mux_fcgi.c 2021-03-30 18:51:07.000000000 +0200 @@ -2957,13 +2957,14 @@ conn_in_list = conn->flags & CO_FL_LIST_MASK; if (conn_in_list) MT_LIST_DEL(&conn->list); + + HA_SPIN_UNLOCK(OTHER_LOCK, &idle_conns[tid].takeover_lock); } else { /* we're certain the connection was not in an idle list */ conn = fconn->conn; TRACE_ENTER(FCGI_EV_FCONN_WAKE, conn); conn_in_list = 0; } - HA_SPIN_UNLOCK(OTHER_LOCK, &idle_conns[tid].takeover_lock); if (!(fconn->wait_event.events & SUB_RETRY_SEND)) ret = fcgi_send(fconn); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/mux_h1.c new/haproxy-2.3.9+git1.afb63bc04/src/mux_h1.c --- old/haproxy-2.3.7+git0.2d39ce334/src/mux_h1.c 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/src/mux_h1.c 2021-03-30 18:51:07.000000000 +0200 @@ -2663,6 +2663,9 @@ { struct h1c *h1c = conn->ctx; + if (conn->flags & CO_FL_SOCK_WR_SH) + return; + TRACE_ENTER(H1_EV_STRM_SHUT, conn, h1c->h1s); conn_xprt_shutw(conn); conn_sock_shutw(conn, (mode == CS_SHW_NORMAL)); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/payload.c new/haproxy-2.3.9+git1.afb63bc04/src/payload.c --- old/haproxy-2.3.7+git0.2d39ce334/src/payload.c 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/src/payload.c 2021-03-30 18:51:07.000000000 +0200 @@ -984,7 +984,7 @@ } max = global.tune.bufsize; if (!head) - return 0; + goto too_short; if (len_offset + len_size > data) goto too_short; @@ -1046,7 +1046,7 @@ } max = global.tune.bufsize; if (!head) - return 0; + goto too_short; if (buf_size > max || buf_offset + buf_size > max) { /* will never match */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/proto_uxdg.c new/haproxy-2.3.9+git1.afb63bc04/src/proto_uxdg.c --- old/haproxy-2.3.7+git0.2d39ce334/src/proto_uxdg.c 1970-01-01 01:00:00.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/src/proto_uxdg.c 2021-03-30 18:51:07.000000000 +0200 @@ -0,0 +1,151 @@ +/* + * DGRAM protocol layer on top of AF_UNIX + * + * Copyright 2020 HAProxy Technologies, Emeric Brun <[email protected]> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/un.h> + +#include <haproxy/fd.h> +#include <haproxy/listener.h> +#include <haproxy/log.h> +#include <haproxy/namespace.h> +#include <haproxy/protocol.h> +#include <haproxy/sock.h> +#include <haproxy/sock_unix.h> + +static int uxdg_bind_listener(struct listener *listener, char *errmsg, int errlen); +static void uxdg_enable_listener(struct listener *listener); +static void uxdg_disable_listener(struct listener *listener); +static int uxdg_suspend_receiver(struct receiver *rx); + +/* Note: must not be declared <const> as its list will be overwritten */ +struct protocol proto_uxdg = { + .name = "uxdg", + + /* connection layer */ + .ctrl_type = SOCK_DGRAM, + .listen = uxdg_bind_listener, + .enable = uxdg_enable_listener, + .disable = uxdg_disable_listener, + .add = default_add_listener, + .unbind = default_unbind_listener, + .suspend = default_suspend_listener, + .resume = default_resume_listener, + + /* binding layer */ + .rx_suspend = uxdg_suspend_receiver, + + /* address family */ + .fam = &proto_fam_unix, + + /* socket layer */ + .sock_type = SOCK_DGRAM, + .sock_prot = 0, + .rx_enable = sock_enable, + .rx_disable = sock_disable, + .rx_unbind = sock_unbind, + .receivers = LIST_HEAD_INIT(proto_uxdg.receivers), + .nb_receivers = 0, +}; + +INITCALL1(STG_REGISTER, protocol_register, &proto_uxdg); + +/* This function tries to bind dgram unix socket listener. It may return a warning or + * an error message in <errmsg> if the message is at most <errlen> bytes long + * (including '\0'). Note that <errmsg> may be NULL if <errlen> is also zero. + * The return value is composed from ERR_ABORT, ERR_WARN, + * ERR_ALERT, ERR_RETRYABLE and ERR_FATAL. ERR_NONE indicates that everything + * was alright and that no message was returned. ERR_RETRYABLE means that an + * error occurred but that it may vanish after a retry (eg: port in use), and + * ERR_FATAL indicates a non-fixable error. ERR_WARN and ERR_ALERT do not alter + * the meaning of the error, but just indicate that a message is present which + * should be displayed with the respective level. Last, ERR_ABORT indicates + * that it's pointless to try to start other listeners. No error message is + * returned if errlen is NULL. + */ +int uxdg_bind_listener(struct listener *listener, char *errmsg, int errlen) +{ + int err = ERR_NONE; + char *msg = NULL; + + /* ensure we never return garbage */ + if (errlen) + *errmsg = 0; + + if (listener->state != LI_ASSIGNED) + return ERR_NONE; /* already bound */ + + if (!(listener->rx.flags & RX_F_BOUND)) { + msg = "receiving socket not bound"; + goto uxdg_return; + } + + listener_set_state(listener, LI_LISTEN); + + uxdg_return: + if (msg && errlen) { + const char *path = ((struct sockaddr_un *)&listener->rx.addr)->sun_path; + snprintf(errmsg, errlen, "%s [%s]", msg, path); + } + return err; +} + +/* Enable receipt of incoming connections for listener <l>. The receiver must + * still be valid. + */ +static void uxdg_enable_listener(struct listener *l) +{ + fd_want_recv_safe(l->rx.fd); +} + +/* Disable receipt of incoming connections for listener <l>. The receiver must + * still be valid. + */ +static void uxdg_disable_listener(struct listener *l) +{ + fd_stop_recv(l->rx.fd); +} + +/* Suspend a receiver. Returns < 0 in case of failure, 0 if the receiver + * was totally stopped, or > 0 if correctly suspended. Nothing is done for + * plain unix sockets since currently it's the new process which handles + * the renaming. Abstract sockets are completely unbound and closed so + * there's no need to stop the poller. + */ +static int uxdg_suspend_receiver(struct receiver *rx) +{ + struct listener *l = LIST_ELEM(rx, struct listener *, rx); + + if (((struct sockaddr_un *)&rx->addr)->sun_path[0]) + return 1; + + /* Listener's lock already held. Call lockless version of + * unbind_listener. */ + do_unbind_listener(l); + return 0; +} + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * End: + */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/ssl_crtlist.c new/haproxy-2.3.9+git1.afb63bc04/src/ssl_crtlist.c --- old/haproxy-2.3.7+git0.2d39ce334/src/ssl_crtlist.c 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/src/ssl_crtlist.c 2021-03-30 18:51:07.000000000 +0200 @@ -311,7 +311,7 @@ * <crt_path> is a ptr in <line> * Return an error code */ -int crtlist_parse_line(char *line, char **crt_path, struct crtlist_entry *entry, const char *file, int linenum, char **err) +int crtlist_parse_line(char *line, char **crt_path, struct crtlist_entry *entry, const char *file, int linenum, int from_cli, char **err) { int cfgerr = 0; int arg, newarg, cur_arg, i, ssl_b = 0, ssl_e = 0; @@ -395,13 +395,14 @@ goto error; } } + cur_arg = ssl_b ? ssl_b : 1; while (cur_arg < ssl_e) { newarg = 0; for (i = 0; ssl_bind_kws[i].kw != NULL; i++) { if (strcmp(ssl_bind_kws[i].kw, args[cur_arg]) == 0) { newarg = 1; - cfgerr |= ssl_bind_kws[i].parse(args, cur_arg, NULL, ssl_conf, err); + cfgerr |= ssl_bind_kws[i].parse(args, cur_arg, NULL, ssl_conf, from_cli, err); if (cur_arg + 1 + ssl_bind_kws[i].skip > ssl_e) { memprintf(err, "parsing [%s:%d]: ssl args out of '[]' for %s", file, linenum, args[cur_arg]); @@ -512,7 +513,7 @@ goto error; } - cfgerr |= crtlist_parse_line(thisline, &crt_path, entry, file, linenum, err); + cfgerr |= crtlist_parse_line(thisline, &crt_path, entry, file, linenum, 0, err); if (cfgerr & ERR_CODE) goto error; @@ -1216,7 +1217,7 @@ goto error; } /* cert_path is filled here */ - cfgerr |= crtlist_parse_line(payload, &cert_path, entry, "CLI", 1, &err); + cfgerr |= crtlist_parse_line(payload, &cert_path, entry, "CLI", 1, 1, &err); if (cfgerr & ERR_CODE) goto error; } else { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/ssl_sock.c new/haproxy-2.3.9+git1.afb63bc04/src/ssl_sock.c --- old/haproxy-2.3.7+git0.2d39ce334/src/ssl_sock.c 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/src/ssl_sock.c 2021-03-30 18:51:07.000000000 +0200 @@ -300,11 +300,16 @@ return NULL; } -int ssl_store_load_locations_file(char *path) +int ssl_store_load_locations_file(char *path, int create_if_none) { - if (ssl_store_get0_locations_file(path) == NULL) { + X509_STORE *store = ssl_store_get0_locations_file(path); + + /* If this function is called by the CLI, we should not call the + * X509_STORE_load_locations function because it performs forbidden disk + * accesses. */ + if (!store && create_if_none) { struct cafile_entry *ca_e; - X509_STORE *store = X509_STORE_new(); + store = X509_STORE_new(); if (X509_STORE_load_locations(store, path, NULL)) { int pathlen; pathlen = strlen(path); @@ -313,13 +318,13 @@ memcpy(ca_e->path, path, pathlen + 1); ca_e->ca_store = store; ebst_insert(&cafile_tree, &ca_e->node); - return 1; } + } else { + X509_STORE_free(store); + store = NULL; } - X509_STORE_free(store); - return 0; } - return 1; + return (store != NULL); } /* mimic what X509_STORE_load_locations do with store_ctx */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/stats.c new/haproxy-2.3.9+git1.afb63bc04/src/stats.c --- old/haproxy-2.3.7+git0.2d39ce334/src/stats.c 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/src/stats.c 2021-03-30 18:51:07.000000000 +0200 @@ -1073,13 +1073,13 @@ strcmp(field_str(stats, ST_F_STATUS), "DOWN (agent)") == 0) { style = "down"; } - else if (strcmp(field_str(stats, ST_F_STATUS), "DOWN ") == 0) { + else if (strncmp(field_str(stats, ST_F_STATUS), "DOWN ", strlen("DOWN ")) == 0) { style = "going_up"; } else if (strcmp(field_str(stats, ST_F_STATUS), "DRAIN") == 0) { style = "draining"; } - else if (strcmp(field_str(stats, ST_F_STATUS), "NOLB ") == 0) { + else if (strncmp(field_str(stats, ST_F_STATUS), "NOLB ", strlen("NOLB ")) == 0) { style = "going_down"; } else if (strcmp(field_str(stats, ST_F_STATUS), "NOLB") == 0) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/thread.c new/haproxy-2.3.9+git1.afb63bc04/src/thread.c --- old/haproxy-2.3.7+git0.2d39ce334/src/thread.c 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/src/thread.c 2021-03-30 18:51:07.000000000 +0200 @@ -48,13 +48,15 @@ #endif /* Marks the thread as harmless until the last thread using the rendez-vous - * point quits. Given that we can wait for a long time, sched_yield() is used - * when available to offer the CPU resources to competing threads if needed. + * point quits, excluding the current one. Thus an isolated thread may be safely + * marked as harmless. Given that we can wait for a long time, sched_yield() is + * used when available to offer the CPU resources to competing threads if + * needed. */ void thread_harmless_till_end() { _HA_ATOMIC_OR(&threads_harmless_mask, tid_bit); - while (threads_want_rdv_mask & all_threads_mask) { + while (threads_want_rdv_mask & ~tid_bit) { ha_thread_relax(); } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/time.c new/haproxy-2.3.9+git1.afb63bc04/src/time.c --- old/haproxy-2.3.7+git0.2d39ce334/src/time.c 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/src/time.c 2021-03-30 18:51:07.000000000 +0200 @@ -15,6 +15,7 @@ #include <haproxy/api.h> #include <haproxy/time.h> +#include <haproxy/ticks.h> #include <haproxy/tools.h> THREAD_LOCAL unsigned int ms_left_scaled; /* milliseconds left for current second (0..2^32-1) */ @@ -28,7 +29,8 @@ THREAD_LOCAL struct timeval after_poll; /* system date after leaving poll() */ static THREAD_LOCAL struct timeval tv_offset; /* per-thread time ofsset relative to global time */ -static volatile unsigned long long global_now; /* common date between all threads (32:32) */ +volatile unsigned long long global_now; /* common date between all threads (32:32) */ +volatile unsigned int global_now_ms; /* common date in milliseconds (may wrap) */ static THREAD_LOCAL unsigned int iso_time_sec; /* last iso time value for this thread */ static THREAD_LOCAL char iso_time_str[34]; /* ISO time representation of gettimeofday() */ @@ -177,6 +179,7 @@ { struct timeval adjusted, deadline, tmp_now, tmp_adj; unsigned int curr_sec_ms; /* millisecond of current second (0..999) */ + unsigned int old_now_ms, new_now_ms; unsigned long long old_now; unsigned long long new_now; @@ -260,6 +263,15 @@ */ ms_left_scaled = (999U - curr_sec_ms) * 4294967U; now_ms = now.tv_sec * 1000 + curr_sec_ms; + + /* update the global current millisecond */ + old_now_ms = global_now_ms; + do { + new_now_ms = old_now_ms; + if (tick_is_lt(new_now_ms, now_ms) || !new_now_ms) + new_now_ms = now_ms; + } while (!_HA_ATOMIC_CAS(&global_now_ms, &old_now_ms, new_now_ms)); + return; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/tools.c new/haproxy-2.3.9+git1.afb63bc04/src/tools.c --- old/haproxy-2.3.7+git0.2d39ce334/src/tools.c 2021-03-16 15:49:34.000000000 +0100 +++ new/haproxy-2.3.9+git1.afb63bc04/src/tools.c 2021-03-30 18:51:07.000000000 +0200 @@ -1381,7 +1381,9 @@ /* - * Parse IPv4 address found in url. + * Parse IPv4 address found in url. Return the number of bytes parsed. It + * expects exactly 4 numbers between 0 and 255 delimited by dots, and returns + * zero in case of mismatch. */ int url2ipv4(const char *addr, struct in_addr *dst) { @@ -1394,9 +1396,10 @@ *(tp = tmp) = 0; while (*addr) { - unsigned char digit = (ch = *addr++) - '0'; + unsigned char digit = (ch = *addr) - '0'; if (digit > 9 && ch != '.') break; + addr++; if (digit <= 9) { u_int new = *tp * 10 + digit; if (new > 255) @@ -1420,7 +1423,7 @@ return 0; memcpy(&dst->s_addr, tmp, 4); - return addr-cp-1; + return addr - cp; } /*
