diff --git a/SPECS/ntopng/CVE-2021-44964.patch b/SPECS/ntopng/CVE-2021-44964.patch new file mode 100644 index 00000000000..ec36c16f525 --- /dev/null +++ b/SPECS/ntopng/CVE-2021-44964.patch @@ -0,0 +1,394 @@ +From 0bfc572e51d9035a615ef6e9523f736c9ffa8e57 Mon Sep 17 00:00:00 2001 +From: Roberto Ierusalimschy +Date: Mon, 13 Dec 2021 10:41:17 -0300 +Subject: [PATCH] Bug: GC is not reentrant + +As the GC is not reentrant, finalizers should not be able to invoke it. + +Upstream patch reference: https://github.com/lua/lua/commit/0bfc572e51d9035a615ef6e9523f736c9ffa8e57.patch +--- + third-party/lua-5.4.3/src/lapi.c | 17 ++++----- + third-party/lua-5.4.3/src/lbaselib.c | 19 ++++++++-- + third-party/lua-5.4.3/src/ldebug.c | 54 +++++++++++++++++----------- + third-party/lua-5.4.3/src/lgc.c | 17 +++++---- + third-party/lua-5.4.3/src/lgc.h | 10 ++++++ + third-party/lua-5.4.3/src/llimits.h | 2 +- + third-party/lua-5.4.3/src/lstate.c | 4 +-- + third-party/lua-5.4.3/src/lstate.h | 4 +-- + 8 files changed, 84 insertions(+), 43 deletions(-) + +diff --git a/third-party/lua-5.4.3/src/lapi.c b/third-party/lua-5.4.3/src/lapi.c +index f8f70cd..b7e4711 100644 +--- a/third-party/lua-5.4.3/src/lapi.c ++++ b/third-party/lua-5.4.3/src/lapi.c +@@ -1126,18 +1126,19 @@ LUA_API int lua_status (lua_State *L) { + LUA_API int lua_gc (lua_State *L, int what, ...) { + va_list argp; + int res = 0; +- global_State *g; ++ global_State *g = G(L); ++ if (g->gcstp & GCSTPGC) /* internal stop? */ ++ return -1; /* all options are invalid when stopped */ + lua_lock(L); +- g = G(L); + va_start(argp, what); + switch (what) { + case LUA_GCSTOP: { +- g->gcrunning = 0; ++ g->gcstp = GCSTPUSR; /* stopped by the user */ + break; + } + case LUA_GCRESTART: { + luaE_setdebt(g, 0); +- g->gcrunning = 1; ++ g->gcstp = 0; /* (GCSTPGC must be already zero here) */ + break; + } + case LUA_GCCOLLECT: { +@@ -1156,8 +1157,8 @@ LUA_API int lua_gc (lua_State *L, int what, ...) { + case LUA_GCSTEP: { + int data = va_arg(argp, int); + l_mem debt = 1; /* =1 to signal that it did an actual step */ +- lu_byte oldrunning = g->gcrunning; +- g->gcrunning = 1; /* allow GC to run */ ++ lu_byte oldstp = g->gcstp; ++ g->gcstp = 0; /* allow GC to run (GCSTPGC must be zero here) */ + if (data == 0) { + luaE_setdebt(g, 0); /* do a basic step */ + luaC_step(L); +@@ -1167,7 +1168,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) { + luaE_setdebt(g, debt); + luaC_checkGC(L); + } +- g->gcrunning = oldrunning; /* restore previous state */ ++ g->gcstp = oldstp; /* restore previous state */ + if (debt > 0 && g->gcstate == GCSpause) /* end of cycle? */ + res = 1; /* signal it */ + break; +@@ -1185,7 +1186,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) { + break; + } + case LUA_GCISRUNNING: { +- res = g->gcrunning; ++ res = gcrunning(g); + break; + } + case LUA_GCGEN: { +diff --git a/third-party/lua-5.4.3/src/lbaselib.c b/third-party/lua-5.4.3/src/lbaselib.c +index 83ad306..82abd94 100644 +--- a/third-party/lua-5.4.3/src/lbaselib.c ++++ b/third-party/lua-5.4.3/src/lbaselib.c +@@ -182,12 +182,20 @@ static int luaB_rawset (lua_State *L) { + + + static int pushmode (lua_State *L, int oldmode) { +- lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental" +- : "generational"); ++ if (oldmode == -1) ++ luaL_pushfail(L); /* invalid call to 'lua_gc' */ ++ else ++ lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental" ++ : "generational"); + return 1; + } + + ++/* ++** check whether call to 'lua_gc' was valid (not inside a finalizer) ++*/ ++#define checkvalres(res) { if (res == -1) break; } ++ + static int luaB_collectgarbage (lua_State *L) { + static const char *const opts[] = {"stop", "restart", "collect", + "count", "step", "setpause", "setstepmul", +@@ -200,12 +208,14 @@ static int luaB_collectgarbage (lua_State *L) { + case LUA_GCCOUNT: { + int k = lua_gc(L, o); + int b = lua_gc(L, LUA_GCCOUNTB); ++ checkvalres(k); + lua_pushnumber(L, (lua_Number)k + ((lua_Number)b/1024)); + return 1; + } + case LUA_GCSTEP: { + int step = (int)luaL_optinteger(L, 2, 0); + int res = lua_gc(L, o, step); ++ checkvalres(res); + lua_pushboolean(L, res); + return 1; + } +@@ -213,11 +223,13 @@ static int luaB_collectgarbage (lua_State *L) { + case LUA_GCSETSTEPMUL: { + int p = (int)luaL_optinteger(L, 2, 0); + int previous = lua_gc(L, o, p); ++ checkvalres(previous); + lua_pushinteger(L, previous); + return 1; + } + case LUA_GCISRUNNING: { + int res = lua_gc(L, o); ++ checkvalres(res); + lua_pushboolean(L, res); + return 1; + } +@@ -234,10 +246,13 @@ static int luaB_collectgarbage (lua_State *L) { + } + default: { + int res = lua_gc(L, o); ++ checkvalres(res); + lua_pushinteger(L, res); + return 1; + } + } ++ luaL_pushfail(L); /* invalid call (inside a finalizer) */ ++ return 1; + } + + +diff --git a/third-party/lua-5.4.3/src/ldebug.c b/third-party/lua-5.4.3/src/ldebug.c +index 5524fae..43d77bb 100644 +--- a/third-party/lua-5.4.3/src/ldebug.c ++++ b/third-party/lua-5.4.3/src/ldebug.c +@@ -34,8 +34,8 @@ + #define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL) + + +-static const char *funcnamefromcode (lua_State *L, CallInfo *ci, +- const char **name); ++static const char *funcnamefromcall (lua_State *L, CallInfo *ci, ++ const char **name); + + + static int currentpc (CallInfo *ci) { +@@ -310,15 +310,9 @@ static void collectvalidlines (lua_State *L, Closure *f) { + + + static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { +- if (ci == NULL) /* no 'ci'? */ +- return NULL; /* no info */ +- else if (ci->callstatus & CIST_FIN) { /* is this a finalizer? */ +- *name = "__gc"; +- return "metamethod"; /* report it as such */ +- } +- /* calling function is a known Lua function? */ +- else if (!(ci->callstatus & CIST_TAIL) && isLua(ci->previous)) +- return funcnamefromcode(L, ci->previous, name); ++ /* calling function is a known function? */ ++ if (ci != NULL && !(ci->callstatus & CIST_TAIL)) ++ return funcnamefromcall(L, ci->previous, name); + else return NULL; /* no way to find a name */ + } + +@@ -590,16 +584,10 @@ static const char *getobjname (const Proto *p, int lastpc, int reg, + ** Returns what the name is (e.g., "for iterator", "method", + ** "metamethod") and sets '*name' to point to the name. + */ +-static const char *funcnamefromcode (lua_State *L, CallInfo *ci, +- const char **name) { ++static const char *funcnamefromcode (lua_State *L, const Proto *p, ++ int pc, const char **name) { + TMS tm = (TMS)0; /* (initial value avoids warnings) */ +- const Proto *p = ci_func(ci)->p; /* calling function */ +- int pc = currentpc(ci); /* calling instruction index */ + Instruction i = p->code[pc]; /* calling instruction */ +- if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */ +- *name = "?"; +- return "hook"; +- } + switch (GET_OPCODE(i)) { + case OP_CALL: + case OP_TAILCALL: +@@ -636,6 +624,26 @@ static const char *funcnamefromcode (lua_State *L, CallInfo *ci, + return "metamethod"; + } + ++ ++/* ++** Try to find a name for a function based on how it was called. ++*/ ++static const char *funcnamefromcall (lua_State *L, CallInfo *ci, ++ const char **name) { ++ if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */ ++ *name = "?"; ++ return "hook"; ++ } ++ else if (ci->callstatus & CIST_FIN) { /* was it called as a finalizer? */ ++ *name = "__gc"; ++ return "metamethod"; /* report it as such */ ++ } ++ else if (isLua(ci)) ++ return funcnamefromcode(L, ci_func(ci)->p, currentpc(ci), name); ++ else ++ return NULL; ++} ++ + /* }====================================================== */ + + +@@ -694,11 +702,15 @@ l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) { + luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o)); + } + +- ++/* ++** Raise an error for calling a non-callable object. Try to find a name ++** for the object based on how it was called ('funcnamefromcall'); if it ++** cannot get a name there, try 'varinfo'. ++*/ + l_noret luaG_callerror (lua_State *L, const TValue *o) { + CallInfo *ci = L->ci; + const char *name = NULL; /* to avoid warnings */ +- const char *what = (isLua(ci)) ? funcnamefromcode(L, ci, &name) : NULL; ++ const char *what = funcnamefromcall(L, ci, &name); + if (what != NULL) { + const char *t = luaT_objtypename(L, o); + luaG_runerror(L, "%s '%s' is not callable (a %s value)", what, name, t); +diff --git a/third-party/lua-5.4.3/src/lgc.c b/third-party/lua-5.4.3/src/lgc.c +index b360eed..42a73d8 100644 +--- a/third-party/lua-5.4.3/src/lgc.c ++++ b/third-party/lua-5.4.3/src/lgc.c +@@ -906,18 +906,18 @@ static void GCTM (lua_State *L) { + if (!notm(tm)) { /* is there a finalizer? */ + int status; + lu_byte oldah = L->allowhook; +- int running = g->gcrunning; ++ int oldgcstp = g->gcstp; ++ g->gcstp |= GCSTPGC; /* avoid GC steps */ + L->allowhook = 0; /* stop debug hooks during GC metamethod */ +- g->gcrunning = 0; /* avoid GC steps */ + setobj2s(L, L->top++, tm); /* push finalizer... */ + setobj2s(L, L->top++, &v); /* ... and its argument */ + L->ci->callstatus |= CIST_FIN; /* will run a finalizer */ + status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0); + L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */ + L->allowhook = oldah; /* restore hooks */ +- g->gcrunning = running; /* restore state */ ++ g->gcstp = oldgcstp; /* restore state */ + if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */ +- luaE_warnerror(L, "__gc metamethod"); ++ luaE_warnerror(L, "__gc"); + L->top--; /* pops error object */ + } + } +@@ -1011,7 +1011,8 @@ static void correctpointers (global_State *g, GCObject *o) { + void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { + global_State *g = G(L); + if (tofinalize(o) || /* obj. is already marked... */ +- gfasttm(g, mt, TM_GC) == NULL) /* or has no finalizer? */ ++ gfasttm(g, mt, TM_GC) == NULL || /* or has no finalizer... */ ++ (g->gcstp & GCSTPCLS)) /* or closing state? */ + return; /* nothing to be done */ + else { /* move 'o' to 'finobj' list */ + GCObject **p; +@@ -1502,12 +1503,13 @@ static void deletelist (lua_State *L, GCObject *p, GCObject *limit) { + */ + void luaC_freeallobjects (lua_State *L) { + global_State *g = G(L); ++ g->gcstp = GCSTPCLS; /* no extra finalizers after here */ + luaC_changemode(L, KGC_INC); + separatetobefnz(g, 1); /* separate all objects with finalizers */ + lua_assert(g->finobj == NULL); + callallpendingfinalizers(L); + deletelist(L, g->allgc, obj2gco(g->mainthread)); +- deletelist(L, g->finobj, NULL); ++ lua_assert(g->finobj == NULL); /* no new finalizers */ + deletelist(L, g->fixedgc, NULL); /* collect fixed objects */ + lua_assert(g->strt.nuse == 0); + } +@@ -1647,6 +1649,7 @@ void luaC_runtilstate (lua_State *L, int statesmask) { + } + + ++ + /* + ** Performs a basic incremental step. The debt and step size are + ** converted from bytes to "units of work"; then the function loops +@@ -1678,7 +1681,7 @@ static void incstep (lua_State *L, global_State *g) { + void luaC_step (lua_State *L) { + global_State *g = G(L); + lua_assert(!g->gcemergency); +- if (g->gcrunning) { /* running? */ ++ if (gcrunning(g)) { /* running? */ + if(isdecGCmodegen(g)) + genstep(L, g); + else +diff --git a/third-party/lua-5.4.3/src/lgc.h b/third-party/lua-5.4.3/src/lgc.h +index 073e2a4..4a12563 100644 +--- a/third-party/lua-5.4.3/src/lgc.h ++++ b/third-party/lua-5.4.3/src/lgc.h +@@ -148,6 +148,16 @@ + */ + #define isdecGCmodegen(g) (g->gckind == KGC_GEN || g->lastatomic != 0) + ++ ++/* ++** Control when GC is running: ++*/ ++#define GCSTPUSR 1 /* bit true when GC stopped by user */ ++#define GCSTPGC 2 /* bit true when GC stopped by itself */ ++#define GCSTPCLS 4 /* bit true when closing Lua state */ ++#define gcrunning(g) ((g)->gcstp == 0) ++ ++ + /* + ** Does one step of collection when debt becomes positive. 'pre'/'pos' + ** allows some adjustments to be done only when needed. macro +diff --git a/third-party/lua-5.4.3/src/llimits.h b/third-party/lua-5.4.3/src/llimits.h +index 025f1c8..9a68a66 100644 +--- a/third-party/lua-5.4.3/src/llimits.h ++++ b/third-party/lua-5.4.3/src/llimits.h +@@ -347,7 +347,7 @@ typedef l_uint32 Instruction; + #define condchangemem(L,pre,pos) ((void)0) + #else + #define condchangemem(L,pre,pos) \ +- { if (G(L)->gcrunning) { pre; luaC_fullgc(L, 0); pos; } } ++ { if (gcrunning(G(L))) { pre; luaC_fullgc(L, 0); pos; } } + #endif + + #endif +diff --git a/third-party/lua-5.4.3/src/lstate.c b/third-party/lua-5.4.3/src/lstate.c +index 38da773..59b4f21 100644 +--- a/third-party/lua-5.4.3/src/lstate.c ++++ b/third-party/lua-5.4.3/src/lstate.c +@@ -236,7 +236,7 @@ static void f_luaopen (lua_State *L, void *ud) { + luaS_init(L); + luaT_init(L); + luaX_init(L); +- g->gcrunning = 1; /* allow gc */ ++ g->gcstp = 0; /* allow gc */ + setnilvalue(&g->nilvalue); /* now state is complete */ + luai_userstateopen(L); + } +@@ -373,7 +373,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { + g->ud_warn = NULL; + g->mainthread = L; + g->seed = luai_makeseed(L); +- g->gcrunning = 0; /* no GC while building state */ ++ g->gcstp = GCSTPGC; /* no GC while building state */ + g->strt.size = g->strt.nuse = 0; + g->strt.hash = NULL; + setnilvalue(&g->l_registry); +diff --git a/third-party/lua-5.4.3/src/lstate.h b/third-party/lua-5.4.3/src/lstate.h +index c1283bb..11f27fd 100644 +--- a/third-party/lua-5.4.3/src/lstate.h ++++ b/third-party/lua-5.4.3/src/lstate.h +@@ -209,7 +209,7 @@ typedef struct CallInfo { + #define CIST_YPCALL (1<<4) /* doing a yieldable protected call */ + #define CIST_TAIL (1<<5) /* call was tail called */ + #define CIST_HOOKYIELD (1<<6) /* last hook called yielded */ +-#define CIST_FIN (1<<7) /* call is running a finalizer */ ++#define CIST_FIN (1<<7) /* function "called" a finalizer */ + #define CIST_TRAN (1<<8) /* 'ci' has transfer information */ + #define CIST_CLSRET (1<<9) /* function is closing tbc variables */ + /* Bits 10-12 are used for CIST_RECST (see below) */ +@@ -263,7 +263,7 @@ typedef struct global_State { + lu_byte gcstopem; /* stops emergency collections */ + lu_byte genminormul; /* control for minor generational collections */ + lu_byte genmajormul; /* control for major generational collections */ +- lu_byte gcrunning; /* true if GC is running */ ++ lu_byte gcstp; /* control whether GC is running */ + lu_byte gcemergency; /* true if this is an emergency collection */ + lu_byte gcpause; /* size of pause between successive GCs */ + lu_byte gcstepmul; /* GC "speed" */ +-- +2.45.4 + diff --git a/SPECS/ntopng/ntopng.spec b/SPECS/ntopng/ntopng.spec index 1124941ce5d..533a67f89d9 100644 --- a/SPECS/ntopng/ntopng.spec +++ b/SPECS/ntopng/ntopng.spec @@ -2,7 +2,7 @@ Summary: Web-based Network Traffic Monitoring Application Name: ntopng Version: 5.2.1 -Release: 5%{?dist} +Release: 6%{?dist} License: GPLv3 Vendor: Microsoft Corporation Distribution: Azure Linux @@ -18,6 +18,7 @@ Patch3: CVE-2017-18214.patch Patch4: CVE-2022-33099.patch Patch5: CVE-2021-44647.patch Patch6: CVE-2021-43519.patch +Patch7: CVE-2021-44964.patch BuildRequires: curl-devel BuildRequires: gcc BuildRequires: glib-devel @@ -67,6 +68,9 @@ mv nDPI-%{nDPIver} nDPI %{_datadir}/ntopng/* %changelog +* Fri Dec 26 2025 Jyoti Kanase - 5.2.1-6 +- Patch to fix CVE-2021-44964 + * Thu Feb 06 2025 Jyoti Kanase - 5.2.1-5 - Patch to fix CVE-2021-44647 and CVE-2021-43519.