Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package falco-libs for openSUSE:Factory checked in at 2026-10-17 21:27:00 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/falco-libs (Old) and /work/SRC/openSUSE:Factory/.falco-libs.new.3698736 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "falco-libs" Sat Oct 17 21:27:00 2026 rev:4 rq:1385350 version:0.26.1 Changes: -------- --- /work/SRC/openSUSE:Factory/falco-libs/falco-libs.changes 2026-09-16 17:44:56.769540768 +0200 +++ /work/SRC/openSUSE:Factory/.falco-libs.new.3698736/falco-libs.changes 2026-10-17 21:27:05.012088454 +0200 @@ -1,0 +2,15 @@ +Sat Oct 17 06:15:34 UTC 2026 - Martin Pluskal <[email protected]> + +- Update to 0.26.1: + * libsinsp: report real event deltatime values in JSON output; + proc.ppid.duration now returns NULL when ancestor data + is missing + * libscap: clear fd records before savefile parsing + * Driver API 11.0.1 with modern-BPF fixes (no d_path on remote + task paths, BPF_CORE siginfo read); minimum accepted driver + unchanged (API 11.0.0, schema 4.3.0) + * Default container plugin upgraded to 0.7.5 + * Keep support-bshoshany-thread-pool-v5.patch (still applies + cleanly, upstream keeps the v4-only spelling) + +------------------------------------------------------------------- Old: ---- falco-libs-0.26.0.tar.gz New: ---- falco-libs-0.26.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ falco-libs.spec ++++++ --- /var/tmp/diff_new_pack.hEnyzS/_old 2026-10-17 21:27:05.777120373 +0200 +++ /var/tmp/diff_new_pack.hEnyzS/_new 2026-10-17 21:27:05.779120456 +0200 @@ -21,7 +21,7 @@ # Library Policy: libscap0_26, libsinsp0_26. %define sover 0_26 Name: falco-libs -Version: 0.26.0 +Version: 0.26.1 Release: 0 Summary: Libraries for system inspection (libscap and libsinsp) License: Apache-2.0 ++++++ falco-libs-0.26.0.tar.gz -> falco-libs-0.26.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libs-0.26.0/.github/workflows/release-body.yml new/libs-0.26.1/.github/workflows/release-body.yml --- old/libs-0.26.0/.github/workflows/release-body.yml 2026-09-12 15:05:17.000000000 +0200 +++ new/libs-0.26.1/.github/workflows/release-body.yml 2026-10-14 09:51:41.000000000 +0200 @@ -74,6 +74,7 @@ if: ${{ needs.release-settings.outputs.is_latest_libs == 'true' }} # Only for latest libs releases. permissions: contents: write + pull-requests: read # rn2md lists the merged PRs runs-on: ubuntu-24.04 steps: - name: Clone repo @@ -103,7 +104,7 @@ echo "" >> release-body.md - name: Generate release notes - uses: leodido/rn2md@9c351d81278644c0e17b1ca68edbdba305276c73 + uses: ekoops/rn2md@a30974f3c228cbca9409a3bb5b6eb17a2eeb9f71 # leodido/rn2md#15, until it is merged upstream with: milestone: ${{ github.event.release.tag_name }} output: ./notes.md @@ -136,6 +137,7 @@ if: ${{ needs.release-settings.outputs.is_latest_drivers == 'true' }} # Only for latest drivers releases. permissions: contents: write + pull-requests: read # rn2md lists the merged PRs runs-on: ubuntu-24.04 steps: - name: Clone libs repo @@ -208,7 +210,7 @@ cat matrix_X64.md matrix_ARM64.md >> release-body.md - name: Generate release notes - uses: leodido/rn2md@9c351d81278644c0e17b1ca68edbdba305276c73 # main + uses: ekoops/rn2md@a30974f3c228cbca9409a3bb5b6eb17a2eeb9f71 # leodido/rn2md#15, until it is merged upstream with: milestone: ${{ github.event.release.tag_name }} output: ./notes.md diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libs-0.26.0/cmake/modules/container_plugin.cmake new/libs-0.26.1/cmake/modules/container_plugin.cmake --- old/libs-0.26.0/cmake/modules/container_plugin.cmake 2026-09-12 15:05:17.000000000 +0200 +++ new/libs-0.26.1/cmake/modules/container_plugin.cmake 2026-10-14 09:51:41.000000000 +0200 @@ -22,13 +22,13 @@ ) if(NOT CONTAINER_VERSION) - set(CONTAINER_VERSION "0.7.4") + set(CONTAINER_VERSION "0.7.5") endif() if(NOT CONTAINER_HASH) if(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "x86_64") - set(CONTAINER_HASH "0cdb98cbad263862c5513f559d94a9c016a0d732f3551e10a67e00344fef34a0") + set(CONTAINER_HASH "ac29cbb16aa3c9bbb290e6533aef9a9a39943ffa1be6e1a2ed8ff1c3780b5d9b") else() # arm64 - set(CONTAINER_HASH "d149f30b0756140030ffc37879a5dfedf350329d92b95d7654d4ec7a7f71b169") + set(CONTAINER_HASH "907a54f1bdbad59cbc137859c66be1f315c3556ecf42b012592fb6b5818b0374") endif() endif() if(NOT TARGET container_plugin) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libs-0.26.0/driver/API_VERSION new/libs-0.26.1/driver/API_VERSION --- old/libs-0.26.0/driver/API_VERSION 2026-09-12 15:05:17.000000000 +0200 +++ new/libs-0.26.1/driver/API_VERSION 2026-10-14 09:51:41.000000000 +0200 @@ -1 +1 @@ -11.0.0 +11.0.1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libs-0.26.0/driver/modern_bpf/programs/attached/events/signal_deliver.bpf.c new/libs-0.26.1/driver/modern_bpf/programs/attached/events/signal_deliver.bpf.c --- old/libs-0.26.0/driver/modern_bpf/programs/attached/events/signal_deliver.bpf.c 2026-09-12 15:05:17.000000000 +0200 +++ new/libs-0.26.1/driver/modern_bpf/programs/attached/events/signal_deliver.bpf.c 2026-10-14 09:51:41.000000000 +0200 @@ -30,10 +30,15 @@ /* Try to find the source pid */ pid_t spid = 0; + /* Signal tracepoints can receive the `SEND_SIG_NOINFO` (0) and + * `SEND_SIG_PRIV` (1) sentinels instead of a real pointer, so newer kernels + * expose `info` as a scalar and the verifier rejects direct accesses. + * `BPF_CORE_READ` works with both the scalar and the BTF pointer. + */ if(info != NULL) { switch(sig) { case SIGKILL: - spid = info->_sifields._kill._pid; + spid = BPF_CORE_READ(info, _sifields._kill._pid); break; case SIGTERM: @@ -41,18 +46,18 @@ case SIGINT: case SIGTSTP: case SIGQUIT: { - int si_code = info->si_code; + int si_code = BPF_CORE_READ(info, si_code); if(si_code == SI_USER || si_code == SI_QUEUE || si_code <= 0) { /* This is equivalent to `info->si_pid` where * `si_pid` is a macro `_sifields._kill._pid` */ - spid = info->_sifields._kill._pid; + spid = BPF_CORE_READ(info, _sifields._kill._pid); } break; } case SIGCHLD: - spid = info->_sifields._sigchld._pid; + spid = BPF_CORE_READ(info, _sifields._sigchld._pid); break; default: @@ -61,7 +66,7 @@ } if(sig >= SIGRTMIN && sig <= SIGRTMAX) { - spid = info->_sifields._rt._pid; + spid = BPF_CORE_READ(info, _sifields._rt._pid); } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libs-0.26.0/driver/modern_bpf/programs/attached/iterators/task.bpf.c new/libs-0.26.1/driver/modern_bpf/programs/attached/iterators/task.bpf.c --- old/libs-0.26.0/driver/modern_bpf/programs/attached/iterators/task.bpf.c 2026-09-12 15:05:17.000000000 +0200 +++ new/libs-0.26.1/driver/modern_bpf/programs/attached/iterators/task.bpf.c 2026-10-14 09:51:41.000000000 +0200 @@ -65,7 +65,8 @@ task); /* Parameter 7: exepath (type: PT_FSPATH) */ - auxmap__store_task_exe_file_path_sleepable(auxmap, task); + /* An RCU read-side critical section does not pin remote task path objects. */ + auxmap__store_task_exe_file_path(auxmap, task); /* Parameter 8: flags (type: PT_FLAGS32) */ uint32_t flags = 0; @@ -96,7 +97,7 @@ task); /* Parameter 10: cwd (type: PT_CHARBUF) */ - auxmap__store_task_cwd_sleepable(auxmap, task); + auxmap__store_task_cwd(auxmap, task); /* Parameter 11: fdlimit (type: PT_UINT64) */ unsigned long fdlimit = extract__fdlimit(task); @@ -180,7 +181,7 @@ auxmap__store_cgroups_param(auxmap, task); /* Parameter 29: root (type: PT_FSPATH) */ - auxmap__store_task_root_sleepable(auxmap, task); + auxmap__store_task_root(auxmap, task); // filterd_out and fdlist in scap_threadinfo are internal fields, not relevant in this context. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libs-0.26.0/test/libscap/test_suites/engines/savefile/fdlist_initialization.cpp new/libs-0.26.1/test/libscap/test_suites/engines/savefile/fdlist_initialization.cpp --- old/libs-0.26.0/test/libscap/test_suites/engines/savefile/fdlist_initialization.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/libs-0.26.1/test/libscap/test_suites/engines/savefile/fdlist_initialization.cpp 2026-10-14 09:51:41.000000000 +0200 @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: Apache-2.0 +/* Copyright (C) 2026 The Falco Authors. */ + +#include <gtest/gtest.h> +#include <libscap/scap.h> +#include <libscap/scap_engines.h> +#include <libscap/scap_procs.h> +#include <libscap/scap_platform.h> +#include <libscap/scap_savefile.h> +#include <libscap/engine/savefile/savefile_public.h> + +#include <cstdint> +#include <string> +#include <vector> +#include <unistd.h> + +namespace { +template<typename T> +void append(std::vector<uint8_t>& buf, T value) { + const auto* p = reinterpret_cast<const uint8_t*>(&value); + buf.insert(buf.end(), p, p + sizeof(T)); +} + +std::vector<uint8_t> section_header() { + std::vector<uint8_t> body; + append<uint32_t>(body, SHB_MAGIC); + append<uint16_t>(body, CURRENT_MAJOR_VERSION); + append<uint16_t>(body, CURRENT_MINOR_VERSION); + append<uint64_t>(body, UINT64_MAX); + const uint32_t total = sizeof(block_header) + body.size() + sizeof(uint32_t); + std::vector<uint8_t> out; + append<uint32_t>(out, SHB_BLOCK_TYPE); + append<uint32_t>(out, total); + out.insert(out.end(), body.begin(), body.end()); + append<uint32_t>(out, total); + return out; +} + +void append_fname(std::vector<uint8_t>& record, const std::string& name) { + append<uint16_t>(record, static_cast<uint16_t>(name.size())); + record.insert(record.end(), name.begin(), name.end()); +} + +std::vector<uint8_t> unix_record() { + std::vector<uint8_t> payload; + append<int64_t>(payload, 3); + append<uint64_t>(payload, 10); + append<uint8_t>(payload, SCAP_FD_UNIX_SOCK); + append<uint64_t>(payload, 1); + append<uint64_t>(payload, 2); + // Fill the whole union, including the bytes that map to regularinfo.mount_id/dev. + append_fname(payload, std::string(SCAP_MAX_PATH_SIZE - 1, static_cast<char>(0x5a))); + std::vector<uint8_t> record; + append<uint32_t>(record, static_cast<uint32_t>(payload.size() + sizeof(uint32_t))); + record.insert(record.end(), payload.begin(), payload.end()); + return record; +} + +std::vector<uint8_t> short_file_v2_record() { + std::vector<uint8_t> payload; + append<int64_t>(payload, 4); + append<uint64_t>(payload, 11); + append<uint8_t>(payload, SCAP_FD_FILE_V2); + append<uint32_t>(payload, 0); + append_fname(payload, "x"); + // Old captures may end here, before dev; mount_id is never serialized. + std::vector<uint8_t> record; + append<uint32_t>(record, static_cast<uint32_t>(payload.size() + sizeof(uint32_t))); + record.insert(record.end(), payload.begin(), payload.end()); + return record; +} + +std::vector<uint8_t> fdlist_block() { + std::vector<uint8_t> body; + append<uint64_t>(body, 123); + for(const auto& record : {unix_record(), short_file_v2_record()}) { + body.insert(body.end(), record.begin(), record.end()); + } + while((sizeof(block_header) + body.size() + sizeof(uint32_t)) % 4 != 0) { + body.push_back(0); + } + const uint32_t total = sizeof(block_header) + body.size() + sizeof(uint32_t); + std::vector<uint8_t> out; + append<uint32_t>(out, FDL_BLOCK_TYPE_V2); + append<uint32_t>(out, total); + out.insert(out.end(), body.begin(), body.end()); + append<uint32_t>(out, total); + return out; +} + +std::vector<uint8_t> event_block() { + std::vector<uint8_t> body; + append<uint16_t>(body, 0); + append<uint64_t>(body, 1); + append<uint64_t>(body, 123); + append<uint32_t>(body, 26); + append<uint16_t>(body, PPME_GENERIC_E); + append<uint32_t>(body, 0); + while((sizeof(block_header) + body.size() + sizeof(uint32_t)) % 4 != 0) + body.push_back(0); + const uint32_t total = sizeof(block_header) + body.size() + sizeof(uint32_t); + std::vector<uint8_t> out; + append<uint32_t>(out, EV_BLOCK_TYPE_V2); + append<uint32_t>(out, total); + out.insert(out.end(), body.begin(), body.end()); + append<uint32_t>(out, total); + return out; +} + +int32_t collect_fds(void* context, + char*, + int64_t, + scap_threadinfo*, + scap_fdinfo* fdinfo, + scap_threadinfo**) { + if(fdinfo != nullptr) + static_cast<std::vector<scap_fdinfo>*>(context)->push_back(*fdinfo); + return SCAP_SUCCESS; +} +} // namespace + +TEST(savefile_fdlist, clears_missing_fields_between_records) { + auto capture = section_header(); + for(const auto& block : {fdlist_block(), event_block()}) + capture.insert(capture.end(), block.begin(), block.end()); + char path[] = "/tmp/scap_fd_init_XXXXXX"; + const int fd = mkstemp(path); + ASSERT_GE(fd, 0); + ASSERT_EQ(write(fd, capture.data(), capture.size()), static_cast<ssize_t>(capture.size())); + close(fd); + + std::vector<scap_fdinfo> fds; + scap_proc_callbacks callbacks{}; + callbacks.m_refresh_start_cb = default_refresh_start_end_callback; + callbacks.m_refresh_end_cb = default_refresh_start_end_callback; + callbacks.m_proc_entry_cb = collect_fds; + callbacks.m_callback_context = &fds; + scap_savefile_engine_params params{}; + params.fname = path; + params.platform = scap_savefile_alloc_platform(callbacks); + scap_open_args args{}; + args.engine_params = ¶ms; + char error[SCAP_LASTERR_SIZE] = {}; + int32_t rc = SCAP_FAILURE; + scap_t* h = scap_open(&args, &scap_savefile_engine, error, &rc); + ASSERT_NE(h, nullptr) << error; + ASSERT_EQ(fds.size(), 2u); + EXPECT_EQ(fds[1].type, SCAP_FD_FILE_V2); + EXPECT_EQ(fds[1].info.regularinfo.mount_id, 0u); + EXPECT_EQ(fds[1].info.regularinfo.dev, 0u); + scap_close(h); + scap_platform_close(params.platform); + scap_platform_free(params.platform); + remove(path); +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libs-0.26.0/userspace/libscap/engine/savefile/scap_savefile.c new/libs-0.26.1/userspace/libscap/engine/savefile/scap_savefile.c --- old/libs-0.26.0/userspace/libscap/engine/savefile/scap_savefile.c 2026-09-12 15:05:17.000000000 +0200 +++ new/libs-0.26.1/userspace/libscap/engine/savefile/scap_savefile.c 2026-10-14 09:51:41.000000000 +0200 @@ -1602,6 +1602,7 @@ totreadsize += readsize; while(((int32_t)block_length - (int32_t)totreadsize) >= 4) { + memset(&fdi, 0, sizeof(fdi)); if(scap_fd_read_from_disk(&fdi, &readsize, block_type, r, error) != SCAP_SUCCESS) { return SCAP_FAILURE; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libs-0.26.0/userspace/libsinsp/eventformatter.cpp new/libs-0.26.1/userspace/libsinsp/eventformatter.cpp --- old/libs-0.26.0/userspace/libsinsp/eventformatter.cpp 2026-09-12 15:05:17.000000000 +0200 +++ new/libs-0.26.1/userspace/libsinsp/eventformatter.cpp 2026-10-14 09:51:41.000000000 +0200 @@ -234,8 +234,8 @@ retval = false; break; } - // Keep the second extraction: some fields update state on each call. - m_root[t.name] = t.token->tojson(evt); + // One extraction per field: some fields update state on each call. + m_root[t.name] = json_value; sanitize_json_strings(m_root[t.name]); } output = m_writer.write(m_root); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libs-0.26.0/userspace/libsinsp/eventformatter.h new/libs-0.26.1/userspace/libsinsp/eventformatter.h --- old/libs-0.26.0/userspace/libsinsp/eventformatter.h 2026-09-12 15:05:17.000000000 +0200 +++ new/libs-0.26.1/userspace/libsinsp/eventformatter.h 2026-10-14 09:51:41.000000000 +0200 @@ -175,7 +175,7 @@ virtual void visit(const libsinsp::filter::ast::field_transformer_expr *) override; std::string m_last_field_name; - bool m_is_last_transformer; + bool m_is_last_transformer{false}; std::shared_ptr<sinsp_filter_factory> m_factory; std::vector<resolution_token> &m_resolution_tokens; }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libs-0.26.0/userspace/libsinsp/sinsp_filtercheck_thread.cpp new/libs-0.26.1/userspace/libsinsp/sinsp_filtercheck_thread.cpp --- old/libs-0.26.0/userspace/libsinsp/sinsp_filtercheck_thread.cpp 2026-09-12 15:05:17.000000000 +0200 +++ new/libs-0.26.1/userspace/libsinsp/sinsp_filtercheck_thread.cpp 2026-10-14 09:51:41.000000000 +0200 @@ -1538,6 +1538,7 @@ ASSERT(m_val.s64 > 0); return extract_single_val(m_val.s64, len); } + return NULL; } case TYPE_FDOPENCOUNT: m_val.u64 = tinfo->get_fd_opencount(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libs-0.26.0/userspace/libsinsp/test/eventformatter.ut.cpp new/libs-0.26.1/userspace/libsinsp/test/eventformatter.ut.cpp --- old/libs-0.26.0/userspace/libsinsp/test/eventformatter.ut.cpp 2026-09-12 15:05:17.000000000 +0200 +++ new/libs-0.26.1/userspace/libsinsp/test/eventformatter.ut.cpp 2026-10-14 09:51:41.000000000 +0200 @@ -202,14 +202,26 @@ EXPECT_TRUE(json["evt.asynctype"].isNull()); } -TEST_F(sinsp_formatter_test, json_preserves_deltatime_behavior) { +TEST_F(sinsp_formatter_test, json_deltatime_reports_event_gaps) { sinsp_evt_formatter formatter(&m_inspector, "%evt.deltatime %evt.deltatime.s %evt.deltatime.ns", m_filter_list); + // The gaps differ on purpose: a value left over from the previous event cannot pass. + struct test_case { + uint64_t offset; + int64_t deltatime; + int64_t deltatime_s; + int64_t deltatime_ns; + }; + const std::vector<test_case> cases = { + {0ULL, 0, 0, 0}, + {1000000000ULL, 1000000000, 1, 0}, + {2500000000ULL, 1500000000, 1, 500000000}, + }; const uint64_t first_ts = increasing_ts(); - for(uint64_t offset : {0ULL, 1000000042ULL, 2000000084ULL}) { - SCOPED_TRACE(offset); - auto evt = add_event_advance_ts(first_ts + offset, + for(const auto& test : cases) { + SCOPED_TRACE(test.offset); + auto evt = add_event_advance_ts(first_ts + test.offset, INIT_TID, PPME_SYSCALL_GETCWD_X, 2, @@ -217,8 +229,12 @@ "/test/dir"); std::string output; ASSERT_TRUE(formatter.tostring_withformat(evt, output, sinsp_evt_formatter::OF_JSON)); - // Preserve the existing second extraction, which observes the same timestamp and returns 0. - EXPECT_EQ(output, "{\"evt.deltatime\":0,\"evt.deltatime.ns\":0,\"evt.deltatime.s\":0}"); + Json::Value json; + Json::Reader reader; + ASSERT_TRUE(reader.parse(output, json)) << output; + EXPECT_EQ(json["evt.deltatime"].asInt64(), test.deltatime); + EXPECT_EQ(json["evt.deltatime.s"].asInt64(), test.deltatime_s); + EXPECT_EQ(json["evt.deltatime.ns"].asInt64(), test.deltatime_ns); } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libs-0.26.0/userspace/libsinsp/test/filterchecks/proc.cpp new/libs-0.26.1/userspace/libsinsp/test/filterchecks/proc.cpp --- old/libs-0.26.0/userspace/libsinsp/test/filterchecks/proc.cpp 2026-09-12 15:05:17.000000000 +0200 +++ new/libs-0.26.1/userspace/libsinsp/test/filterchecks/proc.cpp 2026-10-14 09:51:41.000000000 +0200 @@ -305,3 +305,23 @@ ASSERT_EQ(get_field_as_string(evt, "proc.stderr.name"), tuple_str); } #endif + +TEST_F(sinsp_with_test_input, PROC_FILTER_ppid_duration) { + DEFAULT_TREE + + /* p3_t1 is a process cloned from p2_t1, so its ancestor process has a clone time and the + * field has a value. */ + auto evt = generate_random_event(p3_t1_tid); + ASSERT_TRUE(field_has_value(evt, "proc.ppid.duration")); + + /* A thread info that was neither created from a clone event nor read from /proc keeps a zero + * clone time. The ancestor has no known age then, so the field must have no value. It must + * not fall through to proc.fdopencount and report the open descriptor count of the current + * thread as a duration. */ + auto ptinfo = m_inspector.m_thread_manager->find_thread(p2_t1_tid, true).get(); + ASSERT_TRUE(ptinfo); + ptinfo->m_clone_ts = 0; + + evt = generate_random_event(p3_t1_tid); + ASSERT_FALSE(field_has_value(evt, "proc.ppid.duration")); +}
