From b5952edcc634a5fe93da407d38f55ac151b156ee Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Mon, 27 Feb 2023 19:13:56 +0000 Subject: Version bump. --- docs/changes.xml | 30 ++++++++++++++++++++++++++++++ version | 4 ++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/docs/changes.xml b/docs/changes.xml index e569f474..06fcd229 100644 --- a/docs/changes.xml +++ b/docs/changes.xml @@ -5,6 +5,36 @@ + + + + +NGINX Unit updated to 1.29.1. + + + + + + + + + + + + + + + +Initial release of Python 3.11 module for NGINX Unit. + + + + + + -- cgit From 2596a8952720bb8503430eda3b4560435fd7b71e Mon Sep 17 00:00:00 2001 From: Konstantin Pavlov Date: Wed, 28 Dec 2022 20:06:43 -0800 Subject: Packages: do not clean up rpm build root. These directories are used in the Makefile to determine status of a target. --- pkg/rpm/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/rpm/Makefile b/pkg/rpm/Makefile index d00a25ac..5c104ca3 100644 --- a/pkg/rpm/Makefile +++ b/pkg/rpm/Makefile @@ -184,7 +184,7 @@ rpmbuild/SOURCES/unit-$(VERSION).tar.gz: unit: check-build-depends-unit rpmbuild/SPECS/unit.spec rpmbuild/SOURCES/unit-$(VERSION).tar.gz @echo "===> Building $@ package" ; \ - rpmbuild -D "_topdir `pwd`/rpmbuild" -ba rpmbuild/SPECS/unit.spec && \ + rpmbuild -D "_topdir `pwd`/rpmbuild" -ba --noclean rpmbuild/SPECS/unit.spec && \ ln -s rpmbuild/BUILD/$@-$(VERSION)/build $@ rpmlint: @@ -235,7 +235,7 @@ rpmbuild/SPECS/unit-%.spec: unit.module.spec.in ../../docs/changes.xml | rpmbuil unit-%: check-build-depends-% rpmbuild/SPECS/unit-%.spec rpmbuild/SOURCES/unit-$(VERSION).tar.gz @echo "===> Building $(subst _,-,$@) package" ; \ - rpmbuild -D "_topdir `pwd`/rpmbuild" -ba rpmbuild/SPECS/$@.spec && \ + rpmbuild -D "_topdir `pwd`/rpmbuild" -ba --noclean rpmbuild/SPECS/$@.spec && \ ln -s rpmbuild/BUILD/$(subst _,-,$@)-$(VERSION)/build $@ test: unit modules -- cgit From fcbb26e92af4cab8877ff5dc39b787377e5ce253 Mon Sep 17 00:00:00 2001 From: Andrew Clayton Date: Fri, 30 Dec 2022 00:07:20 +0000 Subject: Python: Do some cleanup in nxt_python3_init_config(). This is a preparatory patch for future work and cleans up the code a little in the Python 3.8+ variant of nxt_python3_init_config(). The main advantage being we no longer have calls to PyConfig_Clear() in two different paths. The variables have a little extra space in their declarations to allow for the next patch which introduces a variable with a longer type name, which will help reduce the size of the diff. Reviewed-by: Alejandro Colomar Signed-off-by: Andrew Clayton --- src/python/nxt_python.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/python/nxt_python.c b/src/python/nxt_python.c index bdb04579..83f2544e 100644 --- a/src/python/nxt_python.c +++ b/src/python/nxt_python.c @@ -75,8 +75,11 @@ static nxt_python_proto_t nxt_py_proto; static nxt_int_t nxt_python3_init_config(nxt_int_t pep405) { - PyStatus status; - PyConfig config; + PyConfig config; + PyStatus status; + nxt_int_t ret; + + ret = NXT_ERROR; PyConfig_InitIsolatedConfig(&config); @@ -84,29 +87,28 @@ nxt_python3_init_config(nxt_int_t pep405) status = PyConfig_SetString(&config, &config.program_name, nxt_py_home); if (PyStatus_Exception(status)) { - goto pyinit_exception; + goto out_config_clear; } } else { - status =PyConfig_SetString(&config, &config.home, nxt_py_home); + status = PyConfig_SetString(&config, &config.home, nxt_py_home); if (PyStatus_Exception(status)) { - goto pyinit_exception; + goto out_config_clear; } } status = Py_InitializeFromConfig(&config); if (PyStatus_Exception(status)) { - goto pyinit_exception; + goto out_config_clear; } - PyConfig_Clear(&config); - return NXT_OK; + ret = NXT_OK; -pyinit_exception: +out_config_clear: PyConfig_Clear(&config); - return NXT_ERROR; + return ret; } #elif PY_MAJOR_VERSION == 3 -- cgit From 96891a308b9269b4bee9450c5fdc1d07b6fed21e Mon Sep 17 00:00:00 2001 From: Andrew Clayton Date: Thu, 5 Jan 2023 22:04:32 +0000 Subject: Python: Fix enabling of UTF-8 in some situations. There was a couple of reports of Python applications failing due to the following type of error File "/opt/netbox/netbox/netbox/configuration.py", line 25, in _import print(f"\U0001f9ec loaded config '{path}'") UnicodeEncodeError: 'ascii' codec can't encode character '\U0001f9ec' in position 0: ordinal not in range(128) due to the use of Unicode text in the print() statement. This only happened for python 3.8+ when using the "home" configuration option as this meant we were going through the new PyConfig configuration. When using this new configuration method with the 'isolated' specific API (for embedded Python) UTF-8 is disabled by default, PyPreConfig->utf8_mode = 0. To fix this we need to setup the Python pre config and enable utf-8 mode. However rather than enable utf-8 unconditionally we can set to it to -1 so that it will use the LC_CTYPE environment variable to determine whether to enable utf-8 mode or not. utf-8 mode will be enabled if LC_CTYPE is either: C, POSIX or some specific UTF-8 locale. This is the default utf8_mode setting when using the non-isolated PyPreConfig API. Reported-by: Tobias Genannt Tested-by: Tobias Genannt Link: Link: Fixes: 491d0f70 ("Python: Added support for Python 3.11.") Closes: Reviewed-by: Alejandro Colomar Signed-off-by: Andrew Clayton --- src/python/nxt_python.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/python/nxt_python.c b/src/python/nxt_python.c index 83f2544e..7c059649 100644 --- a/src/python/nxt_python.c +++ b/src/python/nxt_python.c @@ -78,9 +78,23 @@ nxt_python3_init_config(nxt_int_t pep405) PyConfig config; PyStatus status; nxt_int_t ret; + PyPreConfig preconfig; ret = NXT_ERROR; + PyPreConfig_InitIsolatedConfig(&preconfig); + /* + * Determine whether to use UTF-8 mode or not, UTF-8 + * will be enabled if LC_CTYPE is C, POSIX or some + * specific UTF-8 locale. + */ + preconfig.utf8_mode = -1; + + status = Py_PreInitialize(&preconfig); + if (PyStatus_Exception(status)) { + return ret; + } + PyConfig_InitIsolatedConfig(&config); if (pep405) { -- cgit From c175e47cfee0215ad7386e7c1d9a4865280ba76f Mon Sep 17 00:00:00 2001 From: Andrew Clayton Date: Fri, 2 Dec 2022 17:20:37 +0000 Subject: Autodetect endianness. In configure we set NXT_HAVE_LITTLE_ENDIAN for i386, amd64 and x86_64. However that misses at least AArch64 (arm64) where it's usually run in little endian mode. However none of that really matters as NXT_HAVE_LITTLE_ENDIAN isn't used anywhere. So why this patch? The only place we need to explicitly know about endianness is the nxt_websocket_header_t structure where we lay it out differently depending on endianness. This is currently done using BYTE_ORDER, LITTLE_ENDIAN and BIG_ENDIAN macros. However on at least illumos (OpenSolaris / OpenIndiana) those macros are not defined and we get compiler errors due to duplicate structure members. So let's use our own NXT_HAVE_{BIG,LITTLE}_ENDIAN macros. However it would be better to detect endianness programmatically as some architectures can run in either mode, e.g Linux used to run in big endian on PowerPC but has since switched to little endian (to match x86). This commit adds an auto/endian script (using a slightly modified version of the test program from nginx's auto script), that checks for the endianness of the platform being built on. E.g checking for endianness ... little endian The next commit will switch the nxt_websocket_header_t structure over to these new macros. Link: Link: Tested-by: Alejandro Colomar Reviewed-by: Alejandro Colomar Signed-off-by: Andrew Clayton --- auto/endian | 31 +++++++++++++++++++++++++++++++ configure | 2 +- 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 auto/endian diff --git a/auto/endian b/auto/endian new file mode 100644 index 00000000..cb23639b --- /dev/null +++ b/auto/endian @@ -0,0 +1,31 @@ +# Copyright (C) Igor Sysoev +# Copyright (C) Andrew Clayton +# Copyright (C) Nginx, Inc. + + +nxt_feature="endianness" +nxt_feature_name= +nxt_feature_run=value +nxt_feature_incs= +nxt_feature_libs= +nxt_feature_test="#include + #include + + int main(void) { + int i = 0x11223344; + uint8_t *p; + + p = (uint8_t *)&i; + if (*p == 0x44) + printf(\"little endian\"); + else + printf(\"big endian\"); + return 0; + }" +. auto/feature + +if [ "$nxt_feature_value" = "little endian" ]; then + nxt_have=NXT_HAVE_LITTLE_ENDIAN . auto/have +else + nxt_have=NXT_HAVE_BIG_ENDIAN . auto/have +fi diff --git a/configure b/configure index 1d897f1d..8482b514 100755 --- a/configure +++ b/configure @@ -109,6 +109,7 @@ fi NXT_LIBRT= +. auto/endian . auto/types . auto/clang . auto/atomic @@ -136,7 +137,6 @@ fi case "$NXT_SYSTEM_PLATFORM" in i386 | amd64 | x86_64) - nxt_have=NXT_HAVE_LITTLE_ENDIAN . auto/have nxt_have=NXT_HAVE_NONALIGNED . auto/have ;; esac -- cgit From a8dde6a5ddac07348753ff9db681a950de6a62e5 Mon Sep 17 00:00:00 2001 From: Andrew Clayton Date: Fri, 2 Dec 2022 17:58:20 +0000 Subject: Fix endianness detection in nxt_websocket_header_t. The nxt_websocket_header_t structure defines the layout of a websocket frame header. As the websocket frame is mapped directly onto this structure its layout needs to match how it's coming off the network. The network being big endian means on big endian systems the structure layout can simply match that of the websocket frame header. On little endian systems we need to reverse the two bytes. This was done via the BYTE_ORDER, BIG_ENDIAN and LITTLE_ENDIAN macros, however these are not universal, e.g they are _not_ defined on illumos (OpenSolaris / OpenIndiana) and so we get the following compiler errors In file included from src/nxt_h1proto.c:12:0: src/nxt_websocket_header.h:25:13: error: duplicate member 'opcode' uint8_t opcode:4; ^~~~~~ src/nxt_websocket_header.h:26:13: error: duplicate member 'rsv3' uint8_t rsv3:1; ^~~~ src/nxt_websocket_header.h:27:13: error: duplicate member 'rsv2' uint8_t rsv2:1; ^~~~ src/nxt_websocket_header.h:28:13: error: duplicate member 'rsv1' uint8_t rsv1:1; ^~~~ src/nxt_websocket_header.h:29:13: error: duplicate member 'fin' uint8_t fin:1; ^~~ src/nxt_websocket_header.h:31:13: error: duplicate member 'payload_len' uint8_t payload_len:7; ^~~~~~~~~~~ src/nxt_websocket_header.h:32:13: error: duplicate member 'mask' uint8_t mask:1; ^~~~ This commit fixes that by using the new NXT_HAVE_{BIG,LITTLE}_ENDIAN macros introduced in the previous commit. Closes: Fixes: e501c74 ("Introducing websocket support in router and libunit.") Reviewed-by: Alejandro Colomar Signed-off-by: Andrew Clayton --- src/nxt_websocket_header.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nxt_websocket_header.h b/src/nxt_websocket_header.h index f75dfacd..cb7431dd 100644 --- a/src/nxt_websocket_header.h +++ b/src/nxt_websocket_header.h @@ -10,7 +10,7 @@ typedef struct { -#if (BYTE_ORDER == BIG_ENDIAN) +#if (NXT_HAVE_BIG_ENDIAN) uint8_t fin:1; uint8_t rsv1:1; uint8_t rsv2:1; @@ -21,7 +21,7 @@ typedef struct { uint8_t payload_len:7; #endif -#if (BYTE_ORDER == LITTLE_ENDIAN) +#if (NXT_HAVE_LITTLE_ENDIAN) uint8_t opcode:4; uint8_t rsv3:1; uint8_t rsv2:1; -- cgit From 420ddd4e493fb390c52ea638b22aa00e12fd2f9a Mon Sep 17 00:00:00 2001 From: Andrew Clayton Date: Mon, 7 Nov 2022 00:06:43 +0000 Subject: PHP: Fix a potential problem parsing the path. @dward on GitHub reported an issue with a URL like http://foo.bar/test.php?blah=test.php/foo where we would end up trying to run the script test.php?blah=test.php In the PHP module the format 'file.php/' is treated as a special case in nxt_php_dynamic_request() where we check the _path_ part of the url for the string '.php/'. The problem is that the path actually also contains the query string, thus we were finding 'test.php/' in the above URL and treating that whole path as the script to run. The fix is simple, replace the strstr(3) with a memmem(3), where we can limit the amount of path we use for the check. The trick here and what is not obvious from the code is that while path.start points to the whole path including the query string, path.length only contains the length of the _path_ part. NOTE: memmem(3) is a GNU extension and is neither specified by POSIX or ISO C, however it is available on a number of other systems, including: FreeBSD, OpenBSD, NetBSD, illumos, and macOS. If it comes to it we can implement a simple alternative for systems which lack memmem(3). This also adds a test case (provided by @dward) to cover this. Closes: Cc: Andrei Zeliankou Reviewed-by: Alejandro Colomar Reviewed-by: Andrei Zeliankou [test] Signed-off-by: Andrew Clayton --- src/nxt_php_sapi.c | 3 ++- test/test_php_targets.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/nxt_php_sapi.c b/src/nxt_php_sapi.c index 126a4684..d2494938 100644 --- a/src/nxt_php_sapi.c +++ b/src/nxt_php_sapi.c @@ -1025,7 +1025,8 @@ nxt_php_dynamic_request(nxt_php_run_ctx_t *ctx, nxt_unit_request_t *r) nxt_str_null(&script_name); - ctx->path_info.start = (u_char *) strstr((char *) path.start, ".php/"); + ctx->path_info.start = memmem(path.start, path.length, ".php/", + strlen(".php/")); if (ctx->path_info.start != NULL) { ctx->path_info.start += 4; path.length = ctx->path_info.start - path.start; diff --git a/test/test_php_targets.py b/test/test_php_targets.py index 918c5fda..eec1846f 100644 --- a/test/test_php_targets.py +++ b/test/test_php_targets.py @@ -47,6 +47,7 @@ class TestPHPTargets(TestApplicationPHP): assert self.get(url='/2')['body'] == '2' assert self.get(url='/blah')['status'] == 503 # TODO 404 assert self.get(url='/')['body'] == 'index' + assert self.get(url='/1.php?test=test.php/')['body'] == '1' assert 'success' in self.conf( "\"1.php\"", 'applications/targets/targets/default/index' -- cgit From 21bc8ee15fb4e7744c65d0f3b13adf17caf8c81a Mon Sep 17 00:00:00 2001 From: Andrew Clayton Date: Fri, 20 Jan 2023 03:27:59 +0000 Subject: Python: ASGI: Factor out event loop creation to its own function. This is a preparatory patch that factors out the asyncio event loop creation code from nxt_python_asgi_ctx_data_alloc() into its own function, to facilitate being called multiple times. This a part of the work to move away from using the asyncio.get_event_loop() function due to it no longer creating event loops if there wasn't one running. See the following commit for the gory details. Reviewed-by: Alejandro Colomar Signed-off-by: Andrew Clayton --- src/python/nxt_python_asgi.c | 56 +++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/src/python/nxt_python_asgi.c b/src/python/nxt_python_asgi.c index 587a17cf..716814a8 100644 --- a/src/python/nxt_python_asgi.c +++ b/src/python/nxt_python_asgi.c @@ -17,6 +17,8 @@ static PyObject *nxt_python_asgi_get_func(PyObject *obj); +static PyObject *nxt_python_asgi_get_event_loop(PyObject *asyncio, + const char *event_loop_func); static int nxt_python_asgi_ctx_data_alloc(void **pdata, int main); static void nxt_python_asgi_ctx_data_free(void *data); static int nxt_python_asgi_startup(void *data); @@ -201,11 +203,41 @@ nxt_python_asgi_init(nxt_unit_init_t *init, nxt_python_proto_t *proto) } +static PyObject * +nxt_python_asgi_get_event_loop(PyObject *asyncio, const char *event_loop_func) +{ + PyObject *event_loop, *loop; + + event_loop = PyDict_GetItemString(PyModule_GetDict(asyncio), + event_loop_func); + if (nxt_slow_path(event_loop == NULL)) { + nxt_unit_alert(NULL, "Python failed to get '%s' from module 'asyncio'", + event_loop_func); + return NULL; + } + + if (nxt_slow_path(PyCallable_Check(event_loop) == 0)) { + nxt_unit_alert(NULL, "'asyncio.%s' is not a callable object", + event_loop_func); + return NULL; + } + + loop = PyObject_CallObject(event_loop, NULL); + if (nxt_slow_path(loop == NULL)) { + nxt_unit_alert(NULL, "Python failed to call 'asyncio.%s'", + event_loop_func); + return NULL; + } + + return loop; +} + + static int nxt_python_asgi_ctx_data_alloc(void **pdata, int main) { uint32_t i; - PyObject *asyncio, *loop, *event_loop, *obj; + PyObject *asyncio, *loop, *obj; const char *event_loop_func; nxt_py_asgi_ctx_data_t *ctx_data; @@ -243,26 +275,8 @@ nxt_python_asgi_ctx_data_alloc(void **pdata, int main) event_loop_func = main ? "get_event_loop" : "new_event_loop"; - event_loop = PyDict_GetItemString(PyModule_GetDict(asyncio), - event_loop_func); - if (nxt_slow_path(event_loop == NULL)) { - nxt_unit_alert(NULL, - "Python failed to get '%s' from module 'asyncio'", - event_loop_func); - goto fail; - } - - if (nxt_slow_path(PyCallable_Check(event_loop) == 0)) { - nxt_unit_alert(NULL, - "'asyncio.%s' is not a callable object", - event_loop_func); - goto fail; - } - - loop = PyObject_CallObject(event_loop, NULL); - if (nxt_slow_path(loop == NULL)) { - nxt_unit_alert(NULL, "Python failed to call 'asyncio.%s'", - event_loop_func); + loop = nxt_python_asgi_get_event_loop(asyncio, event_loop_func); + if (loop == NULL) { goto fail; } -- cgit From 843ae1b842a180605f8d5e897d5e7cb128375fc1 Mon Sep 17 00:00:00 2001 From: Andrew Clayton Date: Fri, 20 Jan 2023 03:33:37 +0000 Subject: Python: ASGI: Switch away from asyncio.get_event_loop(). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Several users on GitHub reported issues with running Python ASGI apps on Unit with Python 3.11.1 (this would also effect Python 3.10.9) with the following error from Unit 2023/01/15 22:43:22 [alert] 0#77128 [unit] Python failed to call 'asyncio.get_event_loop' TL;DR asyncio.get_event_loop() is currently broken due to the process of deprecating part or all of it. First some history. In Unit we had this commit commit 8dcb0b9987033d0349a6ecf528014a9daa574787 Author: Max Romanov Date: Thu Nov 5 00:04:59 2020 +0300 Python: request processing in multiple threads. One of things this did was to create a new asyncio event loop in each thread using asyncio.new_event_loop(). It's perhaps worth noting that all these asyncio.* functions are Python functions that we call from the C code in Unit. Then we had this commit commit f27fbd9b4d2bdaddf1e7001d0d0bc5586ba04cd4 Author: Max Romanov Date: Tue Jul 20 10:37:54 2021 +0300 Python: using default event_loop for main thread for ASGI. This changed things so that Unit calls asyncio.get_event_loop() in the _main_ thread (but still calls asyncio.new_event_loop() in the other threads). asyncio.get_event_loop() up until recently would either return an already running event loop or return a newly created one. This was done for $reasons that the commit message and GitHub issue #560 hint at. But the intimation is that there can already be an event loop running from the application (I assume it's referring to the users application) at this point and if there is we should use it. Now for the Python side of things. On the main branch we had commit 172c0f2752d8708b6dda7b42e6c5a3519420a4e8 Author: Serhiy Storchaka Date: Sun Apr 25 13:40:44 2021 +0300 bpo-39529: Deprecate creating new event loop in asyncio.get_event_loop() (GH-23554) This commit began the deprecating of asyncio.get_event_loop(). commit fd38a2f0ec03b4eec5e3cfd41241d198b1ee555a Author: Serhiy Storchaka Date: Tue Dec 6 19:42:12 2022 +0200 gh-93453: No longer create an event loop in get_event_loop() (#98440) This turned asyncio.get_event_loop() into a RuntimeError _if_ there isn't a current event loop. commit e5bd5ad70d9e549eeb80aadb4f3ccb0f2f23266d Author: Serhiy Storchaka Date: Fri Jan 13 14:40:29 2023 +0200 gh-100160: Restore and deprecate implicit creation of an event loop (GH-100410) This re-creates the event loop if there wasn't one and emits a deprecation warning. After at least the last two commits Unit no longer works with the Python _main_ branch. Meanwhile on the 3.11 branch we had commit 3fae04b10e2655a20a3aadb5e0d63e87206d0c67 Author: Serhiy Storchaka Date: Tue Dec 6 17:15:44 2022 +0200 [3.11] gh-93453: Only emit deprecation warning in asyncio.get_event_loop when a new event loop is created (#99949) which is what caused our breakage, though perhaps unintentionally as we get the following traceback Traceback (most recent call last): File "/usr/lib64/python3.11/asyncio/events.py", line 676, in get_event_loop f = sys._getframe(1) ^^^^^^^^^^^^^^^^ ValueError: call stack is not deep enough 2023/01/18 02:46:10 [alert] 0#180279 [unit] Python failed to call 'asyncio.get_event_loop' However, regardless, it is clear we need to stop using asyncio.get_event_loop(). One option is to switch to the higher level asyncio.run() API, however that is a rather large change. This commit takes the simpler approach of using asyncio.get_running_loop() (which it seems get_event_loop() will eventually be an alias of) in the _main_ thread to return the currently running event loop, or if there is no current event loop, it will call asyncio.new_event_loop() to return a newly created event loop. I believe this mimics the current behaviour. In my testing get_event_loop() seemed to always return a newly created loop, as when just calling get_running_loop() it would return NULL and we would fail out. When running two processes each with 2 threads we would get the following loops with Python 3.11.0 and unpatched Unit <_UnixSelectorEventLoop running=False closed=False debug=False> <_UnixSelectorEventLoop running=False closed=False debug=False> <_UnixSelectorEventLoop running=False closed=False debug=False> <_UnixSelectorEventLoop running=False closed=False debug=False> and with Python 3.11.1 and a patched Unit we would get <_UnixSelectorEventLoop running=False closed=False debug=False> <_UnixSelectorEventLoop running=False closed=False debug=False> <_UnixSelectorEventLoop running=False closed=False debug=False> <_UnixSelectorEventLoop running=False closed=False debug=False> Tested-by: RafaƂ Safin Reviewed-by: Alejandro Colomar Signed-off-by: Andrew Clayton --- src/python/nxt_python_asgi.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/python/nxt_python_asgi.c b/src/python/nxt_python_asgi.c index 716814a8..f26f5a5d 100644 --- a/src/python/nxt_python_asgi.c +++ b/src/python/nxt_python_asgi.c @@ -241,6 +241,12 @@ nxt_python_asgi_ctx_data_alloc(void **pdata, int main) const char *event_loop_func; nxt_py_asgi_ctx_data_t *ctx_data; +#if PY_VERSION_HEX < NXT_PYTHON_VER(3, 7) + static const char *main_event_loop_func = "get_event_loop"; +#else + static const char *main_event_loop_func = "get_running_loop"; +#endif + ctx_data = nxt_unit_malloc(NULL, sizeof(nxt_py_asgi_ctx_data_t)); if (nxt_slow_path(ctx_data == NULL)) { nxt_unit_alert(NULL, "Failed to allocate context data"); @@ -273,11 +279,24 @@ nxt_python_asgi_ctx_data_alloc(void **pdata, int main) goto fail; } - event_loop_func = main ? "get_event_loop" : "new_event_loop"; + event_loop_func = main ? main_event_loop_func : "new_event_loop"; loop = nxt_python_asgi_get_event_loop(asyncio, event_loop_func); if (loop == NULL) { +#if PY_VERSION_HEX < NXT_PYTHON_VER(3, 7) goto fail; +#else + if (!main) { + goto fail; + } + + PyErr_Clear(); + + loop = nxt_python_asgi_get_event_loop(asyncio, "new_event_loop"); + if (nxt_slow_path(loop == NULL)) { + goto fail; + } +#endif } for (i = 0; i < nxt_nitems(handlers); i++) { -- cgit From b2d19155787e7dd85f0a915bb74d4c9aa2cd91d6 Mon Sep 17 00:00:00 2001 From: Andrew Clayton Date: Tue, 7 Feb 2023 13:11:10 +0000 Subject: Python: ASGI: Don't log asyncio.get_running_loop() errors. This adds a check to nxt_python_asgi_get_event_loop() on the event_loop_func name in the case that running that function fails, and if it's get_running_loop() that failed we skip printing an error message as this is an often expected behaviour since the previous commit and we don't want users reporting erroneous bugs. This check will always happen regardless of Python version while it really only applies to Python >= 3.7, there didn't seem much point adding complexity to the code for this case and in what will be an ever diminishing case of people running older Pythons. Reviewed-by: Alejandro Colomar Signed-off-by: Andrew Clayton --- src/python/nxt_python_asgi.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/python/nxt_python_asgi.c b/src/python/nxt_python_asgi.c index f26f5a5d..adf03e2b 100644 --- a/src/python/nxt_python_asgi.c +++ b/src/python/nxt_python_asgi.c @@ -224,8 +224,11 @@ nxt_python_asgi_get_event_loop(PyObject *asyncio, const char *event_loop_func) loop = PyObject_CallObject(event_loop, NULL); if (nxt_slow_path(loop == NULL)) { - nxt_unit_alert(NULL, "Python failed to call 'asyncio.%s'", - event_loop_func); + if (strcmp(event_loop_func, "get_running_loop") != 0) { + nxt_unit_alert(NULL, "Python failed to call 'asyncio.%s'", + event_loop_func); + } + return NULL; } -- cgit From 1f37d8121a3dfc2f039b859835c4ec22e77f01c9 Mon Sep 17 00:00:00 2001 From: Zhidao HONG Date: Mon, 30 Jan 2023 11:16:01 +0800 Subject: NJS: adding the missing vm destruction. This commit fixed the njs memory leak happened in the config validation, updating and http requests. --- docs/changes.xml | 6 ++++++ src/nxt_conf_validation.c | 18 ++++++++++++++---- src/nxt_http_request.c | 4 ++++ src/nxt_js.c | 17 +++++++++++++++++ src/nxt_js.h | 2 ++ src/nxt_router.c | 6 ++++++ src/nxt_tstr.c | 18 ++++++++++++++++++ src/nxt_tstr.h | 2 ++ 8 files changed, 69 insertions(+), 4 deletions(-) diff --git a/docs/changes.xml b/docs/changes.xml index a34a24e3..fe7b9fe2 100644 --- a/docs/changes.xml +++ b/docs/changes.xml @@ -25,6 +25,12 @@ NGINX Unit updated to 1.29.1. + + +memory leak related to NJS. + + + diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c index bf8aa760..537a3fb7 100644 --- a/src/nxt_conf_validation.c +++ b/src/nxt_conf_validation.c @@ -1284,25 +1284,35 @@ nxt_conf_validate(nxt_conf_validation_t *vldt) vldt->tstr_state = nxt_tstr_state_new(vldt->pool, 1); if (nxt_slow_path(vldt->tstr_state == NULL)) { - return NXT_ERROR; + ret = NXT_ERROR; + goto fail; } ret = nxt_conf_vldt_type(vldt, NULL, vldt->conf, NXT_CONF_VLDT_OBJECT); if (ret != NXT_OK) { - return ret; + goto fail; } ret = nxt_conf_vldt_object(vldt, vldt->conf, nxt_conf_vldt_root_members); if (ret != NXT_OK) { - return ret; + goto fail; } ret = nxt_tstr_state_done(vldt->tstr_state, error); if (ret != NXT_OK) { - return nxt_conf_vldt_error(vldt, "%s", error); + ret = nxt_conf_vldt_error(vldt, "%s", error); + goto fail; } + nxt_tstr_state_release(vldt->tstr_state); + return NXT_OK; + +fail: + + nxt_tstr_state_release(vldt->tstr_state); + + return ret; } diff --git a/src/nxt_http_request.c b/src/nxt_http_request.c index 73ffd2f0..e78975aa 100644 --- a/src/nxt_http_request.c +++ b/src/nxt_http_request.c @@ -833,6 +833,10 @@ nxt_http_request_close_handler(nxt_task_t *task, void *obj, void *data) r->body->file->fd = -1; } + if (r->tstr_query != NULL) { + nxt_tstr_query_release(r->tstr_query); + } + if (nxt_fast_path(proto.any != NULL)) { protocol = r->protocol; diff --git a/src/nxt_js.c b/src/nxt_js.c index aa3c4af5..4327e848 100644 --- a/src/nxt_js.c +++ b/src/nxt_js.c @@ -46,6 +46,7 @@ nxt_js_conf_new(nxt_mp_t *mp) jcf->funcs = nxt_array_create(mp, 4, sizeof(nxt_str_t)); if (nxt_slow_path(jcf->funcs == NULL)) { + njs_vm_destroy(jcf->vm); return NULL; } @@ -53,6 +54,13 @@ nxt_js_conf_new(nxt_mp_t *mp) } +void +nxt_js_conf_release(nxt_js_conf_t *jcf) +{ + njs_vm_destroy(jcf->vm); +} + + void nxt_js_set_proto(nxt_js_conf_t *jcf, njs_external_t *proto, njs_uint_t n) { @@ -297,3 +305,12 @@ nxt_js_call(nxt_task_t *task, nxt_js_cache_t *cache, nxt_js_t *js, return NXT_OK; } + + +void +nxt_js_release(nxt_js_cache_t *cache) +{ + if (cache->vm != NULL) { + njs_vm_destroy(cache->vm); + } +} diff --git a/src/nxt_js.h b/src/nxt_js.h index dea43fe3..74d041ca 100644 --- a/src/nxt_js.h +++ b/src/nxt_js.h @@ -22,12 +22,14 @@ typedef struct { nxt_js_conf_t *nxt_js_conf_new(nxt_mp_t *mp); +void nxt_js_conf_release(nxt_js_conf_t *jcf); void nxt_js_set_proto(nxt_js_conf_t *jcf, njs_external_t *proto, nxt_uint_t n); nxt_js_t *nxt_js_add_tpl(nxt_js_conf_t *jcf, nxt_str_t *str, nxt_bool_t strz); nxt_int_t nxt_js_compile(nxt_js_conf_t *jcf); nxt_int_t nxt_js_test(nxt_js_conf_t *jcf, nxt_str_t *str, u_char *error); nxt_int_t nxt_js_call(nxt_task_t *task, nxt_js_cache_t *cache, nxt_js_t *js, nxt_str_t *str, void *ctx); +void nxt_js_release(nxt_js_cache_t *cache); extern njs_int_t nxt_js_proto_id; diff --git a/src/nxt_router.c b/src/nxt_router.c index edc015c5..17f6c572 100644 --- a/src/nxt_router.c +++ b/src/nxt_router.c @@ -1111,6 +1111,10 @@ temp_fail: fail: + if (rtcf->tstr_state != NULL) { + nxt_tstr_state_release(rtcf->tstr_state); + } + nxt_mp_destroy(mp); return NULL; @@ -3794,6 +3798,8 @@ nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint) nxt_router_access_log_release(task, lock, rtcf->access_log); + nxt_tstr_state_release(rtcf->tstr_state); + nxt_mp_thread_adopt(rtcf->mem_pool); nxt_mp_destroy(rtcf->mem_pool); diff --git a/src/nxt_tstr.c b/src/nxt_tstr.c index fd01797c..fda585b8 100644 --- a/src/nxt_tstr.c +++ b/src/nxt_tstr.c @@ -194,6 +194,15 @@ nxt_tstr_state_done(nxt_tstr_state_t *state, u_char *error) } +void +nxt_tstr_state_release(nxt_tstr_state_t *state) +{ +#if (NXT_HAVE_NJS) + nxt_js_conf_release(state->jcf); +#endif +} + + nxt_bool_t nxt_tstr_is_const(nxt_tstr_t *tstr) { @@ -315,3 +324,12 @@ nxt_tstr_query_handle(nxt_task_t *task, nxt_tstr_query_t *query, task, query->ctx, query->data); } } + + +void +nxt_tstr_query_release(nxt_tstr_query_t *query) +{ +#if (NXT_HAVE_NJS) + nxt_js_release(&query->cache->js); +#endif +} diff --git a/src/nxt_tstr.h b/src/nxt_tstr.h index 0cc24292..ce8e6f3a 100644 --- a/src/nxt_tstr.h +++ b/src/nxt_tstr.h @@ -42,6 +42,7 @@ nxt_tstr_t *nxt_tstr_compile(nxt_tstr_state_t *state, nxt_str_t *str, nxt_tstr_flags_t flags); nxt_int_t nxt_tstr_test(nxt_tstr_state_t *state, nxt_str_t *str, u_char *error); nxt_int_t nxt_tstr_state_done(nxt_tstr_state_t *state, u_char *error); +void nxt_tstr_state_release(nxt_tstr_state_t *state); nxt_bool_t nxt_tstr_is_const(nxt_tstr_t *tstr); void nxt_tstr_str(nxt_tstr_t *tstr, nxt_str_t *str); @@ -55,6 +56,7 @@ void nxt_tstr_query_resolve(nxt_task_t *task, nxt_tstr_query_t *query, void *data, nxt_work_handler_t ready, nxt_work_handler_t error); void nxt_tstr_query_handle(nxt_task_t *task, nxt_tstr_query_t *query, nxt_bool_t failed); +void nxt_tstr_query_release(nxt_tstr_query_t *query); nxt_inline nxt_bool_t -- cgit From 0277d8f1034f6f3dcdb5fd88dc3a9a3f04c1de89 Mon Sep 17 00:00:00 2001 From: Andrew Clayton Date: Fri, 25 Nov 2022 10:32:20 +0000 Subject: Isolation: Fix the enablement of PR_SET_NO_NEW_PRIVS. This prctl(2) option is checked for in auto/isolation, unfortunately due to a typo this feature has never been enabled. In the auto/isolation script the feature name was down as NXT_HAVE_PR_SET_NO_NEW_PRIVS0, which means we end up with the following in build/nxt_auto_config.h #ifndef NXT_HAVE_PR_SET_NO_NEW_PRIVS0 #define NXT_HAVE_PR_SET_NO_NEW_PRIVS0 1 #endif Whereas everywhere else is checking for NXT_HAVE_PR_SET_NO_NEW_PRIVS. This also guards the inclusion of sys/prctl.h in src/nxt_process.c which is required by a subsequent commit. Fixes: e2b53e1 ("Added "rootfs" feature.") Reviewed-by: Alejandro Colomar Signed-off-by: Andrew Clayton --- auto/isolation | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auto/isolation b/auto/isolation index cbf42d9d..b706c94d 100644 --- a/auto/isolation +++ b/auto/isolation @@ -90,7 +90,7 @@ nxt_feature_test="#include nxt_feature="prctl(PR_SET_NO_NEW_PRIVS)" -nxt_feature_name=NXT_HAVE_PR_SET_NO_NEW_PRIVS0 +nxt_feature_name=NXT_HAVE_PR_SET_NO_NEW_PRIVS nxt_feature_run=no nxt_feature_incs= nxt_feature_libs= -- cgit From b7f1d7253a8f44f31c2e1a8d9c8962ef30be83e9 Mon Sep 17 00:00:00 2001 From: Andrew Clayton Date: Fri, 18 Nov 2022 23:42:44 +0000 Subject: Isolation: Rename NXT_HAVE_CLONE -> NXT_HAVE_LINUX_NS. Due to the need to replace our use of clone/__NR_clone on Linux with fork(2)/unshare(2) for enabling Linux namespaces(7) to keep the pthreads(7) API working. Let's rename NXT_HAVE_CLONE to NXT_HAVE_LINUX_NS, i.e name it after the feature, not how it's implemented, then in future if we change how we do namespaces again we don't have to rename this. Reviewed-by: Alejandro Colomar Signed-off-by: Andrew Clayton --- auto/isolation | 14 +++++++------- auto/sources | 2 +- src/nxt_clone.c | 2 +- src/nxt_credential.c | 6 +++--- src/nxt_isolation.c | 8 ++++---- src/nxt_main_process.c | 2 +- src/nxt_process.c | 10 +++++----- src/nxt_process.h | 6 +++--- 8 files changed, 25 insertions(+), 25 deletions(-) diff --git a/auto/isolation b/auto/isolation index b706c94d..27f44624 100644 --- a/auto/isolation +++ b/auto/isolation @@ -4,7 +4,7 @@ # Linux clone syscall. NXT_ISOLATION=NO -NXT_HAVE_CLONE=NO +NXT_HAVE_LINUX_NS=NO NXT_HAVE_CLONE_NEWUSER=NO NXT_HAVE_MOUNT=NO NXT_HAVE_UNMOUNT=NO @@ -12,21 +12,21 @@ NXT_HAVE_ROOTFS=NO nsflags="USER NS PID NET UTS CGROUP" -nxt_feature="clone(2)" -nxt_feature_name=NXT_HAVE_CLONE +nxt_feature="Linux unshare()" +nxt_feature_name=NXT_HAVE_LINUX_NS nxt_feature_run=no nxt_feature_incs= nxt_feature_libs= -nxt_feature_test="#include - #include +nxt_feature_test="#define _GNU_SOURCE + #include int main(void) { - return SYS_clone | SIGCHLD; + return unshare(0); }" . auto/feature if [ $nxt_found = yes ]; then - NXT_HAVE_CLONE=YES + NXT_HAVE_LINUX_NS=YES # Test all isolation flags for flag in $nsflags; do diff --git a/auto/sources b/auto/sources index 29f3c7b5..2ca78844 100644 --- a/auto/sources +++ b/auto/sources @@ -299,7 +299,7 @@ if [ "$NXT_HAVE_HPUX_SENDFILE" = "YES" \ fi -if [ "$NXT_HAVE_CLONE" = "YES" ]; then +if [ "$NXT_HAVE_LINUX_NS" = "YES" ]; then NXT_LIB_SRCS="$NXT_LIB_SRCS $NXT_LIB_CLONE_SRCS" fi diff --git a/src/nxt_clone.c b/src/nxt_clone.c index a9b39ac1..a98aac47 100644 --- a/src/nxt_clone.c +++ b/src/nxt_clone.c @@ -8,7 +8,7 @@ #include #include -#if (NXT_HAVE_CLONE) +#if (NXT_HAVE_LINUX_NS) pid_t nxt_clone(nxt_int_t flags) diff --git a/src/nxt_credential.c b/src/nxt_credential.c index 168db9cf..bda97024 100644 --- a/src/nxt_credential.c +++ b/src/nxt_credential.c @@ -286,7 +286,7 @@ nxt_credential_setuid(nxt_task_t *task, nxt_credential_t *uc) if (setuid(uc->uid) != 0) { -#if (NXT_HAVE_CLONE) +#if (NXT_HAVE_LINUX_NS) if (nxt_errno == EINVAL) { nxt_log(task, NXT_LOG_ERR, "The uid %d (user \"%s\") isn't " "valid in the application namespace.", uc->uid, uc->user); @@ -314,7 +314,7 @@ nxt_credential_setgids(nxt_task_t *task, nxt_credential_t *uc) if (setgid(uc->base_gid) != 0) { -#if (NXT_HAVE_CLONE) +#if (NXT_HAVE_LINUX_NS) if (nxt_errno == EINVAL) { nxt_log(task, NXT_LOG_ERR, "The gid %d isn't valid in the " "application namespace.", uc->base_gid); @@ -333,7 +333,7 @@ nxt_credential_setgids(nxt_task_t *task, nxt_credential_t *uc) if (nxt_slow_path(uc->ngroups > 0 && setgroups(uc->ngroups, uc->gids) != 0)) { -#if (NXT_HAVE_CLONE) +#if (NXT_HAVE_LINUX_NS) if (nxt_errno == EINVAL) { nxt_log(task, NXT_LOG_ERR, "The user \"%s\" (uid: %d) has " "supplementary group ids not valid in the application " diff --git a/src/nxt_isolation.c b/src/nxt_isolation.c index b6b13c59..e43cf1f7 100644 --- a/src/nxt_isolation.c +++ b/src/nxt_isolation.c @@ -21,7 +21,7 @@ static nxt_int_t nxt_isolation_set_cgroup(nxt_task_t *task, nxt_conf_value_t *isolation, nxt_process_t *process); #endif -#if (NXT_HAVE_CLONE) +#if (NXT_HAVE_LINUX_NS) static nxt_int_t nxt_isolation_set_namespaces(nxt_task_t *task, nxt_conf_value_t *isolation, nxt_process_t *process); static nxt_int_t nxt_isolation_clone_flags(nxt_task_t *task, @@ -169,7 +169,7 @@ nxt_isolation_set(nxt_task_t *task, nxt_conf_value_t *isolation, } #endif -#if (NXT_HAVE_CLONE) +#if (NXT_HAVE_LINUX_NS) if (nxt_slow_path(nxt_isolation_set_namespaces(task, isolation, process) != NXT_OK)) { @@ -247,7 +247,7 @@ nxt_isolation_set_cgroup(nxt_task_t *task, nxt_conf_value_t *isolation, #endif -#if (NXT_HAVE_CLONE) +#if (NXT_HAVE_LINUX_NS) static nxt_int_t nxt_isolation_set_namespaces(nxt_task_t *task, nxt_conf_value_t *isolation, @@ -409,7 +409,7 @@ nxt_isolation_vldt_creds(nxt_task_t *task, nxt_process_t *process) #endif -#if (NXT_HAVE_CLONE) +#if (NXT_HAVE_LINUX_NS) static nxt_int_t nxt_isolation_clone_flags(nxt_task_t *task, nxt_conf_value_t *namespaces, diff --git a/src/nxt_main_process.c b/src/nxt_main_process.c index de41e8d7..4c89121e 100644 --- a/src/nxt_main_process.c +++ b/src/nxt_main_process.c @@ -556,7 +556,7 @@ nxt_main_process_created_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) nxt_assert(process != NULL); nxt_assert(process->state == NXT_PROCESS_STATE_CREATING); -#if (NXT_HAVE_CLONE && NXT_HAVE_CLONE_NEWUSER) +#if (NXT_HAVE_LINUX_NS && NXT_HAVE_CLONE_NEWUSER) if (nxt_is_clone_flag_set(process->isolation.clone.flags, NEWUSER)) { if (nxt_slow_path(nxt_clone_credential_map(task, process->pid, process->user_cred, diff --git a/src/nxt_process.c b/src/nxt_process.c index d8836ad2..b40eb8cf 100644 --- a/src/nxt_process.c +++ b/src/nxt_process.c @@ -7,7 +7,7 @@ #include #include -#if (NXT_HAVE_CLONE) +#if (NXT_HAVE_LINUX_NS) #include #endif @@ -18,7 +18,7 @@ #endif -#if (NXT_HAVE_CLONE) && (NXT_HAVE_CLONE_NEWPID) +#if (NXT_HAVE_LINUX_NS) && (NXT_HAVE_CLONE_NEWPID) #define nxt_is_pid_isolated(process) \ nxt_is_clone_flag_set(process->isolation.clone.flags, NEWPID) #else @@ -318,7 +318,7 @@ nxt_process_create(nxt_task_t *task, nxt_process_t *process) nxt_pid_t pid; nxt_runtime_t *rt; -#if (NXT_HAVE_CLONE) +#if (NXT_HAVE_LINUX_NS) pid = nxt_clone(SIGCHLD | process->isolation.clone.flags); if (nxt_slow_path(pid < 0)) { nxt_alert(task, "clone() failed for %s %E", process->name, nxt_errno); @@ -355,7 +355,7 @@ nxt_process_create(nxt_task_t *task, nxt_process_t *process) /* Parent. */ -#if (NXT_HAVE_CLONE) +#if (NXT_HAVE_LINUX_NS) nxt_debug(task, "clone(%s): %PI", process->name, pid); #else nxt_debug(task, "fork(%s): %PI", process->name, pid); @@ -781,7 +781,7 @@ nxt_process_apply_creds(nxt_task_t *task, nxt_process_t *process) cap_setid = rt->capabilities.setid; -#if (NXT_HAVE_CLONE && NXT_HAVE_CLONE_NEWUSER) +#if (NXT_HAVE_LINUX_NS && NXT_HAVE_CLONE_NEWUSER) if (!cap_setid && nxt_is_clone_flag_set(process->isolation.clone.flags, NEWUSER)) { diff --git a/src/nxt_process.h b/src/nxt_process.h index 0db68d45..1dd51521 100644 --- a/src/nxt_process.h +++ b/src/nxt_process.h @@ -7,13 +7,13 @@ #ifndef _NXT_PROCESS_H_INCLUDED_ #define _NXT_PROCESS_H_INCLUDED_ -#if (NXT_HAVE_CLONE) +#if (NXT_HAVE_LINUX_NS) #include #include #endif -#if (NXT_HAVE_CLONE) +#if (NXT_HAVE_LINUX_NS) /* * Old glibc wrapper for getpid(2) returns a cached pid invalidated only by * fork(2) calls. As we use clone(2) for container, it returns the wrong pid. @@ -100,7 +100,7 @@ typedef struct { nxt_cgroup_t cgroup; #endif -#if (NXT_HAVE_CLONE) +#if (NXT_HAVE_LINUX_NS) nxt_clone_t clone; #endif -- cgit From a83354f47331db1214cba4dd8899f2a002295b2f Mon Sep 17 00:00:00 2001 From: Andrew Clayton Date: Wed, 30 Nov 2022 00:13:22 +0000 Subject: Enable the PR_SET_CHILD_SUBREAPER prctl(2) option on Linux. This prctl(2) option can be used to set the "child subreaper" attribute of the calling process. This allows a process to take on the role of 'init', which means the process will inherit descendant processes when their immediate parent terminates. This will be used in an upcoming commit that uses a double fork(2) + unshare(2) to create a new PID namespace. The parent from the second fork will terminate leaving the child process to be inherited by 'init'. Aside from it being better to maintain the parent/child relationships between the various unit processes, without setting this you need to ^C twice to fully quit unit when running in the foreground after the double fork. Reviewed-by: Alejandro Colomar Signed-off-by: Andrew Clayton --- auto/isolation | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/auto/isolation b/auto/isolation index 27f44624..c535e80a 100644 --- a/auto/isolation +++ b/auto/isolation @@ -102,6 +102,19 @@ nxt_feature_test="#include . auto/feature +nxt_feature="prctl(PR_SET_CHILD_SUBREAPER)" +nxt_feature_name=NXT_HAVE_PR_SET_CHILD_SUBREAPER +nxt_feature_run=no +nxt_feature_incs= +nxt_feature_libs= +nxt_feature_test="#include + + int main(void) { + return PR_SET_CHILD_SUBREAPER; + }" +. auto/feature + + nxt_feature="Linux mount()" nxt_feature_name=NXT_HAVE_LINUX_MOUNT nxt_feature_run=no -- cgit From c1299faa7d2990acbeb677dfc036ca5179d2bf54 Mon Sep 17 00:00:00 2001 From: Andrew Clayton Date: Fri, 18 Nov 2022 23:53:30 +0000 Subject: Isolation: Switch to fork(2) & unshare(2) on Linux. On GitHub, @razvanphp & @hbernaciak both reported issues running the APCu PHP module under Unit. When using this module they were seeing errors like 'apcu_fetch(): Failed to acquire read lock' However when running APCu under php-fpm, everything was fine. The issue turned out to be due to our use of SYS_clone breaking the pthreads(7) API used by APCu. Even if we had been using glibc's clone(2) wrapper we would still have run into problems due to a known issue there. Essentially the problem is when using clone, glibc doesn't update the TID cache, so the child ends up having the same TID as the parent and that is used in various parts of pthreads(7) such as in the various locking primitives, so when APCu was grabbing a lock it ended up using the TID of the main unit process (rather than that of the php application processes that was grabbing the lock). So due to the above what was happening was when one of the application processes went to grab either a read or write lock, the lock was actually being attributed to the main unit process. If a process had acquired the write lock, then if a process tried to acquire a read or write lock then glibc would return EDEADLK due to detecting a deadlock situation due to thinking the process already held the write lock when in fact it didn't. It seems the right way to do this is via fork(2) and unshare(2). We already use fork(2) on other platforms. This requires a few tricks to keep the essence of the processes the same as before when using clone 1) We use the prctl(2) PR_SET_CHILD_SUBREAPER option (if its available, since Linux 3.4) to make the main unit process inherit prototype processes after a double fork(2), rather than them being reparented to 'init'. This avoids needing to ^C twice to fully exit unit when running in the foreground. It's probably also better if they maintain their parent child relationship where possible. 2) We use a double fork(2) technique on the prototype processes to ensure they themselves end up in a new PID namespace as PID 1 (when CLONE_NEWPID is being used). When using unshare(CLONE_NEWPID), the calling process is _not_ placed in the namespace (as discussed in pid_namespaces(7)). It only sets things up so that subsequent children are placed in a PID namespace. Having the prototype processes as PID 1 in the new PID namespace is probably a good thing and matches the behaviour of clone(2). Also, some isolation tests break if the prototype process is not PID 1. 3) Due to the above double fork(2) the main unit process looses track of the prototype process ID, which it needs to know. To solve this, we employ a simple pipe(2) between the main unit and prototype processes and pass the prototype grandchild PID from the parent of the second fork(2) before exiting. This needs to be done from the parent and not the grandchild, as the grandchild will see itself having a PID of 1 while the main process needs its externally visible PID. Link: Link: Closes: Reviewed-by: Alejandro Colomar Signed-off-by: Andrew Clayton --- src/nxt_process.c | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 247 insertions(+), 9 deletions(-) diff --git a/src/nxt_process.c b/src/nxt_process.c index b40eb8cf..a2980350 100644 --- a/src/nxt_process.c +++ b/src/nxt_process.c @@ -27,6 +27,19 @@ #endif +#if (NXT_HAVE_LINUX_NS) +static nxt_int_t nxt_process_pipe_timer(nxt_fd_t fd, short event); +static nxt_int_t nxt_process_check_pid_status(const nxt_fd_t *gc_pipe); +static nxt_pid_t nxt_process_recv_pid(const nxt_fd_t *pid_pipe, + const nxt_fd_t *gc_pipe); +static void nxt_process_send_pid(const nxt_fd_t *pid_pipe, nxt_pid_t pid); +static nxt_int_t nxt_process_unshare(nxt_task_t *task, nxt_process_t *process, + nxt_fd_t *pid_pipe, nxt_fd_t *gc_pipe, nxt_bool_t use_pidns); +static nxt_int_t nxt_process_init_pidns(nxt_task_t *task, + const nxt_process_t *process, nxt_fd_t *pid_pipe, nxt_fd_t *gc_pipe, + nxt_bool_t *use_pidns); +#endif + static nxt_pid_t nxt_process_create(nxt_task_t *task, nxt_process_t *process); static nxt_int_t nxt_process_do_start(nxt_task_t *task, nxt_process_t *process); static nxt_int_t nxt_process_whoami(nxt_task_t *task, nxt_process_t *process); @@ -311,6 +324,217 @@ nxt_process_child_fixup(nxt_task_t *task, nxt_process_t *process) } +#if (NXT_HAVE_LINUX_NS) + +static nxt_int_t +nxt_process_pipe_timer(nxt_fd_t fd, short event) +{ + int ret; + sigset_t mask; + struct pollfd pfd; + + static const struct timespec ts = { .tv_sec = 5 }; + + /* + * Temporarily block the signals we are handling, (except + * for SIGINT & SIGTERM) so that ppoll(2) doesn't get + * interrupted. After ppoll(2) returns, our old sigmask + * will be back in effect and any pending signals will be + * delivered. + * + * This is because while the kernel ppoll syscall updates + * the struct timespec with the time remaining if it got + * interrupted with EINTR, the glibc wrapper hides this + * from us so we have no way of knowing how long to retry + * the ppoll(2) for and if we just retry with the same + * timeout we could find ourselves in an infinite loop. + */ + pthread_sigmask(SIG_SETMASK, NULL, &mask); + sigdelset(&mask, SIGINT); + sigdelset(&mask, SIGTERM); + + pfd.fd = fd; + pfd.events = event; + + ret = ppoll(&pfd, 1, &ts, &mask); + if (ret <= 0 || (ret == 1 && pfd.revents & POLLERR)) { + return NXT_ERROR; + } + + return NXT_OK; +} + + +static nxt_int_t +nxt_process_check_pid_status(const nxt_fd_t *gc_pipe) +{ + int8_t status; + ssize_t ret; + + close(gc_pipe[1]); + + ret = nxt_process_pipe_timer(gc_pipe[0], POLLIN); + if (ret == NXT_OK) { + ret = read(gc_pipe[0], &status, sizeof(int8_t)); + } + + if (ret <= 0) { + status = -1; + } + + close(gc_pipe[0]); + + return status; +} + + +static nxt_pid_t +nxt_process_recv_pid(const nxt_fd_t *pid_pipe, const nxt_fd_t *gc_pipe) +{ + int8_t status; + ssize_t ret; + nxt_pid_t pid; + + close(pid_pipe[1]); + close(gc_pipe[0]); + + status = 0; + + ret = nxt_process_pipe_timer(pid_pipe[0], POLLIN); + if (ret == NXT_OK) { + ret = read(pid_pipe[0], &pid, sizeof(nxt_pid_t)); + } + + if (ret <= 0) { + status = -1; + pid = -1; + } + + write(gc_pipe[1], &status, sizeof(int8_t)); + + close(pid_pipe[0]); + close(gc_pipe[1]); + + return pid; +} + + +static void +nxt_process_send_pid(const nxt_fd_t *pid_pipe, nxt_pid_t pid) +{ + nxt_int_t ret; + + close(pid_pipe[0]); + + ret = nxt_process_pipe_timer(pid_pipe[1], POLLOUT); + if (ret == NXT_OK) { + write(pid_pipe[1], &pid, sizeof(nxt_pid_t)); + } + + close(pid_pipe[1]); +} + + +static nxt_int_t +nxt_process_unshare(nxt_task_t *task, nxt_process_t *process, + nxt_fd_t *pid_pipe, nxt_fd_t *gc_pipe, + nxt_bool_t use_pidns) +{ + int ret; + nxt_pid_t pid; + + if (process->isolation.clone.flags == 0) { + return NXT_OK; + } + + ret = unshare(process->isolation.clone.flags); + if (nxt_slow_path(ret == -1)) { + nxt_alert(task, "unshare() failed for %s %E", process->name, + nxt_errno); + + if (use_pidns) { + nxt_pipe_close(task, gc_pipe); + nxt_pipe_close(task, pid_pipe); + } + + return NXT_ERROR; + } + + if (!use_pidns) { + return NXT_OK; + } + + /* + * PID namespace requested. Employ a double fork(2) technique + * so that the prototype process will be placed into the new + * namespace and end up with PID 1 (as before with clone). + */ + pid = fork(); + if (nxt_slow_path(pid < 0)) { + nxt_alert(task, "fork() failed for %s %E", process->name, nxt_errno); + nxt_pipe_close(task, gc_pipe); + nxt_pipe_close(task, pid_pipe); + + return NXT_ERROR; + + } else if (pid > 0) { + nxt_pipe_close(task, gc_pipe); + nxt_process_send_pid(pid_pipe, pid); + + _exit(EXIT_SUCCESS); + } + + nxt_pipe_close(task, pid_pipe); + ret = nxt_process_check_pid_status(gc_pipe); + if (ret == -1) { + return NXT_ERROR; + } + + return NXT_OK; +} + + +static nxt_int_t +nxt_process_init_pidns(nxt_task_t *task, const nxt_process_t *process, + nxt_fd_t *pid_pipe, nxt_fd_t *gc_pipe, + nxt_bool_t *use_pidns) +{ + int ret; + + *use_pidns = 0; + +#if (NXT_HAVE_CLONE_NEWPID) + *use_pidns = nxt_is_pid_isolated(process); +#endif + + if (!*use_pidns) { + return NXT_OK; + } + + ret = nxt_pipe_create(task, pid_pipe, 0, 0); + if (nxt_slow_path(ret == NXT_ERROR)) { + return NXT_ERROR; + } + + ret = nxt_pipe_create(task, gc_pipe, 0, 0); + if (nxt_slow_path(ret == NXT_ERROR)) { + return NXT_ERROR; + } + +#if (NXT_HAVE_PR_SET_CHILD_SUBREAPER) + ret = prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0); + if (nxt_slow_path(ret == -1)) { + nxt_alert(task, "prctl(PR_SET_CHILD_SUBREAPER) failed for %s %E", + process->name, nxt_errno); + } +#endif + + return NXT_OK; +} + +#endif /* NXT_HAVE_LINUX_NS */ + + static nxt_pid_t nxt_process_create(nxt_task_t *task, nxt_process_t *process) { @@ -319,22 +543,31 @@ nxt_process_create(nxt_task_t *task, nxt_process_t *process) nxt_runtime_t *rt; #if (NXT_HAVE_LINUX_NS) - pid = nxt_clone(SIGCHLD | process->isolation.clone.flags); - if (nxt_slow_path(pid < 0)) { - nxt_alert(task, "clone() failed for %s %E", process->name, nxt_errno); - return pid; + nxt_fd_t pid_pipe[2], gc_pipe[2]; + nxt_bool_t use_pidns; + + ret = nxt_process_init_pidns(task, process, pid_pipe, gc_pipe, &use_pidns); + if (ret == NXT_ERROR) { + return -1; } -#else +#endif + pid = fork(); if (nxt_slow_path(pid < 0)) { nxt_alert(task, "fork() failed for %s %E", process->name, nxt_errno); return pid; } -#endif if (pid == 0) { /* Child. */ +#if (NXT_HAVE_LINUX_NS) + ret = nxt_process_unshare(task, process, pid_pipe, gc_pipe, use_pidns); + if (ret == NXT_ERROR) { + _exit(EXIT_FAILURE); + } +#endif + ret = nxt_process_child_fixup(task, process); if (nxt_slow_path(ret != NXT_OK)) { nxt_process_quit(task, 1); @@ -355,10 +588,15 @@ nxt_process_create(nxt_task_t *task, nxt_process_t *process) /* Parent. */ -#if (NXT_HAVE_LINUX_NS) - nxt_debug(task, "clone(%s): %PI", process->name, pid); -#else nxt_debug(task, "fork(%s): %PI", process->name, pid); + +#if (NXT_HAVE_LINUX_NS) + if (use_pidns) { + pid = nxt_process_recv_pid(pid_pipe, gc_pipe); + if (pid == -1) { + return pid; + } + } #endif process->pid = pid; -- cgit From b9c1a2977b161e6befbc1fa770f6fe482ea3e9ca Mon Sep 17 00:00:00 2001 From: Andrew Clayton Date: Sat, 19 Nov 2022 02:27:22 +0000 Subject: Isolation: Remove nxt_clone(). Since the previous commit, this is no longer used. Reviewed-by: Alejandro Colomar Signed-off-by: Andrew Clayton --- src/nxt_clone.c | 14 -------------- src/nxt_clone.h | 3 --- 2 files changed, 17 deletions(-) diff --git a/src/nxt_clone.c b/src/nxt_clone.c index a98aac47..1cd70f6c 100644 --- a/src/nxt_clone.c +++ b/src/nxt_clone.c @@ -8,20 +8,6 @@ #include #include -#if (NXT_HAVE_LINUX_NS) - -pid_t -nxt_clone(nxt_int_t flags) -{ -#if defined(__s390x__) || defined(__s390__) || defined(__CRIS__) - return syscall(SYS_clone, NULL, flags); -#else - return syscall(SYS_clone, flags, NULL); -#endif -} - -#endif - #if (NXT_HAVE_CLONE_NEWUSER) diff --git a/src/nxt_clone.h b/src/nxt_clone.h index c2066ce6..6cea1bd7 100644 --- a/src/nxt_clone.h +++ b/src/nxt_clone.h @@ -33,9 +33,6 @@ typedef struct { } nxt_clone_t; -pid_t nxt_clone(nxt_int_t flags); - - #define nxt_is_clone_flag_set(flags, test) \ ((flags & CLONE_##test) == CLONE_##test) -- cgit From 58812e74d3a0ab14b528933e1953ae28c8f9f627 Mon Sep 17 00:00:00 2001 From: Andrew Clayton Date: Sat, 19 Nov 2022 23:58:51 +0000 Subject: Isolation: Remove the syscall(SYS_getpid) wrapper. When using SYS_clone we used the getpid kernel system call directly via syscall(SYS_getpid) to avoid issues with cached pids. However since we are now only using fork(2) (+ unshare(2) for namespaces) we no longer need to call the kernel getpid directly as the fork(2) will ensure the cached pid is invalidated. Reviewed-by: Alejandro Colomar Signed-off-by: Andrew Clayton --- src/nxt_process.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/nxt_process.h b/src/nxt_process.h index 1dd51521..de54e383 100644 --- a/src/nxt_process.h +++ b/src/nxt_process.h @@ -13,17 +13,8 @@ #endif -#if (NXT_HAVE_LINUX_NS) -/* - * Old glibc wrapper for getpid(2) returns a cached pid invalidated only by - * fork(2) calls. As we use clone(2) for container, it returns the wrong pid. - */ -#define nxt_getpid() \ - syscall(SYS_getpid) -#else #define nxt_getpid() \ getpid() -#endif typedef pid_t nxt_pid_t; -- cgit From 7d7b5a977c4e461976422c59f4594280b05dde0a Mon Sep 17 00:00:00 2001 From: Andrew Clayton Date: Thu, 1 Dec 2022 21:05:39 +0000 Subject: Remove the nxt_getpid() alias. Since the previous commit, nxt_getpid() is only ever aliased to getpid(2). nxt_getpid() was only used once in the code, while there are multiple direct uses of getpid(2) $ grep -r "getpid()" src/ src/nxt_unit.c: nxt_unit_pid = getpid(); src/nxt_process.c: nxt_pid = nxt_getpid(); src/nxt_process.c: nxt_pid = getpid(); src/nxt_lib.c: nxt_pid = getpid(); src/nxt_process.h:#define nxt_getpid() \ src/nxt_process.h:#define nxt_getpid() \ src/nxt_process.h: getpid() Just remove it and convert the _single_ instance of nxt_getpid() to getpid(2). Reviewed-by: Alejandro Colomar Signed-off-by: Andrew Clayton --- src/nxt_process.c | 2 +- src/nxt_process.h | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/nxt_process.c b/src/nxt_process.c index a2980350..fe9349e8 100644 --- a/src/nxt_process.c +++ b/src/nxt_process.c @@ -269,7 +269,7 @@ nxt_process_child_fixup(nxt_task_t *task, nxt_process_t *process) nxt_ppid = nxt_pid; - nxt_pid = nxt_getpid(); + nxt_pid = getpid(); process->pid = nxt_pid; process->isolated_pid = nxt_pid; diff --git a/src/nxt_process.h b/src/nxt_process.h index de54e383..16d6110c 100644 --- a/src/nxt_process.h +++ b/src/nxt_process.h @@ -13,9 +13,6 @@ #endif -#define nxt_getpid() \ - getpid() - typedef pid_t nxt_pid_t; -- cgit From 1b7cf1f3d00adbbcd17890f1475c2c36f75c3f68 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Tue, 21 Feb 2023 15:35:38 +0000 Subject: Tests: added Python tests with encoding. --- test/python/encoding/wsgi.py | 12 +++++++ test/python/unicode/wsgi.py | 8 +++++ test/test_python_application.py | 78 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 test/python/encoding/wsgi.py create mode 100644 test/python/unicode/wsgi.py diff --git a/test/python/encoding/wsgi.py b/test/python/encoding/wsgi.py new file mode 100644 index 00000000..0a916a9b --- /dev/null +++ b/test/python/encoding/wsgi.py @@ -0,0 +1,12 @@ +import sys + + +def application(environ, start_response): + start_response( + '200', + [ + ('Content-Length', '0'), + ('X-Encoding', sys.getfilesystemencoding()), + ], + ) + return [] diff --git a/test/python/unicode/wsgi.py b/test/python/unicode/wsgi.py new file mode 100644 index 00000000..40043af9 --- /dev/null +++ b/test/python/unicode/wsgi.py @@ -0,0 +1,8 @@ +def application(environ, start_response): + temp_dir = environ.get('HTTP_TEMP_DIR') + + with open(temp_dir + '/tempfile', 'w') as f: + f.write('\u26a0\ufe0f') + + start_response('200', [('Content-Length', '0')]) + return [] diff --git a/test/test_python_application.py b/test/test_python_application.py index c9483b6a..c9065eae 100644 --- a/test/test_python_application.py +++ b/test/test_python_application.py @@ -2,9 +2,12 @@ import grp import os import pwd import re +import subprocess import time +import venv import pytest +from packaging import version from unit.applications.lang.python import TestApplicationPython @@ -526,6 +529,81 @@ last line: 987654321 assert self.get()['body'] == '0123456789', 'write' + def test_python_application_encoding(self): + self.load('encoding') + + try: + locales = ( + subprocess.check_output( + ['locale', '-a'], + stderr=subprocess.STDOUT, + ) + .decode() + .splitlines() + ) + except ( + FileNotFoundError, + UnicodeDecodeError, + subprocess.CalledProcessError, + ): + pytest.skip('require locale') + + to_check = [ + re.compile(r'.*UTF[-_]?8'), + re.compile(r'.*ISO[-_]?8859[-_]?1'), + ] + matches = [ + loc + for loc in locales + if any(pattern.match(loc.upper()) for pattern in to_check) + ] + + if not matches: + pytest.skip('no available locales') + + def unify(str): + str.upper().replace('-', '').replace('_', '') + + for loc in matches: + assert 'success' in self.conf( + {"LC_CTYPE": loc, "LC_ALL": ""}, + '/config/applications/encoding/environment', + ) + resp = self.get() + assert resp['status'] == 200, 'status' + assert unify(resp['headers']['X-Encoding']) == unify( + loc.split('.')[-1] + ) + + def test_python_application_unicode(self, temp_dir): + try: + app_type = self.get_application_type() + v = version.Version(app_type.split()[-1]) + if v.major != 3: + raise version.InvalidVersion + + except version.InvalidVersion: + pytest.skip('require python module version 3') + + venv_path = temp_dir + '/venv' + venv.create(venv_path) + + self.load('unicode') + assert 'success' in self.conf( + '"' + venv_path + '"', + '/config/applications/unicode/home', + ) + assert ( + self.get( + headers={ + 'Host': 'localhost', + 'Temp-dir': temp_dir, + 'Connection': 'close', + } + )['status'] + == 200 + ) + def test_python_application_threading(self): """wait_for_record() timeouts after 5s while every thread works at least 3s. So without releasing GIL test should fail. -- cgit From 5c9113ddac6eb42efac7f0c77b2f374853ba7d8c Mon Sep 17 00:00:00 2001 From: Andrew Clayton Date: Wed, 22 Feb 2023 16:04:53 +0000 Subject: Isolation: rootfs: Set the sticky bit on the tmp directory. When using the 'rootfs' isolation option, by default a tmpfs filesystem is mounted on tmp/. Currently this is mounted with a mode of 0777, i.e drwxrwxrwx. 3 root root 60 Feb 22 11:56 tmp however this should really have the sticky bit[0] set (as is per-normal for such directories) to prevent users from having free reign on the files contained within. What we really want is it mounted with a mode of 01777, i.e drwxrwxrwt. 3 root root 60 Feb 22 11:57 tmp [0]: To quote inode(7) "The sticky bit (S_ISVTX) on a directory means that a file in that directory can be renamed or deleted only by the owner of the file, by the owner of the directory, and by a privileged process." Reviewed-by: Liam Crilly Signed-off-by: Andrew Clayton --- src/nxt_isolation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nxt_isolation.c b/src/nxt_isolation.c index e43cf1f7..614d6bb5 100644 --- a/src/nxt_isolation.c +++ b/src/nxt_isolation.c @@ -652,7 +652,7 @@ nxt_isolation_set_lang_mounts(nxt_task_t *task, nxt_process_t *process, mnt->flags = (NXT_FS_FLAGS_NOSUID | NXT_FS_FLAGS_NODEV | NXT_FS_FLAGS_NOEXEC); - mnt->data = (u_char *) "size=1m,mode=777"; + mnt->data = (u_char *) "size=1m,mode=1777"; mnt->builtin = 1; mnt->deps = 0; -- cgit From 29471c8d32a640d6e2e460f65d5a319c60043733 Mon Sep 17 00:00:00 2001 From: Andrew Clayton Date: Thu, 23 Feb 2023 12:01:14 +0000 Subject: Set a safer umask(2) when running as a daemon. When running as a daemon. unit currently sets umask(0), i.e no umask. This is resulting in various directories being created with a mode of 0777, e.g rwxrwxrwx this is currently affecting cgroup and rootfs directories, which are being created with a mode of 0777, and when running as a daemon as there is no umask to restrict the permissions. This also affects the language modules (the umask is inherited over fork(2)) whereby unless something explicitly sets a umask, files and directories will be created with full permissions, 0666 (rw-rw-rw-)/ 0777 (rwxrwxrwx) respectively. This could be an unwitting security issue. My original idea was to just remove the umask(0) call and thus inherit the umask from the executing shell/program. However there was some concern about just inheriting whatever umask was in effect. Alex suggested that rather than simply removing the umask(0) call we change it to a value of 022 (which is a common default), which will result in directories and files with permissions at most of 0755 (rwxr-xr-x) & 0644 (rw-r--r--). If applications need some other umask set, they can (as they always have been able to) set their own umask(2). Suggested-by: Alejandro Colomar Reviewed-by: Liam Crilly Signed-off-by: Andrew Clayton --- src/nxt_process.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/nxt_process.c b/src/nxt_process.c index fe9349e8..025efe70 100644 --- a/src/nxt_process.c +++ b/src/nxt_process.c @@ -1156,10 +1156,10 @@ nxt_process_daemon(nxt_task_t *task) } /* - * Reset file mode creation mask: any access - * rights can be set on file creation. + * Set a sefe umask to give at most 755/644 permissions on + * directories/files. */ - umask(0); + umask(0022); /* Redirect STDIN and STDOUT to the "/dev/null". */ -- cgit From f4298180ebae2de1658684b0dc6604387b372a73 Mon Sep 17 00:00:00 2001 From: Konstantin Pavlov Date: Mon, 27 Feb 2023 15:45:04 -0800 Subject: contrib: updated njs to 0.7.10. --- pkg/contrib/src/njs/Makefile | 2 +- pkg/contrib/src/njs/SHA512SUMS | 2 +- pkg/contrib/src/njs/version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/contrib/src/njs/Makefile b/pkg/contrib/src/njs/Makefile index 54255aef..4e752df5 100644 --- a/pkg/contrib/src/njs/Makefile +++ b/pkg/contrib/src/njs/Makefile @@ -15,5 +15,5 @@ njs: njs-$(NJS_VERSION).tar.gz .sum-njs $(MOVE) .njs: njs - cd $< && ./configure && $(MAKE) libnjs + cd $< && ./configure --no-libxml2 && $(MAKE) libnjs touch $@ diff --git a/pkg/contrib/src/njs/SHA512SUMS b/pkg/contrib/src/njs/SHA512SUMS index 1bddec9b..0bba673b 100644 --- a/pkg/contrib/src/njs/SHA512SUMS +++ b/pkg/contrib/src/njs/SHA512SUMS @@ -1 +1 @@ -dc73029e7b570a7fbc94e90deb1e17c9a3d85072dc0e060f11dd96bd173e11b7c823c57115369d3c68af7acd97fabe619b70dfd73280694f8b5dc8b7929d850b njs-0.7.9.tar.gz +5063fcfac18298d86157d05dc618f47815763a2192538befa5f046d081a7d5c6b624b65258674a6d9719147c102a703d5c3a80d937f4e9d43985da8e85dbc539 njs-0.7.10.tar.gz diff --git a/pkg/contrib/src/njs/version b/pkg/contrib/src/njs/version index 511715d0..6088389d 100644 --- a/pkg/contrib/src/njs/version +++ b/pkg/contrib/src/njs/version @@ -1 +1 @@ -NJS_VERSION := 0.7.9 +NJS_VERSION := 0.7.10 -- cgit From ca9988171bbf65487f7fc2f2d6e8242eb83e66fc Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Tue, 28 Feb 2023 13:09:06 +0000 Subject: Added missing fixes in changes.xml. --- docs/changes.xml | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/docs/changes.xml b/docs/changes.xml index fe7b9fe2..8af9db14 100644 --- a/docs/changes.xml +++ b/docs/changes.xml @@ -25,12 +25,51 @@ NGINX Unit updated to 1.29.1. + + +stop creating world-writeable directories. + + + memory leak related to NJS. + + +path parsing in PHP applications. + + + + + +enabled UTF-8 for Python config by default to avoid applications failing +in some cases. + + + + + +using asyncio.get_running_loop() instead of asyncio.get_event_loop() +when it's available to prevent errors in some Python ASGI applications. + + + + + +applications that make use of various low level APIs such as pthreads could +fail to work correctly. + + + + + +websocket endianness detection for obscure operating systems. + + + -- cgit From 8295a0eb08908ebe09a70e0724f3dddd2a615ce3 Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Tue, 28 Feb 2023 16:01:54 +0000 Subject: Changes moved to the correct section. --- docs/changes.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/changes.xml b/docs/changes.xml index 8af9db14..9eb17c0b 100644 --- a/docs/changes.xml +++ b/docs/changes.xml @@ -25,6 +25,13 @@ NGINX Unit updated to 1.29.1. + + + + + stop creating world-writeable directories. @@ -73,13 +80,6 @@ websocket endianness detection for obscure operating systems. - - - - - @@ -29,7 +29,7 @@ NGINX Unit updated to 1.29.1. -- cgit From 0af1253c17161b19a5c61a0bbb262f6cd2e515ed Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Tue, 28 Feb 2023 14:52:32 +0000 Subject: Generated Dockerfiles for Unit 1.29.1. --- pkg/docker/Dockerfile.go1.19 | 2 +- pkg/docker/Dockerfile.jsc11 | 2 +- pkg/docker/Dockerfile.minimal | 2 +- pkg/docker/Dockerfile.node18 | 2 +- pkg/docker/Dockerfile.perl5.36 | 2 +- pkg/docker/Dockerfile.php8.1 | 2 +- pkg/docker/Dockerfile.python3.11 | 2 +- pkg/docker/Dockerfile.ruby3.1 | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pkg/docker/Dockerfile.go1.19 b/pkg/docker/Dockerfile.go1.19 index ec2b40da..a6ff837c 100644 --- a/pkg/docker/Dockerfile.go1.19 +++ b/pkg/docker/Dockerfile.go1.19 @@ -8,7 +8,7 @@ RUN set -ex \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && hg clone https://hg.nginx.org/unit \ && cd unit \ - && hg up 1.29.0 \ + && hg up 1.29.1 \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ diff --git a/pkg/docker/Dockerfile.jsc11 b/pkg/docker/Dockerfile.jsc11 index b8391997..501bfcda 100644 --- a/pkg/docker/Dockerfile.jsc11 +++ b/pkg/docker/Dockerfile.jsc11 @@ -8,7 +8,7 @@ RUN set -ex \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && hg clone https://hg.nginx.org/unit \ && cd unit \ - && hg up 1.29.0 \ + && hg up 1.29.1 \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ diff --git a/pkg/docker/Dockerfile.minimal b/pkg/docker/Dockerfile.minimal index ca3dec01..6101953e 100644 --- a/pkg/docker/Dockerfile.minimal +++ b/pkg/docker/Dockerfile.minimal @@ -8,7 +8,7 @@ RUN set -ex \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && hg clone https://hg.nginx.org/unit \ && cd unit \ - && hg up 1.29.0 \ + && hg up 1.29.1 \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ diff --git a/pkg/docker/Dockerfile.node18 b/pkg/docker/Dockerfile.node18 index bdf968b2..27543df1 100644 --- a/pkg/docker/Dockerfile.node18 +++ b/pkg/docker/Dockerfile.node18 @@ -8,7 +8,7 @@ RUN set -ex \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && hg clone https://hg.nginx.org/unit \ && cd unit \ - && hg up 1.29.0 \ + && hg up 1.29.1 \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ diff --git a/pkg/docker/Dockerfile.perl5.36 b/pkg/docker/Dockerfile.perl5.36 index 9c398c30..8f2b8a61 100644 --- a/pkg/docker/Dockerfile.perl5.36 +++ b/pkg/docker/Dockerfile.perl5.36 @@ -8,7 +8,7 @@ RUN set -ex \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && hg clone https://hg.nginx.org/unit \ && cd unit \ - && hg up 1.29.0 \ + && hg up 1.29.1 \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ diff --git a/pkg/docker/Dockerfile.php8.1 b/pkg/docker/Dockerfile.php8.1 index 76c7c428..eefc4aa8 100644 --- a/pkg/docker/Dockerfile.php8.1 +++ b/pkg/docker/Dockerfile.php8.1 @@ -8,7 +8,7 @@ RUN set -ex \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && hg clone https://hg.nginx.org/unit \ && cd unit \ - && hg up 1.29.0 \ + && hg up 1.29.1 \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ diff --git a/pkg/docker/Dockerfile.python3.11 b/pkg/docker/Dockerfile.python3.11 index 3a83ec57..744eda20 100644 --- a/pkg/docker/Dockerfile.python3.11 +++ b/pkg/docker/Dockerfile.python3.11 @@ -8,7 +8,7 @@ RUN set -ex \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && hg clone https://hg.nginx.org/unit \ && cd unit \ - && hg up 1.29.0 \ + && hg up 1.29.1 \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ diff --git a/pkg/docker/Dockerfile.ruby3.1 b/pkg/docker/Dockerfile.ruby3.1 index 1eb6ce5c..132b2b34 100644 --- a/pkg/docker/Dockerfile.ruby3.1 +++ b/pkg/docker/Dockerfile.ruby3.1 @@ -8,7 +8,7 @@ RUN set -ex \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && hg clone https://hg.nginx.org/unit \ && cd unit \ - && hg up 1.29.0 \ + && hg up 1.29.1 \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ && CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \ -- cgit From d5382aebb75e16c6d953f004d76c11037d999fcb Mon Sep 17 00:00:00 2001 From: Andrei Zeliankou Date: Tue, 28 Feb 2023 16:18:19 +0000 Subject: Unit 1.29.1 release. --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 79aeaf89..bf4ba812 100644 --- a/.hgtags +++ b/.hgtags @@ -36,3 +36,4 @@ f804aaf7eee10a7d8116820840d6312dd4914a41 1.21.0 1a08f884b24effa8b843d6aeeaf016b6354d1256 1.26.1 8a9055cbe4ffd450fac4d7a849c00e0db5485ad3 1.27.0 ea073fb3cb75abfb4be5dc12402de73e0c20da60 1.28.0 +fa0227b7f62691a186d752ace475868de49e9fce 1.29.1 -- cgit