Compare commits

...

94 Commits

Author SHA1 Message Date
Luca Guerra b7eb0dd652 fix(libsinsp): check param num on connect/open/openat parsing
Signed-off-by: Luca Guerra <luca@guerra.sh>
2022-03-04 09:01:02 +01:00
Federico Di Pierro 2bc27c049c fix(userspace/libsinsp): fixed podman as user detection.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2022-03-03 16:09:20 +01:00
Luca Guerra 7e7a5129b6 new(libsinsp, libscap): Support full argument retrieval on both entry and exit for some syscalls
Signed-off-by: Luca Guerra <luca@guerra.sh>
Co-authored-by: Lorenzo Susini <susinilorenzo1@gmail.com>
2022-03-03 12:10:07 +01:00
Mauro Ezequiel Moltrasio 86d06a8e91 new(chisel): Trim chisel path and read correctly
Signed-off-by: Mauro Ezequiel Moltrasio <mmoltras@redhat.com>
2022-03-01 14:59:24 +01:00
Mauro Ezequiel Moltrasio 11c8096fc5 new(chisel): Allow chisels to be loaded from memory
Signed-off-by: Mauro Ezequiel Moltrasio <mmoltras@redhat.com>
2022-03-01 14:59:24 +01:00
Michael Cho e71045b29d update to let cmake find system luajit-2.1
Signed-off-by: Michael Cho <cho-m@tuta.io>
2022-02-28 16:00:16 +01:00
Federico Di Pierro f05aaecd11 fix(userspace/libsinsp): force the usage of `testing::PrintToString` in evttype_filter unit tests to avoid a build failure with some gtest versions.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2022-02-24 18:36:18 +01:00
Federico Di Pierro 7ffd922614 update(userspace/libscap): added a couple of comments.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2022-02-24 18:00:12 +01:00
Federico Di Pierro 33b7ce9124 fix(userspace/libscap): fixed cgroups v2 support in scap_proc_fill_cgroups().
Basically, cgroups v2 uses the "Unified hierarchy" for subsystems, thus the subsys list string is always empty in /proc/pid/cgroup file.
Workaround this by forcing a default set of subsystems <cpu,cpuset,memory>.

For cgroups v1 instead everything is kept the same.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2022-02-24 18:00:12 +01:00
Angelo Puglisi 0765e5de62 perf(sinsp): optimize sinsp_threadinfo::populate_cmdline
Prefer += over +
Tested with callgrind, ~2x improvement

Signed-off-by: Angelo Puglisi <angelopuglisi86@gmail.com>
2022-02-24 15:44:19 +01:00
vadim.zyarko 65784c2e94 make sinsp_threadinfo *tinfo as const* in populate_cmdline
Signed-off-by: Angelo Puglisi <angelopuglisi86@gmail.com>
2022-02-24 15:44:19 +01:00
Andrea Terzolo e821bb23a6 fix(libscap): fix the number of `drops_buffer`
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-02-24 11:57:25 +01:00
Andrea Terzolo 04fe1a6563 new(bpf_probe): add a check when the buffer is full
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-02-24 11:57:25 +01:00
Andrea Terzolo 6280aaaca6 new(bpf_probe,libscap,libsinsp): add scratch map stats
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-02-24 11:57:25 +01:00
Andrea Terzolo 271c8f71ac refactor(bpf_probe): add error code `PPM_FAILURE_FRAME_SCRATCH_MAP_FULL`
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-02-24 11:57:25 +01:00
Andrea Terzolo c0c04e75eb fix(driver,libscap): add `PPM_SC_CLONE` and `PPM_SC_CLONE3`
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-02-23 19:01:38 +01:00
Mauro Ezequiel Moltrasio dcf1dc9d34 chore(cmake/modules) Fix GRPC dependencies after bump
Signed-off-by: Mauro Ezequiel Moltrasio <mmoltras@redhat.com>
2022-02-23 17:31:24 +01:00
Mauro Ezequiel Moltrasio c2ec5dca61 chore(cmake/modules) Bump bundled GRPC version to 1.44.0
Signed-off-by: Mauro Ezequiel Moltrasio <mmoltras@redhat.com>
2022-02-23 17:31:24 +01:00
Federico Di Pierro 109398a09a fix(userspace/libsinsp): properly include <memory> in libsinsp token_bucket unit test.
This fixes build in debian 10 for example.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2022-02-23 16:55:38 +01:00
Angelo Puglisi 4f4c882d3e perf(sinsp): avoid copy in sinsp_utils::find_first_env
Signed-off-by: Angelo Puglisi <angelopuglisi86@gmail.com>
2022-02-22 15:43:43 +01:00
Federico Di Pierro 39e05ab79c new(userspace/libsinsp): allow to specify a list of cri socket paths to be tried in fallback manner.
This allows to pass multiple "--cri" option in Falco and be sure that the first socket that works will be used.
A PR in Falco is needed to manage multiple "--cri" options though.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2022-02-21 17:32:35 +01:00
Mark Stemm c260765511 Always skip update command for git based external projects
I noticed that some external projects were being reconfigured/built
with every make, even though no files in the external project had been
updated.

With some debugging I noticed that git based external projects were
re-running their "update" step every time, and that in turn caused the
configure/build/install steps to re-run as well. (Generally the build
step is a no-op as the Makefile/etc. in the external project is well
formed and doesn't do anything, but the configure/install steps still
run).

It seems related to this cmake bug:
https://gitlab.kitware.com/cmake/cmake/-/issues/19703. In short, the
git update step for an external project does not create any "done"
file that denotes that the files are still up-to-date. Without that
"done" file, the update step is always run, and that in turn causes
the other steps for the external project to re-run as well.

The best way to fix this seems to be to skip the update step by
defining an empty UPDATE_COMMAND. As long as the downloaded code for a
given hash/tag/etc does not change, the update step is unnecessary.

And if we *really* wanted to ensure unchanged dependencies, we would
download our own copies anyway.

Making this change significantly cleans up the falco build to avoid
rebuilding git based external dependencies.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2022-02-18 17:15:42 +01:00
Lorenzo Susini 97dd002dfc update(libsinsp): add k8s node name validation
Signed-off-by: Lorenzo Susini <susinilorenzo1@gmail.com>
2022-02-18 10:58:32 +01:00
Andrea Terzolo 388011895c refactor(libsinsp): remove unused `sinsp_evttype_filter` class
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-02-17 10:01:07 +01:00
Andrea Terzolo f05af8ac65 refactor(libsinsp): remove unused field `m_evttype_filter`
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-02-17 10:01:07 +01:00
Andrea Terzolo de964b79c7 refactor(libsinsp): delete unused `add_evttype_filter` API
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-02-17 10:01:07 +01:00
Andrea Bonanno 4232351731 fix(chisel): fixes mismatch in a lua callback used by some chisels
Signed-off-by: Andrea Bonanno <andrea@bonanno.cloud>
2022-02-15 16:36:46 +01:00
Grzegorz Nosek 8e2a574bce fix: pass API versions from kmod via pointer, not return value
The return value is limited to 32 bits, which chops off most
high-order bits.

Signed-off-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2022-02-14 18:27:50 +01:00
Grzegorz Nosek 1ea8a662a6 fix: fix bit twiddling macros for API versioning support
Signed-off-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2022-02-14 18:27:50 +01:00
Andrea Terzolo 57c076266f docs(driver): fix clone event names in comments
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-02-14 16:30:44 +01:00
Gerald Combs 1b612964a8 libsinsp: Add support for plugin "info" and "conversation" properties.
Add EPF_INFO and EPF_CONVERSATION to filtercheck_field_flags so that
they can be exposed via sinsp_plugin::fields().

Signed-off-by: Gerald Combs <gerald@wireshark.org>
2022-02-14 11:50:31 +01:00
Andrea Terzolo f144d588df fix(driver,bpf_probe): capture also execveat exit event
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-02-14 11:18:49 +01:00
Gerald Combs 76fef4e57e libsinsp: Make filtercheck_field_info.m_display optional.
The display name might not be set in all cases, e.g. for hidden fields.
Make it optional.

Signed-off-by: Gerald Combs <gerald@wireshark.org>
2022-02-14 10:37:31 +01:00
Gerald Combs 93dad63469 libsinsp: Fix some typos.
Signed-off-by: Gerald Combs <gerald@wireshark.org>
2022-02-14 10:37:31 +01:00
Gerald Combs 5b4fad5cbb libsinsp: Add a field display name to filtercheck_field_info.
Add a field display name element to filtercheck_field_info, which can be
used to display short descriptions of field values in a UI. Fill it in
using the "Display" key provided by plugins and update the constants in
libsinsp/filterchecks.cpp as needed.

Signed-off-by: Gerald Combs <gerald@wireshark.org>
2022-02-14 10:37:31 +01:00
Andrea Terzolo e473353cf6 style(driver,bpf_probe): fix indentation problems
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-02-11 22:15:51 +01:00
Andrea Terzolo f92018e1b4 update(libsinsp): adding support to clone3 in libsinsp
Signed-off-by: Andrea Terzolo <s276109@studenti.polito.it>
Co-authored-by: Jason Dellaluce <jasondellaluce@gmail.com>
2022-02-11 22:15:51 +01:00
Andrea Terzolo 27ea5bcb0b update(libscap): adding support to clone3 in libscap
Signed-off-by: Andrea Terzolo <s276109@studenti.polito.it>
2022-02-11 22:15:51 +01:00
Andrea Terzolo 431f65f1dc new(driver/bpf): adding support to clone3 in bpf probe
Signed-off-by: Andrea Terzolo <s276109@studenti.polito.it>
2022-02-11 22:15:51 +01:00
Andrea Terzolo f21502ed92 new(driver): adding support to clone3
Signed-off-by: Andrea Terzolo <s276109@studenti.polito.it>
2022-02-11 22:15:51 +01:00
Lorenzo Susini 25afadce41 update(libsinsp): add case specific parsing for copy_file_range syscall
Signed-off-by: Lorenzo Susini <susinilorenzo1@gmail.com>
Co-authored-by: Jason Dellaluce <jasondellaluce@gmail.com>
2022-02-11 16:05:46 +01:00
Lorenzo Susini 045f38284a update(libscap): add copy_file_range syscall
Signed-off-by: Lorenzo Susini <susinilorenzo1@gmail.com>
Co-authored-by: Jason Dellaluce <jasondellaluce@gmail.com>
2022-02-11 16:05:46 +01:00
Lorenzo Susini 53039b6a3c update(driver/bpf): add ebpf filler for copy_file_range
Signed-off-by: Lorenzo Susini <susinilorenzo1@gmail.com>
Co-authored-by: Jason Dellaluce <jasondellaluce@gmail.com>
2022-02-11 16:05:46 +01:00
Lorenzo Susini 93f897de7c update(driver): add copy_file_range syscall
Signed-off-by: Lorenzo Susini <susinilorenzo1@gmail.com>
Co-authored-by: Jason Dellaluce <jasondellaluce@gmail.com>
2022-02-11 16:05:46 +01:00
Grzegorz Nosek 02a3712b06 Remove unnecessary method in Podman code
Signed-off-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2022-02-08 19:56:41 +01:00
Grzegorz Nosek 50d21d1dc3 Remove unnecessary method in Windows Docker code
Signed-off-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2022-02-08 19:56:41 +01:00
Grzegorz Nosek 4f177295c3 Invert `if` condition for readability
Signed-off-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2022-02-08 19:56:41 +01:00
Grzegorz Nosek ccadd6884c Actually enable the Podman engine
Signed-off-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2022-02-08 19:56:41 +01:00
Grzegorz Nosek 7227177d4b Add a podman_owner_uid label for rootless Podman containers
Signed-off-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2022-02-08 19:56:41 +01:00
Grzegorz Nosek 0bc1b30852 Log the socket used to contact the Docker/Podman daemon
Signed-off-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2022-02-08 19:56:41 +01:00
Grzegorz Nosek 663e607eed Support Podman container engine
Since it's very similar to Docker (modulo some quirks handled by
the previous commit), it inherits almos all the code from `docker_base`.

The cgroup detection for non-root containers is done manually
and due to the limitations of our driver (not easily bypassed),
we have to fall back to parsing cgroups files manually.

Signed-off-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2022-02-08 19:56:41 +01:00
Grzegorz Nosek b864389510 Match Podman images including the tag
If a container is started e.g. as `docker.io/library/httpd`,
this is what ends up in container.m_image. Then we match m_image
against the names on the container image list, but they always
have a tag, e.g. `docker.io/library/httpd:latest` so they won't
match the name without a tag.

Fix it by:
- defaulting to the `latest` tag a bit earlier (before fetching
  the image list)
- using repo + ':' + tag as the string to match to always have
  the tag in the name to compare

Signed-off-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2022-02-08 19:56:41 +01:00
Grzegorz Nosek cc821199ca Split the right image id for podman containers
While these two are apparently always the same, we check .Image
for the '/' and then we parse .Config.Image.

Switch to parsing .Image for somewhat reduced confusion.

Signed-off-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2022-02-08 19:56:41 +01:00
Grzegorz Nosek 4722ec6da3 Support Podman quirks in docker_async_source
Signed-off-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2022-02-08 19:56:41 +01:00
Joseph Pittman 688fcebb59 Include linux/compat.h before net/compat.h
When attempting to build the eBPF probe in a kernel development
environment with the config parameter CONFIG_COMPAT=no, the compile
of filler_helpers.h fails due to unknown types in net/compat.h
There is a kernel patch available to fix this problem:
- https://patches.linaro.org/project/netdev/patch/20201121214844.1488283-1-kuba@kernel.org/
But for environments where this patch is not available (such as
RHEL8 on ARM processors), we can work around this problem by
explicitly including linux/compat.h before net/compat.h, where
it is needed.

Signed-off-by: Joseph Pittman <joseph.pittman@sysdig.com>
2022-02-08 19:25:40 +01:00
Leonardo Grasso cba4af082a docs(proposals/20220203-versioning-schema-amendment): correct typo
Co-authored-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>

Co-authored-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2022-02-08 09:58:39 +01:00
Leonardo Grasso a14f7d883f docs(proposal): clarify versioning schema usage
Co-authored-by: Jason Dellaluce <jasondellaluce@gmail.com>
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2022-02-08 09:58:39 +01:00
Leonardo Grasso a4174d8090 docs(proposal): corret typo
Co-authored-by: Federico Di Pierro <nierro92@gmail.com>
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2022-02-08 09:58:39 +01:00
Leonardo Grasso 6f6d296395 docs(proposals): versioning schema amendment improvements
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2022-02-08 09:58:39 +01:00
Leonardo Grasso 6b1b9c0dcf docs(proposals): versioning schema amendment
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2022-02-08 09:58:39 +01:00
Federico Di Pierro 85f898e7af fix(userspace/libsinsp): fix a wreorder warning that caused errors on centos7 build for Falco.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2022-02-07 17:35:39 +01:00
Leonardo Grasso cc42b767e8 update(userspace/scap): incompatible driver error message
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2022-02-04 22:47:37 +01:00
Leonardo Grasso a34513703d docs(driver): use `driver` instead of `probe`
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2022-02-04 22:47:37 +01:00
Leonardo Grasso 7f3ee83f64 chore(driver): rename readme to .md
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2022-02-04 22:47:37 +01:00
Leonardo Grasso 50b6f03ae5 update(userspace): use `driver` instead of `probe` in API names
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2022-02-04 22:47:37 +01:00
Leonardo Grasso 2c080edf47 build(driver): rename `PROBE_COMMIT` to `DRIVER_COMMIT`
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2022-02-04 22:47:37 +01:00
Leonardo Grasso 0b5d160896 build: refactor `PROBE_` to `DRIVER_` for driver API/schema versioning
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2022-02-04 22:47:37 +01:00
Leonardo Grasso 7d5af8bbc2 chore(driver): improve cpuhp callback name
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2022-02-04 22:47:37 +01:00
Leonardo Grasso 5ef0ad690a chore(userspace/libscap): correct def name to `SCAP_DRIVER_MODULE_NAME`
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2022-02-04 22:47:37 +01:00
Leonardo Grasso 8596512f11 update(driver)!: replace `PROBE_DEVICE_NAME` with `DRIVER_DEVICE_NAME`
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2022-02-04 22:47:37 +01:00
Leonardo Grasso b2b4fe86b0 chore(userspace/libscap): clean up const
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2022-02-04 22:47:37 +01:00
Leonardo Grasso 96add173cf update(driver): rename `PPM_IOCTL_GET_DRIVER_VERSION`
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2022-02-04 22:47:37 +01:00
Leonardo Grasso 60434ce291 update(driver)!: replace `PROBE_VERSION` with `DRIVER_VERSION`
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2022-02-04 22:47:37 +01:00
Leonardo Grasso 9f372d0e50 update(driver)!: replace `PROBE_NAME` with `DRIVER_NAME`
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2022-02-04 22:47:37 +01:00
Federico Di Pierro 033c4b9f28 update(userspace/libsinsp): simplify sinsp_plugin::is_plugin_loaded() impl.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2022-02-03 15:22:08 +01:00
Federico Di Pierro bb2e13f499 update(userspace/libsinsp): introduce a sinsp_plugin_handle typedef.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>

Co-authored-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2022-02-03 15:22:08 +01:00
Federico Di Pierro ba8d76e194 fix(userspace/libsinsp): destroy the library handle if a wrong plugin type is passed and return the error.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2022-02-03 15:22:08 +01:00
Federico Di Pierro 44418e930d new(userspace/libsinsp): added a is_plugin_loaded() API to check if desired library object is currently loaded.
Moreover, properly keep a reference to library handle and dlclose it in dtor.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2022-02-03 15:22:08 +01:00
Luca Guerra dfaff4e4af new(gen_filters): port markdown function to generic filters
Signed-off-by: Luca Guerra <luca@guerra.sh>
2022-02-03 11:08:28 +01:00
Lorenzo Susini c19fe029ec refactor(libscap): cleanup sysdig references
Signed-off-by: Lorenzo Susini <susinilorenzo1@gmail.com>
2022-02-03 10:38:25 +01:00
Lorenzo Susini 73e0b8f008 refactor(driver/bpf): cleanup sysdig references
Signed-off-by: Lorenzo Susini <susinilorenzo1@gmail.com>
2022-02-03 10:38:25 +01:00
Lorenzo Susini d1a2bb749f refactor(driver): cleanup sysdig references
Signed-off-by: Lorenzo Susini <susinilorenzo1@gmail.com>
2022-02-03 10:38:25 +01:00
Grzegorz Nosek 12406fc9fd fix: don't leak fds in scap_open_live_int error path
If fcntl(F_SETFD, FD_CLOEXEC) failed in scap_open_live_int,
we returned from the function with the fd still open
(scap_close only closes the fds which have a mmapped buffer
attached).

Signed-off-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2022-02-02 18:00:02 +01:00
Grzegorz Nosek 3745949eeb feat: API versioning for user/kernel boundary
This allows reusing eBPF probes across different consumers
(and consumer versions) as long as the API is compatible.

It also adds validation of API versions in the non-eBPF
kernel probes, which was a long-standing omission. Since
the actual interface evolved slowly, it generally worked fine,
but in some rare cases it could easily end up with a kernel
panic.

Signed-off-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2022-02-02 18:00:02 +01:00
Federico Di Pierro 2750b8893b update(README): small fixes.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2022-02-01 17:21:00 +01:00
Federico Di Pierro 50aa758594 update(README): added some more links and docs.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>

Co-authored-by: deepskyblue86 <angelopuglisi86@gmail.com>
2022-02-01 17:21:00 +01:00
Federico Di Pierro fa1e72b0cd update(readme): improved scap-open related part.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2022-02-01 17:21:00 +01:00
Federico Di Pierro 87ea250323 Update README.md
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>

Co-authored-by: Leonardo Grasso <me@leonardograsso.com>
2022-02-01 17:21:00 +01:00
Federico Di Pierro 4df7717bff Update README.md
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>

Co-authored-by: Leonardo Grasso <me@leonardograsso.com>
2022-02-01 17:21:00 +01:00
Federico Di Pierro ad771ad8a0 Update README.md
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>

Co-authored-by: Leonardo Grasso <me@leonardograsso.com>
2022-02-01 17:21:00 +01:00
Federico Di Pierro 5f0ebecb47 Update README.md
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>

Co-authored-by: Leonardo Grasso <me@leonardograsso.com>
2022-02-01 17:21:00 +01:00
Federico Di Pierro 71b6cfd7ad update: mention chisels.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2022-02-01 17:21:00 +01:00
Federico Di Pierro c87aee07ee update: added license section, and driver testing through scap-open.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2022-02-01 17:21:00 +01:00
Federico Di Pierro 2374ead905 chore: updated readme.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2022-02-01 17:21:00 +01:00
86 changed files with 3224 additions and 1314 deletions

140
README.md
View File

@ -1,3 +1,141 @@
# falcosecurity/libs
As per the [OSS Libraries Contribution Plan](https://github.com/falcosecurity/falco/blob/master/proposals/20210119-libraries-contribution.md), this repository has been chosen to be the new home for **libsinsp**, **libscap**, the **kernel module driver** and the **eBPF driver sources**.
As per the [OSS Libraries Contribution Plan](https://github.com/falcosecurity/falco/blob/master/proposals/20210119-libraries-contribution.md), this repository has been chosen to be the new home for **libsinsp**, **libscap**, the **kernel module** and the **eBPF probe** sources.
Refer to https://falco.org/blog/contribution-drivers-kmod-ebpf-libraries/ for more informations.
These components are at the foundation of [Falco](https://github.com/falcosecurity/falco) and other projects that work with the same kind of data.
This component stack mainly operates on a data source: system calls. This data source is collected using either a kernel module or an eBPF probe, which we call *drivers*. On top of the drivers, libscap manages the data capture process, libsinsp enriches the data, and provides a rich set of API to consume the data. Furthermore, these two libraries also implement a [plugin](https://github.com/falcosecurity/plugins) framework that extends this stack to potentially any other data sources.
An image is worth a thousand words, they say:
![diagram](https://falco.org/img/falco-diagram-blog-contribution.png)
## Project Layout
* [_driver/_](./driver) contains kernel module and eBPF probe source code,
so-called **drivers**.
* [_userspace/_](./userspace) contains libscap and libsinsp libraries code,
plus chisels related code and common utilities.
* **libscap** (aka lib for *System CAPture*) is the userspace library
that directly communicates with the drivers, reading syscall events from
the ring buffer (where drivers place them), and forwarding them
up to libsinsp. Moreover, libscap implements OS state collection and
supports reading/writing to scap files.
* **libsinsp** (aka lib for *System INSPection*) receives events from
libscap and enriches them with machine state: moreover, it performs
events filtering with rule evaluation through its internal rule engine.
Finally, it manages outputs.
* **chisels** are just little Lua scripts to analyze an event stream
and perform useful actions. In this subfolder, the backend code for
chisels support can be found.
* [_proposals/_](./proposals) unexpectedly contains the list of proposals.
* [_cmake/modules/_](./cmake/modules) contains modules to build
external dependencies, plus the libscap and libsinsp ones; consumers
(like Falco) use those modules to build the libs in their projects.
## Build
Libs relies upon `cmake` build system.
Lots of `make` targets will be available; the most important ones are:
* `driver` -> to build the kmod
* `bpf` -> to build the eBPF probe
* `scap` -> to build libscap
* `sinsp` -> to build libsinsp (depends upon `scap` target)
* `scap-open` -> to build a small libscap example to quickly test drivers (depends upon `scap`)
To start, first create and move inside `build/` folder:
```bash
mkdir build && cd build
```
### Bundled deps
Easiest way to build the project is to use BUNDLED_DEPS option,
meaning that most of the dependencies will be fetched and compiled during the process:
```bash
cmake -DUSE_BUNDLED_DEPS=true ../
make sinsp
```
> **NOTE:** take a break as this will take quite a bit of time (around 15 mins, dependent on the hardware obviously).
### System deps
To build using the system deps instead, first make sure to have all the needed packages installed.
Refer to https://falco.org/docs/getting-started/source/ for the list of dependencies.
Then, simply issue:
```bash
cmake ../
make sinsp
```
> **NOTE:** using system libraries is useful to cut compile times down, as this way it will only build libs, and not all deps.
> On the other hand, system deps version may have an impact, and we cannot guarantee everything goes smoothly while using them.
### Build kmod
To build the kmod driver, you need your kernel headers installed. Again, checkout the Falco documentation for this step.
Then it will be just a matter of running:
```bash
make driver
```
### Build eBPF probe
To build the eBPF probe, you need `clang` and `llvm` packages.
Then, issue:
```bash
cmake -DBUILD_BPF=true ../
make bpf
```
## Test drivers
Libscap ships a small example that is quite handy to quickly check that drivers are working fine.
To build it, issue:
```bash
make scap-open
```
Then, to execute it with the eBPF probe, issue:
```bash
sudo BPF_PROBE=driver/bpf/probe.o ./libscap/examples/01-open/scap-open
```
To execute it with the kmod instead issue:
```bash
sudo insmod driver/scap.ko
sudo ./libscap/examples/01-open/scap-open
sudo rmmod scap
```
As soon as you quit (ctrl-C) the scap-open program, you will be prompted with detailed informations on the capture:
```bash
events captured: 39460
seen by driver: 39912
Number of dropped events: 0
Number of dropped events caused by full buffer: 0
Number of dropped events caused by invalid memory access: 0
Number of dropped events caused by an invalid condition in the kernel instrumentation: 0
Number of preemptions: 0
Number of events skipped due to the tid being in a set of suppressed tids: 0
Number of threads currently being suppressed: 0
```
therefore confirming that the drivers are indeed working fine!
## Contribute
Any contribution is incredibly helpful and **warmly** accepted; be it code, documentation, or just ideas, please feel free to share it!
For a contribution guideline, refer to: https://github.com/falcosecurity/.github/blob/master/CONTRIBUTING.md.
### Adding syscalls
Implementing new syscalls is surely one of the highest frequency request.
While it is indeed important for libs to support as many syscalls as possible, most of the time it is not a high priority task.
But **you** can speed up things by opening a PR for it!
Luckily enough, a Falco blog post explains the process very thoroughly: https://falco.org/blog/falco-monitoring-new-syscalls/.
## License
This project is licensed to you under the [Apache 2.0](./COPYING) open source license. Some subcomponents might be licensed separately. You can find licensing notices [here](./NOTICES).

View File

@ -83,13 +83,14 @@ else()
"${GRPC_SRC}/libupb.a"
"${GRPC_SRC}/third_party/abseil-cpp/absl/hash/libabsl_hash.a"
"${GRPC_SRC}/third_party/abseil-cpp/absl/hash/libabsl_city.a"
"${GRPC_SRC}/third_party/abseil-cpp/absl/hash/libabsl_wyhash.a"
"${GRPC_SRC}/third_party/abseil-cpp/absl/hash/libabsl_low_level_hash.a"
"${GRPC_SRC}/third_party/abseil-cpp/absl/container/libabsl_raw_hash_set.a"
"${GRPC_SRC}/third_party/abseil-cpp/absl/container/libabsl_hashtablez_sampler.a"
"${GRPC_SRC}/third_party/abseil-cpp/absl/base/libabsl_exponential_biased.a"
"${GRPC_SRC}/third_party/abseil-cpp/absl/status/libabsl_statusor.a"
"${GRPC_SRC}/third_party/abseil-cpp/absl/status/libabsl_status.a"
"${GRPC_SRC}/third_party/abseil-cpp/absl/strings/libabsl_cord.a"
"${GRPC_SRC}/third_party/abseil-cpp/absl/strings/libabsl_cordz_functions.a"
"${GRPC_SRC}/third_party/abseil-cpp/absl/profiling/libabsl_exponential_biased.a"
"${GRPC_SRC}/third_party/abseil-cpp/absl/types/libabsl_bad_optional_access.a"
"${GRPC_SRC}/third_party/abseil-cpp/absl/types/libabsl_bad_variant_access.a"
"${GRPC_SRC}/third_party/abseil-cpp/absl/strings/libabsl_str_format_internal.a"
@ -111,13 +112,24 @@ else()
"${GRPC_SRC}/third_party/abseil-cpp/absl/base/libabsl_raw_logging_internal.a"
"${GRPC_SRC}/third_party/abseil-cpp/absl/base/libabsl_log_severity.a"
"${GRPC_SRC}/third_party/abseil-cpp/absl/time/libabsl_time_zone.a"
"${GRPC_SRC}/third_party/abseil-cpp/absl/strings/libabsl_cord_internal.a"
"${GRPC_SRC}/third_party/abseil-cpp/absl/strings/libabsl_cordz_info.a"
"${GRPC_SRC}/third_party/abseil-cpp/absl/strings/libabsl_cordz_handle.a"
"${GRPC_SRC}/third_party/abseil-cpp/absl/random/libabsl_random_internal_pool_urbg.a"
"${GRPC_SRC}/third_party/abseil-cpp/absl/random/libabsl_random_internal_randen.a"
"${GRPC_SRC}/third_party/abseil-cpp/absl/random/libabsl_random_internal_randen_hwaes.a"
"${GRPC_SRC}/third_party/abseil-cpp/absl/random/libabsl_random_internal_randen_hwaes_impl.a"
"${GRPC_SRC}/third_party/abseil-cpp/absl/random/libabsl_random_internal_platform.a"
"${GRPC_SRC}/third_party/abseil-cpp/absl/random/libabsl_random_internal_randen_slow.a"
"${GRPC_SRC}/third_party/abseil-cpp/absl/random/libabsl_random_internal_seed_material.a"
"${GRPC_SRC}/third_party/abseil-cpp/absl/random/libabsl_random_seed_gen_exception.a"
)
ExternalProject_Add(grpc
PREFIX "${PROJECT_BINARY_DIR}/grpc-prefix"
DEPENDS openssl protobuf c-ares zlib
GIT_REPOSITORY https://github.com/grpc/grpc.git
GIT_TAG v1.38.1
GIT_TAG v1.44.0
GIT_SUBMODULES "third_party/abseil-cpp third_party/re2"
CMAKE_CACHE_ARGS
-DCMAKE_INSTALL_PREFIX:PATH=${GRPC_INSTALL_DIR}
@ -156,6 +168,7 @@ else()
BUILD_BYPRODUCTS ${GRPC_LIB} ${GRPCPP_LIB} ${GPR_LIB} ${GRPC_LIBRARIES}
# Keep installation files into the local ${GRPC_INSTALL_DIR}
# since here is the case when we are embedding gRPC
UPDATE_COMMAND ""
INSTALL_COMMAND DESTDIR= ${CMD_MAKE} install
)
endif()

View File

@ -6,7 +6,7 @@ option(USE_BUNDLED_LUAJIT "Enable building of the bundled LuaJIT" ${USE_BUNDLED_
if(LUAJIT_INCLUDE)
# we already have luajit
elseif(NOT USE_BUNDLED_LUAJIT)
find_path(LUAJIT_INCLUDE luajit.h PATH_SUFFIXES luajit-2.0 luajit)
find_path(LUAJIT_INCLUDE luajit.h PATH_SUFFIXES luajit-2.0 luajit-2.1 luajit)
find_library(LUAJIT_LIB NAMES luajit luajit-5.1)
if(LUAJIT_INCLUDE AND LUAJIT_LIB)
message(STATUS "Found LuaJIT: include: ${LUAJIT_INCLUDE}, lib: ${LUAJIT_LIB}")
@ -42,6 +42,7 @@ else()
BUILD_COMMAND ${CMD_MAKE}
BUILD_IN_SOURCE 1
BUILD_BYPRODUCTS ${LUAJIT_LIB}
UPDATE_COMMAND ""
INSTALL_COMMAND "")
elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "s390x")
ExternalProject_Add(luajit
@ -52,6 +53,7 @@ else()
BUILD_COMMAND ${CMD_MAKE}
BUILD_IN_SOURCE 1
BUILD_BYPRODUCTS ${LUAJIT_LIB}
UPDATE_COMMAND ""
INSTALL_COMMAND "")
elseif(APPLE)
ExternalProject_Add(luajit
@ -72,6 +74,7 @@ else()
BUILD_COMMAND ${CMD_MAKE}
BUILD_IN_SOURCE 1
BUILD_BYPRODUCTS ${LUAJIT_LIB}
UPDATE_COMMAND ""
INSTALL_COMMAND "")
endif()
else()

1
driver/API_VERSION Normal file
View File

@ -0,0 +1 @@
1.0.0

View File

@ -1,5 +1,5 @@
#
# Copyright (C) 2021 The Falco Authors.
# Copyright (C) 2022 The Falco Authors.
#
# This file is dual licensed under either the MIT or GPL 2. See
# MIT.txt or GPL.txt for full copies of the license.
@ -39,6 +39,23 @@ endif()
# after the build we copy the compiled module one directory up,
# to ${CMAKE_CURRENT_BINARY_DIR}.
file(STRINGS API_VERSION DRIVER_API_VERSION LIMIT_COUNT 1)
string(REGEX MATCHALL "[0-9]+" DRIVER_API_COMPONENTS "${DRIVER_API_VERSION}")
list(GET DRIVER_API_COMPONENTS 0 PPM_API_CURRENT_VERSION_MAJOR)
list(GET DRIVER_API_COMPONENTS 1 PPM_API_CURRENT_VERSION_MINOR)
list(GET DRIVER_API_COMPONENTS 2 PPM_API_CURRENT_VERSION_PATCH)
message(STATUS "Driver API version ${PPM_API_CURRENT_VERSION_MAJOR}.${PPM_API_CURRENT_VERSION_MINOR}.${PPM_API_CURRENT_VERSION_PATCH}")
file(STRINGS SCHEMA_VERSION DRIVER_SCHEMA_VERSION LIMIT_COUNT 1)
string(REGEX MATCHALL "[0-9]+" DRIVER_SCHEMA_COMPONENTS "${DRIVER_SCHEMA_VERSION}")
list(GET DRIVER_SCHEMA_COMPONENTS 0 PPM_SCHEMA_CURRENT_VERSION_MAJOR)
list(GET DRIVER_SCHEMA_COMPONENTS 1 PPM_SCHEMA_CURRENT_VERSION_MINOR)
list(GET DRIVER_SCHEMA_COMPONENTS 2 PPM_SCHEMA_CURRENT_VERSION_PATCH)
message(STATUS "Driver schema version ${PPM_SCHEMA_CURRENT_VERSION_MAJOR}.${PPM_SCHEMA_CURRENT_VERSION_MINOR}.${PPM_SCHEMA_CURRENT_VERSION_PATCH}")
execute_process(COMMAND git rev-parse HEAD OUTPUT_VARIABLE GIT_COMMIT ERROR_QUIET WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
string(STRIP "${GIT_COMMIT}" GIT_COMMIT)
configure_file(dkms.conf.in src/dkms.conf)
configure_file(Makefile.in src/Makefile)
configure_file(driver_config.h.in src/driver_config.h)
@ -51,6 +68,7 @@ set(DRIVER_SOURCES
kernel_hacks.h
main.c
ppm.h
ppm_api_version.h
ppm_events.c
ppm_events.h
ppm_events_public.h
@ -84,13 +102,13 @@ endif()
if(BUILD_DRIVER)
add_custom_target(driver ALL
COMMAND ${MAKE_COMMAND}
COMMAND "${CMAKE_COMMAND}" -E copy_if_different ${PROBE_NAME}.ko "${CMAKE_CURRENT_BINARY_DIR}"
COMMAND "${CMAKE_COMMAND}" -E copy_if_different ${DRIVER_NAME}.ko "${CMAKE_CURRENT_BINARY_DIR}"
WORKING_DIRECTORY src
VERBATIM)
else()
add_custom_target(driver
COMMAND ${MAKE_COMMAND}
COMMAND "${CMAKE_COMMAND}" -E copy_if_different ${PROBE_NAME}.ko "${CMAKE_CURRENT_BINARY_DIR}"
COMMAND "${CMAKE_COMMAND}" -E copy_if_different ${DRIVER_NAME}.ko "${CMAKE_CURRENT_BINARY_DIR}"
WORKING_DIRECTORY src
VERBATIM)
endif()
@ -106,7 +124,7 @@ if(ENABLE_DKMS)
${CMAKE_CURRENT_BINARY_DIR}/src/dkms.conf
${CMAKE_CURRENT_BINARY_DIR}/src/driver_config.h
${DRIVER_SOURCES}
DESTINATION "src/${DRIVER_PACKAGE_NAME}-${PROBE_VERSION}"
DESTINATION "src/${DRIVER_PACKAGE_NAME}-${DRIVER_VERSION}"
COMPONENT ${DRIVER_COMPONENT_NAME})
endif()

View File

@ -1,12 +1,12 @@
#
# Copyright (C) 2021 The Falco Authors.
# Copyright (C) 2022 The Falco Authors.
#
# This file is dual licensed under either the MIT or GPL 2. See
# MIT.txt or GPL.txt for full copies of the license.
#
@PROBE_NAME@-y += main.o dynamic_params_table.o fillers_table.o flags_table.o ppm_events.o ppm_fillers.o event_table.o syscall_table.o ppm_cputime.o
obj-m += @PROBE_NAME@.o
@DRIVER_NAME@-y += main.o dynamic_params_table.o fillers_table.o flags_table.o ppm_events.o ppm_fillers.o event_table.o syscall_table.o ppm_cputime.o
obj-m += @DRIVER_NAME@.o
ccflags-y := @KBUILD_FLAGS@
KERNELDIR ?= /lib/modules/$(shell uname -r)/build

25
driver/README.VERSION.md Normal file
View File

@ -0,0 +1,25 @@
# API version number
The file API_VERSION must contain a semver-like version number of the userspace<->kernel API. All other lines are ignored.
## When to increment
**major version**: increment when the driver API becomes incompatible with previous userspace versions
**minor version**: increment when new features are added but existing features remain compatible
**patch version**: increment when code changes don't break compatibility (e.g. bug fixes)
Do *not* increment for patches that only add support for new kernels, without affecting already supported ones.
# Schema version number
The file SCHEMA_VERSION must contain a semver-like version number of the event schema. All other lines are ignored.
## When to increment
**major version**: increment when the schema becomes incompatible with previous userspace versions
**minor version**: increment when new features are added but existing features remain compatible (e.g. new event fields or new events)
**patch version**: increment when code changes don't break compatibility (e.g. bug fixes in filler code)

1
driver/SCHEMA_VERSION Normal file
View File

@ -0,0 +1 @@
1.0.0

View File

@ -1,5 +1,5 @@
#
# Copyright (C) 2021 The Falco Authors.
# Copyright (C) 2022 The Falco Authors.
#
# This file is dual licensed under either the MIT or GPL 2. See
# MIT.txt or GPL.txt for full copies of the license.
@ -29,5 +29,5 @@ install(FILES
quirks.h
ring_helpers.h
types.h
DESTINATION "src/${DRIVER_PACKAGE_NAME}-${PROBE_VERSION}/bpf"
DESTINATION "src/${DRIVER_PACKAGE_NAME}-${DRIVER_VERSION}/bpf"
COMPONENT ${DRIVER_COMPONENT_NAME})

View File

@ -9,6 +9,7 @@ or GPL2.txt for full copies of the license.
#ifndef __SYSDIGBPF_HELPERS_H
#define __SYSDIGBPF_HELPERS_H
#include <linux/compat.h>
#include <net/compat.h>
#include <net/sock.h>
#include <net/inet_sock.h>
@ -745,7 +746,10 @@ static __always_inline int __bpf_val_to_ring(struct filler_data *data,
curoff_bounded = data->state->tail_ctx.curoff & SCRATCH_SIZE_HALF;
if (data->state->tail_ctx.curoff > SCRATCH_SIZE_HALF)
return PPM_FAILURE_BUFFER_FULL;
{
return PPM_FAILURE_FRAME_SCRATCH_MAP_FULL;
}
if (dyn_idx != (u8)-1) {
*((u8 *)&data->buf[curoff_bounded]) = dyn_idx;
len_dyn = sizeof(u8);
@ -755,7 +759,9 @@ static __always_inline int __bpf_val_to_ring(struct filler_data *data,
curoff_bounded = data->state->tail_ctx.curoff & SCRATCH_SIZE_HALF;
if (data->state->tail_ctx.curoff > SCRATCH_SIZE_HALF)
return PPM_FAILURE_BUFFER_FULL;
{
return PPM_FAILURE_FRAME_SCRATCH_MAP_FULL;
}
switch (type) {
case PT_CHARBUF:
@ -815,7 +821,9 @@ static __always_inline int __bpf_val_to_ring(struct filler_data *data,
curoff_bounded = data->state->tail_ctx.curoff & SCRATCH_SIZE_HALF;
if (data->state->tail_ctx.curoff > SCRATCH_SIZE_HALF)
return PPM_FAILURE_BUFFER_FULL;
{
return PPM_FAILURE_FRAME_SCRATCH_MAP_FULL;
}
#ifdef BPF_FORBIDS_ZERO_ACCESS
if (read_size)
@ -900,7 +908,9 @@ static __always_inline int __bpf_val_to_ring(struct filler_data *data,
}
}
if (len_dyn + len > PPM_MAX_ARG_SIZE)
return PPM_FAILURE_BUFFER_FULL;
{
return PPM_FAILURE_FRAME_SCRATCH_MAP_FULL;
}
fixup_evt_arg_len(data->buf, data->state->tail_ctx.curarg, len_dyn + len);
data->state->tail_ctx.curoff += len;

View File

@ -95,7 +95,7 @@ static __always_inline int __bpf_##x(struct filler_data *data) \
FILLER_RAW(terminate_filler)
{
struct sysdig_bpf_per_cpu_state *state;
struct scap_bpf_per_cpu_state *state;
state = get_local_state(bpf_get_smp_processor_id());
if (!state)
@ -130,6 +130,14 @@ FILLER_RAW(terminate_filler)
break;
case PPM_SKIP_EVENT:
break;
case PPM_FAILURE_FRAME_SCRATCH_MAP_FULL:
bpf_printk("PPM_FAILURE_FRAME_SCRATCH_MAP_FULL event=%d curarg=%d\n",
state->tail_ctx.evt_type,
state->tail_ctx.curarg);
if (state->n_drops_scratch_map != ULLONG_MAX) {
++state->n_drops_scratch_map;
}
break;
default:
bpf_printk("Unknown filler res=%d event=%d curarg=%d\n",
state->tail_ctx.prev_res,
@ -169,6 +177,43 @@ FILLER(sys_single_x, true)
return res;
}
FILLER(sys_open_e, true)
{
unsigned long flags;
unsigned long val;
unsigned long mode;
int res;
/*
* name
*/
val = bpf_syscall_get_argument(data, 0);
res = bpf_val_to_ring(data, val);
if (res != PPM_SUCCESS)
return res;
/*
* Flags
* Note that we convert them into the ppm portable representation before pushing them to the ring
*/
val = bpf_syscall_get_argument(data, 1);
flags = open_flags_to_scap(val);
res = bpf_val_to_ring(data, flags);
if (res != PPM_SUCCESS)
return res;
/*
* mode
*/
mode = bpf_syscall_get_argument(data, 2);
mode = open_modes_to_scap(val, mode);
res = bpf_val_to_ring(data, mode);
if (res != PPM_SUCCESS)
return res;
return res;
}
FILLER(sys_open_x, true)
{
unsigned int flags;
@ -301,7 +346,9 @@ static __always_inline int bpf_poll_parse_fds(struct filler_data *data,
fds = (struct pollfd *)data->tmp_scratch;
read_size = nfds * sizeof(struct pollfd);
if (read_size > SCRATCH_SIZE_MAX)
return PPM_FAILURE_BUFFER_FULL;
{
return PPM_FAILURE_FRAME_SCRATCH_MAP_FULL;
}
val = bpf_syscall_get_argument(data, 0);
#ifdef BPF_FORBIDS_ZERO_ACCESS
@ -315,7 +362,9 @@ static __always_inline int bpf_poll_parse_fds(struct filler_data *data,
return PPM_FAILURE_INVALID_USER_MEMORY;
if (data->state->tail_ctx.curoff > SCRATCH_SIZE_HALF)
return PPM_FAILURE_BUFFER_FULL;
{
return PPM_FAILURE_FRAME_SCRATCH_MAP_FULL;
}
off = data->state->tail_ctx.curoff + sizeof(u16);
fds_count = 0;
@ -323,7 +372,9 @@ static __always_inline int bpf_poll_parse_fds(struct filler_data *data,
#pragma unroll
for (j = 0; j < POLL_MAXFDS; ++j) {
if (off > SCRATCH_SIZE_HALF)
return PPM_FAILURE_BUFFER_FULL;
{
return PPM_FAILURE_FRAME_SCRATCH_MAP_FULL;
}
if (j == nfds)
break;
@ -338,7 +389,9 @@ static __always_inline int bpf_poll_parse_fds(struct filler_data *data,
*(s64 *)&data->buf[off & SCRATCH_SIZE_HALF] = fds[j].fd;
off += sizeof(s64);
if (off > SCRATCH_SIZE_HALF)
return PPM_FAILURE_BUFFER_FULL;
{
return PPM_FAILURE_FRAME_SCRATCH_MAP_FULL;
}
*(s16 *)&data->buf[off & SCRATCH_SIZE_HALF] = flags;
off += sizeof(s16);
@ -410,7 +463,9 @@ static __always_inline int bpf_parse_readv_writev_bufs(struct filler_data *data,
iov = (const struct iovec *)data->tmp_scratch;
if (copylen > SCRATCH_SIZE_MAX)
return PPM_FAILURE_BUFFER_FULL;
{
return PPM_FAILURE_FRAME_SCRATCH_MAP_FULL;
}
#ifdef BPF_FORBIDS_ZERO_ACCESS
if (copylen)
@ -907,6 +962,51 @@ FILLER(sys_getrlimit_setrlrimit_x, true)
return res;
}
FILLER(sys_connect_e, true)
{
struct sockaddr *usrsockaddr;
unsigned long val;
long size = 0;
long retval;
int err;
int res;
int fd;
fd = bpf_syscall_get_argument(data, 0);
res = bpf_val_to_ring_type(data, fd, PT_FD);
if (res != PPM_SUCCESS)
return res;
if (fd >= 0) {
usrsockaddr = (struct sockaddr *)bpf_syscall_get_argument(data, 1);
val = bpf_syscall_get_argument(data, 2);
if (usrsockaddr && val != 0) {
/*
* Copy the address
*/
err = bpf_addr_to_kernel(usrsockaddr, val,
(struct sockaddr *)data->tmp_scratch);
if (err >= 0) {
/*
* Convert the fd into socket endpoint information
*/
size = bpf_pack_addr(data,
(struct sockaddr *)data->tmp_scratch,
val);
}
}
}
/*
* Copy the endpoint info into the ring
*/
data->curarg_already_on_frame = true;
res = bpf_val_to_ring_len(data, 0, size);
return res;
}
FILLER(sys_connect_x, true)
{
struct sockaddr *usrsockaddr;
@ -1623,7 +1723,9 @@ static __always_inline int __bpf_append_cgroup(struct css_set *cgroups,
off_bounded = off & SCRATCH_SIZE_HALF;
if (off > SCRATCH_SIZE_HALF)
return PPM_FAILURE_BUFFER_FULL;
{
return PPM_FAILURE_FRAME_SCRATCH_MAP_FULL;
}
int res = bpf_probe_read_str(&buf[off_bounded],
SCRATCH_SIZE_HALF,
@ -1635,7 +1737,9 @@ static __always_inline int __bpf_append_cgroup(struct css_set *cgroups,
off_bounded = off & SCRATCH_SIZE_HALF;
if (off > SCRATCH_SIZE_HALF)
return PPM_FAILURE_BUFFER_FULL;
{
return PPM_FAILURE_FRAME_SCRATCH_MAP_FULL;
}
buf[off_bounded] = '=';
++off;
@ -1656,7 +1760,9 @@ static __always_inline int __bpf_append_cgroup(struct css_set *cgroups,
if (cgroup_path[k]) {
if (!prev_empty) {
if (off > SCRATCH_SIZE_HALF)
return PPM_FAILURE_BUFFER_FULL;
{
return PPM_FAILURE_FRAME_SCRATCH_MAP_FULL;
}
buf[off_bounded] = '/';
++off;
@ -1666,7 +1772,9 @@ static __always_inline int __bpf_append_cgroup(struct css_set *cgroups,
prev_empty = false;
if (off > SCRATCH_SIZE_HALF)
return PPM_FAILURE_BUFFER_FULL;
{
return PPM_FAILURE_FRAME_SCRATCH_MAP_FULL;
}
res = bpf_probe_read_str(&buf[off_bounded],
SCRATCH_SIZE_HALF,
@ -1684,7 +1792,9 @@ static __always_inline int __bpf_append_cgroup(struct css_set *cgroups,
}
if (off > SCRATCH_SIZE_HALF)
return PPM_FAILURE_BUFFER_FULL;
{
return PPM_FAILURE_FRAME_SCRATCH_MAP_FULL;
}
buf[off_bounded] = 0;
++off;
@ -1755,7 +1865,9 @@ static __always_inline int bpf_accumulate_argv_or_env(struct filler_data *data,
break;
if (off > SCRATCH_SIZE_HALF)
return PPM_FAILURE_BUFFER_FULL;
{
return PPM_FAILURE_FRAME_SCRATCH_MAP_FULL;
}
len = bpf_probe_read_str(&data->buf[off & SCRATCH_SIZE_HALF], SCRATCH_SIZE_HALF, arg);
if (len == -EFAULT)
@ -2253,6 +2365,10 @@ FILLER(proc_startupdate_3, true)
long retval;
int res;
#ifdef __NR_clone3
struct clone_args cl_args;
#endif
retval = bpf_syscall_get_retval(data->ctx);
task = (struct task_struct *)bpf_get_current_task();
@ -2261,8 +2377,10 @@ FILLER(proc_startupdate_3, true)
return PPM_FAILURE_BUG;
if (data->state->tail_ctx.evt_type == PPME_SYSCALL_CLONE_20_X ||
data->state->tail_ctx.evt_type == PPME_SYSCALL_FORK_20_X ||
data->state->tail_ctx.evt_type == PPME_SYSCALL_VFORK_20_X) {
data->state->tail_ctx.evt_type == PPME_SYSCALL_FORK_20_X ||
data->state->tail_ctx.evt_type == PPME_SYSCALL_VFORK_20_X ||
data->state->tail_ctx.evt_type == PPME_SYSCALL_CLONE3_X)
{
/*
* clone-only parameters
*/
@ -2278,10 +2396,29 @@ FILLER(proc_startupdate_3, true)
/*
* flags
*/
if (data->state->tail_ctx.evt_type == PPME_SYSCALL_CLONE_20_X)
switch (data->state->tail_ctx.evt_type)
{
case PPME_SYSCALL_CLONE_20_X:
flags = bpf_syscall_get_argument(data, 0);
else
break;
case PPME_SYSCALL_CLONE3_X:
#ifdef __NR_clone3
flags = bpf_syscall_get_argument(data, 0);
if (bpf_probe_read(&cl_args, sizeof(struct clone_args), (void *)flags))
{
return PPM_FAILURE_INVALID_USER_MEMORY;
}
flags = cl_args.flags;
#else
flags = 0;
#endif
break;
default:
flags = 0;
break;
}
flags = clone_flags_to_scap(flags);
@ -2344,7 +2481,7 @@ FILLER(proc_startupdate_3, true)
} else if (data->state->tail_ctx.evt_type == PPME_SYSCALL_EXECVE_19_X ||
data->state->tail_ctx.evt_type == PPME_SYSCALL_EXECVEAT_X) {
/*
* execve-only parameters
* execve family parameters.
*/
long env_len = 0;
kuid_t loginuid;
@ -2598,24 +2735,24 @@ FILLER(sys_unshare_e, true)
FILLER(sys_generic, true)
{
long *sysdig_id;
long *scap_id;
int native_id;
int res;
native_id = bpf_syscall_get_nr(data->ctx);
sysdig_id = bpf_map_lookup_elem(&syscall_code_routing_table, &native_id);
if (!sysdig_id) {
scap_id = bpf_map_lookup_elem(&syscall_code_routing_table, &native_id);
if (!scap_id) {
bpf_printk("no routing for syscall %d\n", native_id);
return PPM_FAILURE_BUG;
}
if (*sysdig_id == PPM_SC_UNKNOWN)
if (*scap_id == PPM_SC_UNKNOWN)
bpf_printk("no syscall for id %d\n", native_id);
/*
* id
*/
res = bpf_val_to_ring(data, *sysdig_id);
res = bpf_val_to_ring(data, *scap_id);
if (res != PPM_SUCCESS)
return res;
@ -2629,6 +2766,54 @@ FILLER(sys_generic, true)
return res;
}
FILLER(sys_openat_e, true)
{
unsigned long flags;
unsigned long val;
unsigned long mode;
int res;
/*
* dirfd
*/
val = bpf_syscall_get_argument(data, 0);
if ((int)val == AT_FDCWD)
val = PPM_AT_FDCWD;
res = bpf_val_to_ring(data, val);
if (res != PPM_SUCCESS)
return res;
/*
* name
*/
val = bpf_syscall_get_argument(data, 1);
res = bpf_val_to_ring(data, val);
if (res != PPM_SUCCESS)
return res;
/*
* Flags
* Note that we convert them into the ppm portable representation before pushing them to the ring
*/
val = bpf_syscall_get_argument(data, 2);
flags = open_flags_to_scap(val);
res = bpf_val_to_ring(data, flags);
if (res != PPM_SUCCESS)
return res;
/*
* mode
*/
mode = bpf_syscall_get_argument(data, 3);
mode = open_modes_to_scap(val, mode);
res = bpf_val_to_ring(data, mode);
if (res != PPM_SUCCESS)
return res;
return res;
}
FILLER(sys_openat_x, true)
{
unsigned long dev;
@ -2692,6 +2877,77 @@ FILLER(sys_openat_x, true)
return res;
}
FILLER(sys_openat2_e, true)
{
unsigned long resolve;
unsigned long flags;
unsigned long val;
unsigned long mode;
int res;
#ifdef __NR_openat2
struct open_how how;
#endif
/*
* dirfd
*/
val = bpf_syscall_get_argument(data, 0);
if ((int)val == AT_FDCWD)
val = PPM_AT_FDCWD;
res = bpf_val_to_ring(data, val);
if (res != PPM_SUCCESS)
return res;
/*
* name
*/
val = bpf_syscall_get_argument(data, 1);
res = bpf_val_to_ring(data, val);
if (res != PPM_SUCCESS)
return res;
#ifdef __NR_openat2
/*
* how: we get the data structure, and put its fields in the buffer one by one
*/
val = bpf_syscall_get_argument(data, 2);
if (bpf_probe_read(&how, sizeof(struct open_how), (void *)val)) {
return PPM_FAILURE_INVALID_USER_MEMORY;
}
flags = open_flags_to_scap(how.flags);
mode = open_modes_to_scap(how.flags, how.mode);
resolve = openat2_resolve_to_scap(how.resolve);
#else
flags = 0;
mode = 0;
resolve = 0;
#endif
/*
* flags (extracted from open_how structure)
* Note that we convert them into the ppm portable representation before pushing them to the ring
*/
res = bpf_val_to_ring(data, flags);
if (res != PPM_SUCCESS)
return res;
/*
* mode (extracted from open_how structure)
* Note that we convert them into the ppm portable representation before pushing them to the ring
*/
res = bpf_val_to_ring(data, mode);
if (res != PPM_SUCCESS)
return res;
/*
* resolve (extracted from open_how structure)
* Note that we convert them into the ppm portable representation before pushing them to the ring
*/
res = bpf_val_to_ring(data, resolve);
return res;
}
FILLER(sys_openat2_x, true)
{
unsigned long resolve;
@ -3404,6 +3660,32 @@ FILLER(sys_sendmsg_x, true)
return res;
}
FILLER(sys_creat_e, true)
{
unsigned long val;
unsigned long mode;
int res;
/*
* name
*/
val = bpf_syscall_get_argument(data, 0);
res = bpf_val_to_ring(data, val);
if (res != PPM_SUCCESS)
return res;
/*
* mode
*/
mode = bpf_syscall_get_argument(data, 1);
mode = open_modes_to_scap(O_CREAT, mode);
res = bpf_val_to_ring(data, mode);
if (res != PPM_SUCCESS)
return res;
return res;
}
FILLER(sys_creat_x, true)
{
unsigned long dev;
@ -4872,4 +5154,67 @@ FILLER(sys_fchmod_x, true)
return res;
}
FILLER(sys_copy_file_range_e, true)
{
int fdin;
unsigned long offin;
unsigned long len;
int res;
/*
* fdin
*/
fdin = bpf_syscall_get_argument(data, 0);
res = bpf_val_to_ring(data, fdin);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* offin
*/
offin = bpf_syscall_get_argument(data, 1);
res = bpf_val_to_ring(data, offin);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* len
*/
len = bpf_syscall_get_argument(data, 4);
res = bpf_val_to_ring(data, len);
if (unlikely(res != PPM_SUCCESS))
return res;
return res;
}
FILLER(sys_copy_file_range_x, true)
{
int fdout;
unsigned long offout;
long retval;
int res;
retval = bpf_syscall_get_retval(data->ctx);
res = bpf_val_to_ring(data, retval);
/*
* fdout
*/
fdout = bpf_syscall_get_argument(data, 2);
res = bpf_val_to_ring(data, fdout);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* offout
*/
offout = bpf_syscall_get_argument(data, 3);
res = bpf_val_to_ring(data, offout);
if (unlikely(res != PPM_SUCCESS))
return res;
return res;
}
#endif

View File

@ -79,14 +79,14 @@ struct bpf_map_def __bpf_section("maps") tmp_scratch_map = {
struct bpf_map_def __bpf_section("maps") settings_map = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(u32),
.value_size = sizeof(struct sysdig_bpf_settings),
.value_size = sizeof(struct scap_bpf_settings),
.max_entries = 1,
};
struct bpf_map_def __bpf_section("maps") local_state_map = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(u32),
.value_size = sizeof(struct sysdig_bpf_per_cpu_state),
.value_size = sizeof(struct scap_bpf_per_cpu_state),
.max_entries = 0,
};

View File

@ -228,9 +228,9 @@ static __always_inline const struct ppm_event_entry *get_event_filler_info(enum
return e;
}
static __always_inline struct sysdig_bpf_settings *get_bpf_settings(void)
static __always_inline struct scap_bpf_settings *get_bpf_settings(void)
{
struct sysdig_bpf_settings *settings;
struct scap_bpf_settings *settings;
int id = 0;
settings = bpf_map_lookup_elem(&settings_map, &id);
@ -240,9 +240,9 @@ static __always_inline struct sysdig_bpf_settings *get_bpf_settings(void)
return settings;
}
static __always_inline struct sysdig_bpf_per_cpu_state *get_local_state(unsigned int cpu)
static __always_inline struct scap_bpf_per_cpu_state *get_local_state(unsigned int cpu)
{
struct sysdig_bpf_per_cpu_state *state;
struct scap_bpf_per_cpu_state *state;
state = bpf_map_lookup_elem(&local_state_map, &cpu);
if (!state)
@ -251,7 +251,7 @@ static __always_inline struct sysdig_bpf_per_cpu_state *get_local_state(unsigned
return state;
}
static __always_inline bool acquire_local_state(struct sysdig_bpf_per_cpu_state *state)
static __always_inline bool acquire_local_state(struct scap_bpf_per_cpu_state *state)
{
if (state->in_use) {
bpf_printk("acquire_local_state: already in use\n");
@ -262,7 +262,7 @@ static __always_inline bool acquire_local_state(struct sysdig_bpf_per_cpu_state
return true;
}
static __always_inline bool release_local_state(struct sysdig_bpf_per_cpu_state *state)
static __always_inline bool release_local_state(struct scap_bpf_per_cpu_state *state)
{
if (!state->in_use) {
bpf_printk("release_local_state: already not in use\n");
@ -327,9 +327,9 @@ static __always_inline int bpf_test_bit(int nr, unsigned long *addr)
}
static __always_inline bool drop_event(void *ctx,
struct sysdig_bpf_per_cpu_state *state,
struct scap_bpf_per_cpu_state *state,
enum ppm_event_type evt_type,
struct sysdig_bpf_settings *settings,
struct scap_bpf_settings *settings,
enum syscall_flags drop_flags)
{
if (!settings->dropping_mode)
@ -422,7 +422,7 @@ static __always_inline bool drop_event(void *ctx,
return false;
}
static __always_inline void reset_tail_ctx(struct sysdig_bpf_per_cpu_state *state,
static __always_inline void reset_tail_ctx(struct scap_bpf_per_cpu_state *state,
enum ppm_event_type evt_type,
unsigned long long ts)
{
@ -437,11 +437,11 @@ static __always_inline void reset_tail_ctx(struct sysdig_bpf_per_cpu_state *stat
static __always_inline void call_filler(void *ctx,
void *stack_ctx,
enum ppm_event_type evt_type,
struct sysdig_bpf_settings *settings,
struct scap_bpf_settings *settings,
enum syscall_flags drop_flags)
{
const struct ppm_event_entry *filler_info;
struct sysdig_bpf_per_cpu_state *state;
struct scap_bpf_per_cpu_state *state;
unsigned long long pid;
unsigned long long ts;
unsigned int cpu;

View File

@ -1,6 +1,6 @@
/*
Copyright (C) 2021 The Falco Authors.
Copyright (C) 2022 The Falco Authors.
This file is dual licensed under either the MIT or GPL 2. See MIT.txt
or GPL2.txt for full copies of the license.
@ -36,7 +36,7 @@ int bpf_##event(struct type *ctx)
BPF_PROBE("raw_syscalls/", sys_enter, sys_enter_args)
{
const struct syscall_evt_pair *sc_evt;
struct sysdig_bpf_settings *settings;
struct scap_bpf_settings *settings;
enum ppm_event_type evt_type;
int drop_flags;
long id;
@ -88,7 +88,7 @@ BPF_PROBE("raw_syscalls/", sys_enter, sys_enter_args)
BPF_PROBE("raw_syscalls/", sys_exit, sys_exit_args)
{
const struct syscall_evt_pair *sc_evt;
struct sysdig_bpf_settings *settings;
struct scap_bpf_settings *settings;
enum ppm_event_type evt_type;
int drop_flags;
long id;
@ -128,7 +128,7 @@ BPF_PROBE("raw_syscalls/", sys_exit, sys_exit_args)
BPF_PROBE("sched/", sched_process_exit, sched_process_exit_args)
{
struct sysdig_bpf_settings *settings;
struct scap_bpf_settings *settings;
enum ppm_event_type evt_type;
struct task_struct *task;
unsigned int flags;
@ -154,7 +154,7 @@ BPF_PROBE("sched/", sched_process_exit, sched_process_exit_args)
BPF_PROBE("sched/", sched_switch, sched_switch_args)
{
struct sysdig_bpf_settings *settings;
struct scap_bpf_settings *settings;
enum ppm_event_type evt_type;
settings = get_bpf_settings();
@ -172,7 +172,7 @@ BPF_PROBE("sched/", sched_switch, sched_switch_args)
static __always_inline int bpf_page_fault(struct page_fault_args *ctx)
{
struct sysdig_bpf_settings *settings;
struct scap_bpf_settings *settings;
enum ppm_event_type evt_type;
settings = get_bpf_settings();
@ -203,7 +203,7 @@ BPF_PROBE("exceptions/", page_fault_kernel, page_fault_args)
BPF_PROBE("signal/", signal_deliver, signal_deliver_args)
{
struct sysdig_bpf_settings *settings;
struct scap_bpf_settings *settings;
enum ppm_event_type evt_type;
settings = get_bpf_settings();
@ -223,7 +223,7 @@ BPF_PROBE("signal/", signal_deliver, signal_deliver_args)
__bpf_section(TP_NAME "sched/sched_process_fork")
int bpf_sched_process_fork(struct sched_process_fork_args *ctx)
{
struct sysdig_bpf_settings *settings;
struct scap_bpf_settings *settings;
enum ppm_event_type evt_type;
struct sys_stash_args args;
unsigned long *argsp;
@ -251,4 +251,10 @@ char kernel_ver[] __bpf_section("kernel_version") = UTS_RELEASE;
char __license[] __bpf_section("license") = "GPL";
char probe_ver[] __bpf_section("probe_version") = PROBE_VERSION;
char probe_ver[] __bpf_section("probe_version") = DRIVER_VERSION;
char probe_commit[] __bpf_section("build_commit") = DRIVER_COMMIT;
uint64_t probe_api_ver __bpf_section("api_version") = PPM_API_CURRENT_VERSION;
uint64_t probe_schema_ver __bpf_section("schema_version") = PPM_SCHEMA_CURRENT_VERSION;

View File

@ -54,7 +54,9 @@ static __always_inline int push_evt_frame(void *ctx,
}
if (data->state->tail_ctx.len > PERF_EVENT_MAX_SIZE)
return PPM_FAILURE_BUFFER_FULL;
{
return PPM_FAILURE_FRAME_SCRATCH_MAP_FULL;
}
fixup_evt_len(data->buf, data->state->tail_ctx.len);
@ -81,13 +83,16 @@ static __always_inline int push_evt_frame(void *ctx,
*
* Schedule a hotplug event on CPU 0
*/
struct sysdig_bpf_per_cpu_state *state = get_local_state(0);
struct scap_bpf_per_cpu_state *state = get_local_state(0);
if (!state)
return PPM_FAILURE_BUG;
state->hotplug_cpu = bpf_get_smp_processor_id();
bpf_printk("detected hotplug event, cpu=%d\n", state->hotplug_cpu);
} else if (res == -ENOSPC) {
bpf_printk("bpf_perf_buffer full\n");
return PPM_FAILURE_BUFFER_FULL;
} else if (res) {
bpf_printk("bpf_perf_event_output failed, res=%d\n", res);
return PPM_FAILURE_BUG;

View File

@ -131,8 +131,8 @@ struct sys_stash_args {
struct filler_data {
void *ctx;
struct sysdig_bpf_settings *settings;
struct sysdig_bpf_per_cpu_state *state;
struct scap_bpf_settings *settings;
struct scap_bpf_per_cpu_state *state;
char *tmp_scratch;
const struct ppm_event_info *evt;
const struct ppm_event_entry *filler_info;
@ -171,23 +171,23 @@ struct perf_event_sample {
#endif /* __KERNEL__ */
enum sysdig_map_types {
SYSDIG_PERF_MAP = 0,
SYSDIG_TAIL_MAP = 1,
SYSDIG_SYSCALL_CODE_ROUTING_TABLE = 2,
SYSDIG_SYSCALL_TABLE = 3,
SYSDIG_EVENT_INFO_TABLE = 4,
SYSDIG_FILLERS_TABLE = 5,
SYSDIG_FRAME_SCRATCH_MAP = 6,
SYSDIG_TMP_SCRATCH_MAP = 7,
SYSDIG_SETTINGS_MAP = 8,
SYSDIG_LOCAL_STATE_MAP = 9,
enum scap_map_types {
SCAP_PERF_MAP = 0,
SCAP_TAIL_MAP = 1,
SCAP_SYSCALL_CODE_ROUTING_TABLE = 2,
SCAP_SYSCALL_TABLE = 3,
SCAP_EVENT_INFO_TABLE = 4,
SCAP_FILLERS_TABLE = 5,
SCAP_FRAME_SCRATCH_MAP = 6,
SCAP_TMP_SCRATCH_MAP = 7,
SCAP_SETTINGS_MAP = 8,
SCAP_LOCAL_STATE_MAP = 9,
#ifndef BPF_SUPPORTS_RAW_TRACEPOINTS
SYSDIG_STASH_MAP = 10,
SCAP_STASH_MAP = 10,
#endif
};
struct sysdig_bpf_settings {
struct scap_bpf_settings {
uint64_t boot_time;
void *socket_file_ops;
uint32_t snaplen;
@ -212,10 +212,11 @@ struct tail_context {
int prev_res;
} __attribute__((packed));
struct sysdig_bpf_per_cpu_state {
struct scap_bpf_per_cpu_state {
struct tail_context tail_ctx;
unsigned long long n_evts;
unsigned long long n_drops_buffer;
unsigned long long n_drops_scratch_map;
unsigned long long n_drops_pf;
unsigned long long n_drops_bug;
unsigned int hotplug_cpu;

View File

@ -1,5 +1,5 @@
PACKAGE_NAME="@DRIVER_PACKAGE_NAME@"
PACKAGE_VERSION="@PROBE_VERSION@"
BUILT_MODULE_NAME[0]="@PROBE_NAME@"
PACKAGE_VERSION="@DRIVER_VERSION@"
BUILT_MODULE_NAME[0]="@DRIVER_NAME@"
DEST_MODULE_LOCATION[0]="/kernel/extra"
AUTOINSTALL="yes"

View File

@ -1,6 +1,6 @@
/*
Copyright (C) 2021 The Falco Authors.
Copyright (C) 2022 The Falco Authors.
This file is dual licensed under either the MIT or GPL 2. See MIT.txt
or GPL2.txt for full copies of the license.
@ -8,12 +8,26 @@ or GPL2.txt for full copies of the license.
*/
#pragma once
#define PROBE_VERSION "${PROBE_VERSION}"
/* taken from driver/API_VERSION */
#define PPM_API_CURRENT_VERSION_MAJOR ${PPM_API_CURRENT_VERSION_MAJOR}
#define PPM_API_CURRENT_VERSION_MINOR ${PPM_API_CURRENT_VERSION_MINOR}
#define PPM_API_CURRENT_VERSION_PATCH ${PPM_API_CURRENT_VERSION_PATCH}
#define PROBE_NAME "${PROBE_NAME}"
/* taken from driver/SCHEMA_VERSION */
#define PPM_SCHEMA_CURRENT_VERSION_MAJOR ${PPM_SCHEMA_CURRENT_VERSION_MAJOR}
#define PPM_SCHEMA_CURRENT_VERSION_MINOR ${PPM_SCHEMA_CURRENT_VERSION_MINOR}
#define PPM_SCHEMA_CURRENT_VERSION_PATCH ${PPM_SCHEMA_CURRENT_VERSION_PATCH}
#define PROBE_DEVICE_NAME "${PROBE_DEVICE_NAME}"
#include "ppm_api_version.h"
#define DRIVER_VERSION "${DRIVER_VERSION}"
#define DRIVER_NAME "${DRIVER_NAME}"
#define DRIVER_DEVICE_NAME "${DRIVER_DEVICE_NAME}"
#define DRIVER_COMMIT "${GIT_COMMIT}"
#ifndef KBUILD_MODNAME
#define KBUILD_MODNAME PROBE_NAME
#define KBUILD_MODNAME DRIVER_NAME
#endif

View File

@ -12,7 +12,7 @@ or GPL2.txt for full copies of the license.
const struct ppm_event_info g_event_info[PPM_EVENT_MAX] = {
/* PPME_GENERIC_E */{"syscall", EC_OTHER, EF_NONE, 2, {{"ID", PT_SYSCALLID, PF_DEC}, {"nativeID", PT_UINT16, PF_DEC} } },
/* PPME_GENERIC_X */{"syscall", EC_OTHER, EF_NONE, 1, {{"ID", PT_SYSCALLID, PF_DEC} } },
/* PPME_SYSCALL_OPEN_E */{"open", EC_FILE, EF_CREATES_FD | EF_MODIFIES_STATE, 0},
/* PPME_SYSCALL_OPEN_E */{"open", EC_FILE, EF_CREATES_FD | EF_MODIFIES_STATE, 3, {{"name", PT_FSPATH, PF_NA}, {"flags", PT_FLAGS32, PF_HEX, file_flags}, {"mode", PT_UINT32, PF_OCT} } },
/* PPME_SYSCALL_OPEN_X */{"open", EC_FILE, EF_CREATES_FD | EF_MODIFIES_STATE, 5, {{"fd", PT_FD, PF_DEC}, {"name", PT_FSPATH, PF_NA}, {"flags", PT_FLAGS32, PF_HEX, file_flags}, {"mode", PT_UINT32, PF_OCT}, {"dev", PT_UINT32, PF_HEX} } },
/* PPME_SYSCALL_CLOSE_E */{"close", EC_IO_OTHER, EF_DESTROYS_FD | EF_USES_FD | EF_MODIFIES_STATE | EF_DROP_SIMPLE_CONS, 1, {{"fd", PT_FD, PF_DEC} } },
/* PPME_SYSCALL_CLOSE_X */{"close", EC_IO_OTHER, EF_DESTROYS_FD | EF_USES_FD | EF_MODIFIES_STATE | EF_DROP_SIMPLE_CONS, 1, {{"res", PT_ERRNO, PF_DEC} } },
@ -24,15 +24,15 @@ const struct ppm_event_info g_event_info[PPM_EVENT_MAX] = {
/* PPME_SYSCALL_BRK_1_X */{"brk", EC_MEMORY, EF_OLD_VERSION, 1, {{"res", PT_UINT64, PF_HEX} } },
/* PPME_SYSCALL_EXECVE_8_E */{"execve", EC_PROCESS, EF_MODIFIES_STATE | EF_OLD_VERSION, 0},
/* PPME_SYSCALL_EXECVE_8_X */{"execve", EC_PROCESS, EF_MODIFIES_STATE | EF_OLD_VERSION, 8, {{"res", PT_ERRNO, PF_DEC}, {"exe", PT_CHARBUF, PF_NA}, {"args", PT_BYTEBUF, PF_NA}, {"tid", PT_PID, PF_DEC}, {"pid", PT_PID, PF_DEC}, {"ptid", PT_PID, PF_DEC}, {"cwd", PT_CHARBUF, PF_NA}, {"fdlimit", PT_UINT64, PF_DEC} } },
/* PPME_CLONE_11_E */{"clone", EC_PROCESS, EF_MODIFIES_STATE | EF_OLD_VERSION, 0},
/* PPME_CLONE_11_X */{"clone", EC_PROCESS, EF_MODIFIES_STATE | EF_OLD_VERSION, 11, {{"res", PT_PID, PF_DEC}, {"exe", PT_CHARBUF, PF_NA}, {"args", PT_BYTEBUF, PF_NA}, {"tid", PT_PID, PF_DEC}, {"pid", PT_PID, PF_DEC}, {"ptid", PT_PID, PF_DEC}, {"cwd", PT_CHARBUF, PF_NA}, {"fdlimit", PT_INT64, PF_DEC}, {"flags", PT_FLAGS32, PF_HEX, clone_flags}, {"uid", PT_UINT32, PF_DEC}, {"gid", PT_UINT32, PF_DEC} } },
/* PPME_SYSCALL_CLONE_11_E */{"clone", EC_PROCESS, EF_MODIFIES_STATE | EF_OLD_VERSION, 0},
/* PPME_SYSCALL_CLONE_11_X */{"clone", EC_PROCESS, EF_MODIFIES_STATE | EF_OLD_VERSION, 11, {{"res", PT_PID, PF_DEC}, {"exe", PT_CHARBUF, PF_NA}, {"args", PT_BYTEBUF, PF_NA}, {"tid", PT_PID, PF_DEC}, {"pid", PT_PID, PF_DEC}, {"ptid", PT_PID, PF_DEC}, {"cwd", PT_CHARBUF, PF_NA}, {"fdlimit", PT_INT64, PF_DEC}, {"flags", PT_FLAGS32, PF_HEX, clone_flags}, {"uid", PT_UINT32, PF_DEC}, {"gid", PT_UINT32, PF_DEC} } },
/* PPME_PROCEXIT_E */{"procexit", EC_PROCESS, EF_MODIFIES_STATE | EF_OLD_VERSION, 0},
/* PPME_NA1 */{"NA1", EC_PROCESS, EF_UNUSED, 0},
/* PPME_SOCKET_SOCKET_E */{"socket", EC_NET, EF_CREATES_FD | EF_MODIFIES_STATE, 3, {{"domain", PT_FLAGS32, PF_DEC, socket_families}, {"type", PT_UINT32, PF_DEC}, {"proto", PT_UINT32, PF_DEC} } },
/* PPME_SOCKET_SOCKET_X */{"socket", EC_NET, EF_CREATES_FD | EF_MODIFIES_STATE, 1, {{"fd", PT_FD, PF_DEC} } },
/* PPME_SOCKET_BIND_E */{"bind", EC_NET, EF_USES_FD | EF_MODIFIES_STATE, 1, {{"fd", PT_FD, PF_DEC} } },
/* PPME_SOCKET_BIND_X */{"bind", EC_NET, EF_USES_FD | EF_MODIFIES_STATE, 2, {{"res", PT_ERRNO, PF_DEC}, {"addr", PT_SOCKADDR, PF_NA} } },
/* PPME_SOCKET_CONNECT_E */{"connect", EC_NET, EF_USES_FD | EF_MODIFIES_STATE, 1, {{"fd", PT_FD, PF_DEC} } },
/* PPME_SOCKET_CONNECT_E */{"connect", EC_NET, EF_USES_FD | EF_MODIFIES_STATE, 2, {{"fd", PT_FD, PF_DEC}, {"addr", PT_SOCKADDR, PF_NA} } },
/* PPME_SOCKET_CONNECT_X */{"connect", EC_NET, EF_USES_FD | EF_MODIFIES_STATE, 2, {{"res", PT_ERRNO, PF_DEC}, {"tuple", PT_SOCKTUPLE, PF_NA} } },
/* PPME_SOCKET_LISTEN_E */{"listen", EC_NET, EF_USES_FD, 2, {{"fd", PT_FD, PF_DEC}, {"backlog", PT_UINT32, PF_DEC} } },
/* PPME_SOCKET_LISTEN_X */{"listen", EC_NET, EF_USES_FD, 1, {{"res", PT_ERRNO, PF_DEC} } },
@ -68,7 +68,7 @@ const struct ppm_event_info g_event_info[PPM_EVENT_MAX] = {
/* PPME_SOCKET_RECVMMSG_X */{"recvmmsg", EC_IO_READ, EF_DROP_SIMPLE_CONS, 0},
/* PPME_SOCKET_ACCEPT4_E */{"accept", EC_NET, EF_CREATES_FD | EF_MODIFIES_STATE | EF_OLD_VERSION, 1, {{"flags", PT_INT32, PF_HEX} } },
/* PPME_SOCKET_ACCEPT4_X */{"accept", EC_NET, EF_CREATES_FD | EF_MODIFIES_STATE | EF_OLD_VERSION, 3, {{"fd", PT_FD, PF_DEC}, {"tuple", PT_SOCKTUPLE, PF_NA}, {"queuepct", PT_UINT8, PF_DEC} } },
/* PPME_SYSCALL_CREAT_E */{"creat", EC_FILE, EF_CREATES_FD | EF_MODIFIES_STATE, 0},
/* PPME_SYSCALL_CREAT_E */{"creat", EC_FILE, EF_CREATES_FD | EF_MODIFIES_STATE, 2, {{"name", PT_FSPATH, PF_NA}, {"mode", PT_UINT32, PF_OCT} } },
/* PPME_SYSCALL_CREAT_X */{"creat", EC_FILE, EF_CREATES_FD | EF_MODIFIES_STATE, 4, {{"fd", PT_FD, PF_DEC}, {"name", PT_FSPATH, PF_NA}, {"mode", PT_UINT32, PF_OCT}, {"dev", PT_UINT32, PF_HEX} } },
/* PPME_SOCKET_PIPE_E */{"pipe", EC_IPC, EF_CREATES_FD | EF_MODIFIES_STATE, 0},
/* PPME_SOCKET_PIPE_X */{"pipe", EC_IPC, EF_CREATES_FD | EF_MODIFIES_STATE, 4, {{"res", PT_ERRNO, PF_DEC}, {"fd1", PT_FD, PF_DEC}, {"fd2", PT_FD, PF_DEC}, {"ino", PT_UINT64, PF_DEC} } },
@ -168,8 +168,8 @@ const struct ppm_event_info g_event_info[PPM_EVENT_MAX] = {
/* PPME_SCHEDSWITCH_6_X */{"NA2", EC_SCHEDULER, EF_UNUSED, 0},
/* PPME_SYSCALL_EXECVE_13_E */{"execve", EC_PROCESS, EF_MODIFIES_STATE | EF_OLD_VERSION, 0},
/* PPME_SYSCALL_EXECVE_13_X */{"execve", EC_PROCESS, EF_MODIFIES_STATE | EF_OLD_VERSION, 13, {{"res", PT_ERRNO, PF_DEC}, {"exe", PT_CHARBUF, PF_NA}, {"args", PT_BYTEBUF, PF_NA}, {"tid", PT_PID, PF_DEC}, {"pid", PT_PID, PF_DEC}, {"ptid", PT_PID, PF_DEC}, {"cwd", PT_CHARBUF, PF_NA}, {"fdlimit", PT_UINT64, PF_DEC}, {"pgft_maj", PT_UINT64, PF_DEC}, {"pgft_min", PT_UINT64, PF_DEC}, {"vm_size", PT_UINT32, PF_DEC}, {"vm_rss", PT_UINT32, PF_DEC}, {"vm_swap", PT_UINT32, PF_DEC} } },
/* PPME_CLONE_16_E */{"clone", EC_PROCESS, EF_MODIFIES_STATE | EF_OLD_VERSION, 0},
/* PPME_CLONE_16_X */{"clone", EC_PROCESS, EF_MODIFIES_STATE | EF_OLD_VERSION, 16, {{"res", PT_PID, PF_DEC}, {"exe", PT_CHARBUF, PF_NA}, {"args", PT_BYTEBUF, PF_NA}, {"tid", PT_PID, PF_DEC}, {"pid", PT_PID, PF_DEC}, {"ptid", PT_PID, PF_DEC}, {"cwd", PT_CHARBUF, PF_NA}, {"fdlimit", PT_INT64, PF_DEC}, {"pgft_maj", PT_UINT64, PF_DEC}, {"pgft_min", PT_UINT64, PF_DEC}, {"vm_size", PT_UINT32, PF_DEC}, {"vm_rss", PT_UINT32, PF_DEC}, {"vm_swap", PT_UINT32, PF_DEC}, {"flags", PT_FLAGS32, PF_HEX, clone_flags}, {"uid", PT_UINT32, PF_DEC}, {"gid", PT_UINT32, PF_DEC} } },
/* PPME_SYSCALL_CLONE_16_E */{"clone", EC_PROCESS, EF_MODIFIES_STATE | EF_OLD_VERSION, 0},
/* PPME_SYSCALL_CLONE_16_X */{"clone", EC_PROCESS, EF_MODIFIES_STATE | EF_OLD_VERSION, 16, {{"res", PT_PID, PF_DEC}, {"exe", PT_CHARBUF, PF_NA}, {"args", PT_BYTEBUF, PF_NA}, {"tid", PT_PID, PF_DEC}, {"pid", PT_PID, PF_DEC}, {"ptid", PT_PID, PF_DEC}, {"cwd", PT_CHARBUF, PF_NA}, {"fdlimit", PT_INT64, PF_DEC}, {"pgft_maj", PT_UINT64, PF_DEC}, {"pgft_min", PT_UINT64, PF_DEC}, {"vm_size", PT_UINT32, PF_DEC}, {"vm_rss", PT_UINT32, PF_DEC}, {"vm_swap", PT_UINT32, PF_DEC}, {"flags", PT_FLAGS32, PF_HEX, clone_flags}, {"uid", PT_UINT32, PF_DEC}, {"gid", PT_UINT32, PF_DEC} } },
/* PPME_SYSCALL_BRK_4_E */{"brk", EC_MEMORY, EF_DROP_SIMPLE_CONS, 1, {{"addr", PT_UINT64, PF_HEX} } },
/* PPME_SYSCALL_BRK_4_X */{"brk", EC_MEMORY, EF_DROP_SIMPLE_CONS, 4, {{"res", PT_UINT64, PF_HEX}, {"vm_size", PT_UINT32, PF_DEC}, {"vm_rss", PT_UINT32, PF_DEC}, {"vm_swap", PT_UINT32, PF_DEC} } },
/* PPME_SYSCALL_MMAP_E */{"mmap", EC_MEMORY, EF_DROP_SIMPLE_CONS, 6, {{"addr", PT_UINT64, PF_HEX}, {"length", PT_UINT64, PF_DEC}, {"prot", PT_FLAGS32, PF_HEX, prot_flags}, {"flags", PT_FLAGS32, PF_HEX, mmap_flags}, {"fd", PT_FD, PF_DEC}, {"offset", PT_UINT64, PF_DEC} } },
@ -228,14 +228,14 @@ const struct ppm_event_info g_event_info[PPM_EVENT_MAX] = {
/* PPME_SYSCALL_GETRESGID_X */ {"getresgid", EC_USER, EF_DROP_SIMPLE_CONS, 4, {{"res", PT_ERRNO, PF_DEC}, {"rgid", PT_GID, PF_DEC }, {"egid", PT_GID, PF_DEC }, {"sgid", PT_GID, PF_DEC } } },
/* PPME_SYSCALL_EXECVE_15_E */{"execve", EC_PROCESS, EF_MODIFIES_STATE | EF_OLD_VERSION, 0},
/* PPME_SYSCALL_EXECVE_15_X */{"execve", EC_PROCESS, EF_MODIFIES_STATE | EF_OLD_VERSION, 15, {{"res", PT_ERRNO, PF_DEC}, {"exe", PT_CHARBUF, PF_NA}, {"args", PT_BYTEBUF, PF_NA}, {"tid", PT_PID, PF_DEC}, {"pid", PT_PID, PF_DEC}, {"ptid", PT_PID, PF_DEC}, {"cwd", PT_CHARBUF, PF_NA}, {"fdlimit", PT_UINT64, PF_DEC}, {"pgft_maj", PT_UINT64, PF_DEC}, {"pgft_min", PT_UINT64, PF_DEC}, {"vm_size", PT_UINT32, PF_DEC}, {"vm_rss", PT_UINT32, PF_DEC}, {"vm_swap", PT_UINT32, PF_DEC}, {"comm", PT_CHARBUF, PF_NA}, {"env", PT_BYTEBUF, PF_NA} } },
/* PPME_CLONE_17_E */{"clone", EC_PROCESS, EF_MODIFIES_STATE | EF_OLD_VERSION, 0},
/* PPME_CLONE_17_X */{"clone", EC_PROCESS, EF_MODIFIES_STATE | EF_OLD_VERSION, 17, {{"res", PT_PID, PF_DEC}, {"exe", PT_CHARBUF, PF_NA}, {"args", PT_BYTEBUF, PF_NA}, {"tid", PT_PID, PF_DEC}, {"pid", PT_PID, PF_DEC}, {"ptid", PT_PID, PF_DEC}, {"cwd", PT_CHARBUF, PF_NA}, {"fdlimit", PT_INT64, PF_DEC}, {"pgft_maj", PT_UINT64, PF_DEC}, {"pgft_min", PT_UINT64, PF_DEC}, {"vm_size", PT_UINT32, PF_DEC}, {"vm_rss", PT_UINT32, PF_DEC}, {"vm_swap", PT_UINT32, PF_DEC}, {"comm", PT_CHARBUF, PF_NA}, {"flags", PT_FLAGS32, PF_HEX, clone_flags}, {"uid", PT_UINT32, PF_DEC}, {"gid", PT_UINT32, PF_DEC} } },
/* PPME_SYSCALL_CLONE_17_E */{"clone", EC_PROCESS, EF_MODIFIES_STATE | EF_OLD_VERSION, 0},
/* PPME_SYSCALL_CLONE_17_X */{"clone", EC_PROCESS, EF_MODIFIES_STATE | EF_OLD_VERSION, 17, {{"res", PT_PID, PF_DEC}, {"exe", PT_CHARBUF, PF_NA}, {"args", PT_BYTEBUF, PF_NA}, {"tid", PT_PID, PF_DEC}, {"pid", PT_PID, PF_DEC}, {"ptid", PT_PID, PF_DEC}, {"cwd", PT_CHARBUF, PF_NA}, {"fdlimit", PT_INT64, PF_DEC}, {"pgft_maj", PT_UINT64, PF_DEC}, {"pgft_min", PT_UINT64, PF_DEC}, {"vm_size", PT_UINT32, PF_DEC}, {"vm_rss", PT_UINT32, PF_DEC}, {"vm_swap", PT_UINT32, PF_DEC}, {"comm", PT_CHARBUF, PF_NA}, {"flags", PT_FLAGS32, PF_HEX, clone_flags}, {"uid", PT_UINT32, PF_DEC}, {"gid", PT_UINT32, PF_DEC} } },
/* PPME_SYSCALL_FORK_17_E */{"fork", EC_PROCESS, EF_MODIFIES_STATE | EF_OLD_VERSION, 0},
/* PPME_SYSCALL_FORK_17_X */{"fork", EC_PROCESS, EF_MODIFIES_STATE | EF_OLD_VERSION, 17, {{"res", PT_PID, PF_DEC}, {"exe", PT_CHARBUF, PF_NA}, {"args", PT_BYTEBUF, PF_NA}, {"tid", PT_PID, PF_DEC}, {"pid", PT_PID, PF_DEC}, {"ptid", PT_PID, PF_DEC}, {"cwd", PT_CHARBUF, PF_NA}, {"fdlimit", PT_INT64, PF_DEC}, {"pgft_maj", PT_UINT64, PF_DEC}, {"pgft_min", PT_UINT64, PF_DEC}, {"vm_size", PT_UINT32, PF_DEC}, {"vm_rss", PT_UINT32, PF_DEC}, {"vm_swap", PT_UINT32, PF_DEC}, {"comm", PT_CHARBUF, PF_NA}, {"flags", PT_FLAGS32, PF_HEX, clone_flags}, {"uid", PT_UINT32, PF_DEC}, {"gid", PT_UINT32, PF_DEC} } },
/* PPME_SYSCALL_VFORK_17_E */{"vfork", EC_PROCESS, EF_MODIFIES_STATE | EF_OLD_VERSION, 0},
/* PPME_SYSCALL_VFORK_17_X */{"vfork", EC_PROCESS, EF_MODIFIES_STATE | EF_OLD_VERSION, 17, {{"res", PT_PID, PF_DEC}, {"exe", PT_CHARBUF, PF_NA}, {"args", PT_BYTEBUF, PF_NA}, {"tid", PT_PID, PF_DEC}, {"pid", PT_PID, PF_DEC}, {"ptid", PT_PID, PF_DEC}, {"cwd", PT_CHARBUF, PF_NA}, {"fdlimit", PT_INT64, PF_DEC}, {"pgft_maj", PT_UINT64, PF_DEC}, {"pgft_min", PT_UINT64, PF_DEC}, {"vm_size", PT_UINT32, PF_DEC}, {"vm_rss", PT_UINT32, PF_DEC}, {"vm_swap", PT_UINT32, PF_DEC}, {"comm", PT_CHARBUF, PF_NA}, {"flags", PT_FLAGS32, PF_HEX, clone_flags}, {"uid", PT_UINT32, PF_DEC}, {"gid", PT_UINT32, PF_DEC} } },
/* PPME_CLONE_20_E */{"clone", EC_PROCESS, EF_MODIFIES_STATE, 0},
/* PPME_CLONE_20_X */{"clone", EC_PROCESS, EF_MODIFIES_STATE, 20, {{"res", PT_PID, PF_DEC}, {"exe", PT_CHARBUF, PF_NA}, {"args", PT_BYTEBUF, PF_NA}, {"tid", PT_PID, PF_DEC}, {"pid", PT_PID, PF_DEC}, {"ptid", PT_PID, PF_DEC}, {"cwd", PT_CHARBUF, PF_NA}, {"fdlimit", PT_INT64, PF_DEC}, {"pgft_maj", PT_UINT64, PF_DEC}, {"pgft_min", PT_UINT64, PF_DEC}, {"vm_size", PT_UINT32, PF_DEC}, {"vm_rss", PT_UINT32, PF_DEC}, {"vm_swap", PT_UINT32, PF_DEC}, {"comm", PT_CHARBUF, PF_NA}, {"cgroups", PT_BYTEBUF, PF_NA}, {"flags", PT_FLAGS32, PF_HEX, clone_flags}, {"uid", PT_UINT32, PF_DEC}, {"gid", PT_UINT32, PF_DEC}, {"vtid", PT_PID, PF_DEC}, {"vpid", PT_PID, PF_DEC} } },
/* PPME_SYSCALL_CLONE_20_E */{"clone", EC_PROCESS, EF_MODIFIES_STATE, 0},
/* PPME_SYSCALL_CLONE_20_X */{"clone", EC_PROCESS, EF_MODIFIES_STATE, 20, {{"res", PT_PID, PF_DEC}, {"exe", PT_CHARBUF, PF_NA}, {"args", PT_BYTEBUF, PF_NA}, {"tid", PT_PID, PF_DEC}, {"pid", PT_PID, PF_DEC}, {"ptid", PT_PID, PF_DEC}, {"cwd", PT_CHARBUF, PF_NA}, {"fdlimit", PT_INT64, PF_DEC}, {"pgft_maj", PT_UINT64, PF_DEC}, {"pgft_min", PT_UINT64, PF_DEC}, {"vm_size", PT_UINT32, PF_DEC}, {"vm_rss", PT_UINT32, PF_DEC}, {"vm_swap", PT_UINT32, PF_DEC}, {"comm", PT_CHARBUF, PF_NA}, {"cgroups", PT_BYTEBUF, PF_NA}, {"flags", PT_FLAGS32, PF_HEX, clone_flags}, {"uid", PT_UINT32, PF_DEC}, {"gid", PT_UINT32, PF_DEC}, {"vtid", PT_PID, PF_DEC}, {"vpid", PT_PID, PF_DEC} } },
/* PPME_SYSCALL_FORK_20_E */{"fork", EC_PROCESS, EF_MODIFIES_STATE, 0},
/* PPME_SYSCALL_FORK_20_X */{"fork", EC_PROCESS, EF_MODIFIES_STATE, 20, {{"res", PT_PID, PF_DEC}, {"exe", PT_CHARBUF, PF_NA}, {"args", PT_BYTEBUF, PF_NA}, {"tid", PT_PID, PF_DEC}, {"pid", PT_PID, PF_DEC}, {"ptid", PT_PID, PF_DEC}, {"cwd", PT_CHARBUF, PF_NA}, {"fdlimit", PT_INT64, PF_DEC}, {"pgft_maj", PT_UINT64, PF_DEC}, {"pgft_min", PT_UINT64, PF_DEC}, {"vm_size", PT_UINT32, PF_DEC}, {"vm_rss", PT_UINT32, PF_DEC}, {"vm_swap", PT_UINT32, PF_DEC}, {"comm", PT_CHARBUF, PF_NA}, {"cgroups", PT_BYTEBUF, PF_NA}, {"flags", PT_FLAGS32, PF_HEX, clone_flags}, {"uid", PT_UINT32, PF_DEC}, {"gid", PT_UINT32, PF_DEC}, {"vtid", PT_PID, PF_DEC}, {"vpid", PT_PID, PF_DEC} } },
/* PPME_SYSCALL_VFORK_20_E */{"vfork", EC_PROCESS, EF_MODIFIES_STATE, 0},
@ -318,7 +318,7 @@ const struct ppm_event_info g_event_info[PPM_EVENT_MAX] = {
/* PPME_SYSCALL_UNLINKAT_2_X */{"unlinkat", EC_FILE, EF_NONE, 4, {{"res", PT_ERRNO, PF_DEC}, {"dirfd", PT_FD, PF_DEC}, {"name", PT_FSRELPATH, PF_NA, DIRFD_PARAM(1)}, {"flags", PT_FLAGS32, PF_HEX, unlinkat_flags} } },
/* PPME_SYSCALL_MKDIRAT_E */{"mkdirat", EC_FILE, EF_NONE, 0},
/* PPME_SYSCALL_MKDIRAT_X */{"mkdirat", EC_FILE, EF_NONE, 4, {{"res", PT_ERRNO, PF_DEC}, {"dirfd", PT_FD, PF_DEC}, {"path", PT_FSRELPATH, PF_NA, DIRFD_PARAM(1)}, {"mode", PT_UINT32, PF_HEX} } },
/* PPME_SYSCALL_OPENAT_2_E */{"openat", EC_FILE, EF_CREATES_FD | EF_MODIFIES_STATE, 0},
/* PPME_SYSCALL_OPENAT_2_E */{"openat", EC_FILE, EF_CREATES_FD | EF_MODIFIES_STATE, 4, {{"dirfd", PT_FD, PF_DEC}, {"name", PT_FSRELPATH, PF_NA, DIRFD_PARAM(1)}, {"flags", PT_FLAGS32, PF_HEX, file_flags}, {"mode", PT_UINT32, PF_OCT} } },
/* PPME_SYSCALL_OPENAT_2_X */{"openat", EC_FILE, EF_CREATES_FD | EF_MODIFIES_STATE, 6, {{"fd", PT_FD, PF_DEC}, {"dirfd", PT_FD, PF_DEC}, {"name", PT_FSRELPATH, PF_NA, DIRFD_PARAM(1)}, {"flags", PT_FLAGS32, PF_HEX, file_flags}, {"mode", PT_UINT32, PF_OCT}, {"dev", PT_UINT32, PF_HEX} } },
/* PPME_SYSCALL_LINK_2_E */{"link", EC_FILE, EF_NONE, 0},
/* PPME_SYSCALL_LINK_2_X */{"link", EC_FILE, EF_NONE, 3, {{"res", PT_ERRNO, PF_DEC}, {"oldpath", PT_FSPATH, PF_NA}, {"newpath", PT_FSPATH, PF_NA} } },
@ -338,12 +338,16 @@ const struct ppm_event_info g_event_info[PPM_EVENT_MAX] = {
/* PPME_NA1 */{"pluginevent", EC_OTHER, EF_UNUSED, 0},
/* PPME_CONTAINER_JSON_2_E */{"container", EC_PROCESS, EF_MODIFIES_STATE | EF_LARGE_PAYLOAD, 1, {{"json", PT_CHARBUF, PF_NA} } },
/* PPME_CONTAINER_JSON_2_X */{"container", EC_PROCESS, EF_UNUSED, 0},
/* PPME_SYSCALL_OPENAT2_E */{"openat2", EC_FILE, EF_CREATES_FD | EF_MODIFIES_STATE, 0},
/* PPME_SYSCALL_OPENAT2_E */{"openat2", EC_FILE, EF_CREATES_FD | EF_MODIFIES_STATE, 5, {{"dirfd", PT_FD, PF_DEC}, {"name", PT_FSRELPATH, PF_NA, DIRFD_PARAM(1)}, {"flags", PT_FLAGS32, PF_HEX, file_flags}, {"mode", PT_UINT32, PF_OCT}, {"resolve", PT_FLAGS32, PF_HEX, openat2_flags} } },
/* PPME_SYSCALL_OPENAT2_X */{"openat2", EC_FILE, EF_CREATES_FD | EF_MODIFIES_STATE, 6, {{"fd", PT_FD, PF_DEC}, {"dirfd", PT_FD, PF_DEC}, {"name", PT_FSRELPATH, PF_NA, DIRFD_PARAM(1)}, {"flags", PT_FLAGS32, PF_HEX, file_flags}, {"mode", PT_UINT32, PF_OCT}, {"resolve", PT_FLAGS32, PF_HEX, openat2_flags} } },
/* PPME_SYSCALL_MPROTECT_E */{"mprotect", EC_MEMORY, EF_DROP_SIMPLE_CONS, 3, {{"addr", PT_UINT64, PF_HEX}, {"length", PT_UINT64, PF_DEC}, {"prot", PT_FLAGS32, PF_HEX, prot_flags} } },
/* PPME_SYSCALL_MPROTECT_X */{"mprotect", EC_MEMORY, EF_DROP_SIMPLE_CONS, 1, {{"res", PT_ERRNO, PF_DEC} } },
/* PPME_SYSCALL_EXECVEAT_E */{"execveat", EC_PROCESS, EF_MODIFIES_STATE, 3, {{"dirfd", PT_FD, PF_DEC}, {"pathname", PT_FSRELPATH, PF_NA, DIRFD_PARAM(0)}, {"flags", PT_FLAGS32, PF_HEX, execveat_flags} } },
/* PPME_SYSCALL_EXECVEAT_X */{"execveat", EC_PROCESS, EF_MODIFIES_STATE, 19, {{"res", PT_ERRNO, PF_DEC}, {"exe", PT_CHARBUF, PF_NA}, {"args", PT_BYTEBUF, PF_NA}, {"tid", PT_PID, PF_DEC}, {"pid", PT_PID, PF_DEC}, {"ptid", PT_PID, PF_DEC}, {"cwd", PT_CHARBUF, PF_NA}, {"fdlimit", PT_UINT64, PF_DEC}, {"pgft_maj", PT_UINT64, PF_DEC}, {"pgft_min", PT_UINT64, PF_DEC}, {"vm_size", PT_UINT32, PF_DEC}, {"vm_rss", PT_UINT32, PF_DEC}, {"vm_swap", PT_UINT32, PF_DEC}, {"comm", PT_CHARBUF, PF_NA}, {"cgroups", PT_BYTEBUF, PF_NA}, {"env", PT_BYTEBUF, PF_NA}, {"tty", PT_INT32, PF_DEC}, {"pgid", PT_PID, PF_DEC}, {"loginuid", PT_INT32, PF_DEC} } },
/* PPME_SYSCALL_EXECVEAT_X */{"execveat", EC_PROCESS, EF_MODIFIES_STATE, 20, {{"res", PT_ERRNO, PF_DEC}, {"exe", PT_CHARBUF, PF_NA}, {"args", PT_BYTEBUF, PF_NA}, {"tid", PT_PID, PF_DEC}, {"pid", PT_PID, PF_DEC}, {"ptid", PT_PID, PF_DEC}, {"cwd", PT_CHARBUF, PF_NA}, {"fdlimit", PT_UINT64, PF_DEC}, {"pgft_maj", PT_UINT64, PF_DEC}, {"pgft_min", PT_UINT64, PF_DEC}, {"vm_size", PT_UINT32, PF_DEC}, {"vm_rss", PT_UINT32, PF_DEC}, {"vm_swap", PT_UINT32, PF_DEC}, {"comm", PT_CHARBUF, PF_NA}, {"cgroups", PT_BYTEBUF, PF_NA}, {"env", PT_BYTEBUF, PF_NA}, {"tty", PT_INT32, PF_DEC}, {"pgid", PT_PID, PF_DEC}, {"loginuid", PT_INT32, PF_DEC}, {"flags", PT_FLAGS32, PF_HEX, execve_flags} } },
/* PPME_SYSCALL_COPY_FILE_RANGE_E */{"copy_file_range", EC_FILE, EF_USES_FD | EF_READS_FROM_FD | EF_WRITES_TO_FD, 3, {{"fdin", PT_FD, PF_DEC}, {"offin", PT_UINT64, PF_DEC}, {"len", PT_UINT64, PF_DEC} } },
/* PPME_SYSCALL_COPY_FILE_RANGE_X */{"copy_file_range", EC_FILE, EF_USES_FD | EF_READS_FROM_FD | EF_WRITES_TO_FD, 3, {{"res", PT_ERRNO, PF_DEC}, {"fdout", PT_FD, PF_DEC}, {"offout", PT_UINT64, PF_DEC} } },
/* PPME_SYSCALL_CLONE3_E */{"clone3", EC_PROCESS, EF_MODIFIES_STATE, 0},
/* PPME_SYSCALL_CLONE3_X */{"clone3", EC_PROCESS, EF_MODIFIES_STATE, 20, {{"res", PT_PID, PF_DEC}, {"exe", PT_CHARBUF, PF_NA}, {"args", PT_BYTEBUF, PF_NA}, {"tid", PT_PID, PF_DEC}, {"pid", PT_PID, PF_DEC}, {"ptid", PT_PID, PF_DEC}, {"cwd", PT_CHARBUF, PF_NA}, {"fdlimit", PT_INT64, PF_DEC}, {"pgft_maj", PT_UINT64, PF_DEC}, {"pgft_min", PT_UINT64, PF_DEC}, {"vm_size", PT_UINT32, PF_DEC}, {"vm_rss", PT_UINT32, PF_DEC}, {"vm_swap", PT_UINT32, PF_DEC}, {"comm", PT_CHARBUF, PF_NA}, {"cgroups", PT_BYTEBUF, PF_NA}, {"flags", PT_FLAGS32, PF_HEX, clone_flags}, {"uid", PT_UINT32, PF_DEC}, {"gid", PT_UINT32, PF_DEC}, {"vtid", PT_PID, PF_DEC}, {"vpid", PT_PID, PF_DEC} } },
/* NB: Starting from scap version 1.2, event types will no longer be changed when an event is modified, and the only kind of change permitted for pre-existent events is adding parameters.
* New event types are allowed only for new syscalls or new internal events.
* The number of parameters can be used to differentiate between event versions.

View File

@ -30,7 +30,7 @@ or GPL2.txt for full copies of the license.
const struct ppm_event_entry g_ppm_events[PPM_EVENT_MAX] = {
[PPME_GENERIC_E] = {FILLER_REF(sys_generic)},
[PPME_GENERIC_X] = {FILLER_REF(sys_generic)},
[PPME_SYSCALL_OPEN_E] = {FILLER_REF(sys_empty)},
[PPME_SYSCALL_OPEN_E] = {FILLER_REF(sys_open_e)},
[PPME_SYSCALL_OPEN_X] = {FILLER_REF(sys_open_x)},
[PPME_SYSCALL_CLOSE_E] = {FILLER_REF(sys_single)},
[PPME_SYSCALL_CLOSE_X] = {FILLER_REF(sys_single_x)},
@ -43,7 +43,7 @@ const struct ppm_event_entry g_ppm_events[PPM_EVENT_MAX] = {
[PPME_SOCKET_SOCKET_X] = {FILLER_REF(sys_socket_x)},
[PPME_SOCKET_BIND_E] = {FILLER_REF(sys_autofill), 1, APT_SOCK, {{0} } },
[PPME_SOCKET_BIND_X] = {FILLER_REF(sys_socket_bind_x)},
[PPME_SOCKET_CONNECT_E] = {FILLER_REF(sys_autofill), 1, APT_SOCK, {{0} } },
[PPME_SOCKET_CONNECT_E] = {FILLER_REF(sys_connect_e)},
[PPME_SOCKET_CONNECT_X] = {FILLER_REF(sys_connect_x)},
[PPME_SOCKET_LISTEN_E] = {FILLER_REF(sys_autofill), 2, APT_SOCK, {{0}, {1} } },
[PPME_SOCKET_LISTEN_X] = {FILLER_REF(sys_single_x)},
@ -78,7 +78,7 @@ const struct ppm_event_entry g_ppm_events[PPM_EVENT_MAX] = {
[PPME_SOCKET_RECVMSG_X] = {FILLER_REF(sys_recvmsg_x)},
[PPME_SOCKET_RECVMMSG_E] = {FILLER_REF(sys_empty)},
[PPME_SOCKET_RECVMMSG_X] = {FILLER_REF(sys_empty)},
[PPME_SYSCALL_CREAT_E] = {FILLER_REF(sys_empty)},
[PPME_SYSCALL_CREAT_E] = {FILLER_REF(sys_creat_e)},
[PPME_SYSCALL_CREAT_X] = {FILLER_REF(sys_creat_x)},
[PPME_SYSCALL_PIPE_E] = {FILLER_REF(sys_empty)},
[PPME_SYSCALL_PIPE_X] = {FILLER_REF(sys_pipe_x)},
@ -291,7 +291,7 @@ const struct ppm_event_entry g_ppm_events[PPM_EVENT_MAX] = {
[PPME_SYSCALL_UNLINKAT_2_X] = {FILLER_REF(sys_unlinkat_x)},
[PPME_SYSCALL_MKDIRAT_E] = {FILLER_REF(sys_empty)},
[PPME_SYSCALL_MKDIRAT_X] = {FILLER_REF(sys_mkdirat_x)},
[PPME_SYSCALL_OPENAT_2_E] = {FILLER_REF(sys_empty)},
[PPME_SYSCALL_OPENAT_2_E] = {FILLER_REF(sys_openat_e)},
[PPME_SYSCALL_OPENAT_2_X] = {FILLER_REF(sys_openat_x)},
[PPME_SYSCALL_LINK_2_E] = {FILLER_REF(sys_empty)},
[PPME_SYSCALL_LINK_2_X] = {FILLER_REF(sys_autofill), 3, APT_REG, {{AF_ID_RETVAL}, {0}, {1} } },
@ -307,11 +307,15 @@ const struct ppm_event_entry g_ppm_events[PPM_EVENT_MAX] = {
[PPME_SYSCALL_RENAMEAT2_X] = {FILLER_REF(sys_renameat2_x)},
[PPME_SYSCALL_USERFAULTFD_E] = {FILLER_REF(sys_empty)},
[PPME_SYSCALL_USERFAULTFD_X] = {FILLER_REF(sys_autofill), 2, APT_REG, {{AF_ID_RETVAL}, {0} } },
[PPME_SYSCALL_OPENAT2_E] = {FILLER_REF(sys_empty)},
[PPME_SYSCALL_OPENAT2_E] = {FILLER_REF(sys_openat2_e)},
[PPME_SYSCALL_OPENAT2_X] = {FILLER_REF(sys_openat2_x)},
[PPME_SYSCALL_MPROTECT_E] = {FILLER_REF(sys_mprotect_e)},
[PPME_SYSCALL_MPROTECT_X] = {FILLER_REF(sys_mprotect_x)},
[PPME_SYSCALL_EXECVEAT_E] = {FILLER_REF(sys_execveat_e)},
[PPME_SYSCALL_EXECVEAT_X] = {FILLER_REF(proc_startupdate)},
[PPME_SYSCALL_COPY_FILE_RANGE_E] = {FILLER_REF(sys_copy_file_range_e)},
[PPME_SYSCALL_COPY_FILE_RANGE_X] = {FILLER_REF(sys_copy_file_range_x)},
[PPME_SYSCALL_CLONE3_E] = {FILLER_REF(sys_empty)},
[PPME_SYSCALL_CLONE3_X] = {FILLER_REF(proc_startupdate)},
#endif /* WDIG */
};

View File

@ -1,6 +1,6 @@
/*
Copyright (C) 2021 The Falco Authors.
Copyright (C) 2022 The Falco Authors.
This file is dual licensed under either the MIT or GPL 2. See MIT.txt
or GPL2.txt for full copies of the license.
@ -775,13 +775,25 @@ cleanup_ioctl_procinfo:
}
ret = 0;
goto cleanup_ioctl_nolock;
} else if (cmd == PPM_IOCTL_GET_PROBE_VERSION) {
if (copy_to_user((void *)arg, PROBE_VERSION, sizeof(PROBE_VERSION))) {
} else if (cmd == PPM_IOCTL_GET_DRIVER_VERSION) {
if (copy_to_user((void *)arg, DRIVER_VERSION, sizeof(DRIVER_VERSION))) {
ret = -EINVAL;
goto cleanup_ioctl_nolock;
}
ret = 0;
goto cleanup_ioctl_nolock;
} else if (cmd == PPM_IOCTL_GET_API_VERSION) {
unsigned long long __user *out = (unsigned long long __user *) arg;
ret = 0;
if(put_user(PPM_API_CURRENT_VERSION, out))
ret = -EINVAL;
goto cleanup_ioctl_nolock;
} else if (cmd == PPM_IOCTL_GET_SCHEMA_VERSION) {
unsigned long long __user *out = (unsigned long long __user *) arg;
ret = 0;
if(put_user(PPM_SCHEMA_CURRENT_VERSION, out))
ret = -EINVAL;
goto cleanup_ioctl_nolock;
}
mutex_lock(&g_consumer_mutex);
@ -2385,15 +2397,15 @@ static int do_cpu_callback(unsigned long cpu, long sd_action)
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0))
static int sysdig_cpu_online(unsigned int cpu)
static int scap_cpu_online(unsigned int cpu)
{
vpr_info("sysdig_cpu_online on cpu %d\n", cpu);
vpr_info("scap_cpu_online on cpu %d\n", cpu);
return do_cpu_callback(cpu, 1);
}
static int sysdig_cpu_offline(unsigned int cpu)
static int scap_cpu_offline(unsigned int cpu)
{
vpr_info("sysdig_cpu_offline on cpu %d\n", cpu);
vpr_info("scap_cpu_offline on cpu %d\n", cpu);
return do_cpu_callback(cpu, 2);
}
#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) */
@ -2435,7 +2447,7 @@ static struct notifier_block cpu_notifier = {
};
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) */
int sysdig_init(void)
int scap_init(void)
{
dev_t dev;
unsigned int cpu;
@ -2452,7 +2464,7 @@ int sysdig_init(void)
#else
struct class_device *device = NULL;
#endif
pr_info("driver loading, " PROBE_NAME " " PROBE_VERSION "\n");
pr_info("driver loading, " DRIVER_NAME " " DRIVER_VERSION "\n");
ret = get_tracepoint_handles();
if (ret < 0)
@ -2467,14 +2479,14 @@ int sysdig_init(void)
* Initialize the user I/O
* ( + 1 for sysdig-events)
*/
acrret = alloc_chrdev_region(&dev, 0, num_cpus + 1, PROBE_DEVICE_NAME);
acrret = alloc_chrdev_region(&dev, 0, num_cpus + 1, DRIVER_DEVICE_NAME);
if (acrret < 0) {
pr_err("could not allocate major number for %s\n", PROBE_DEVICE_NAME);
pr_err("could not allocate major number for %s\n", DRIVER_DEVICE_NAME);
ret = -ENOMEM;
goto init_module_err;
}
g_ppm_class = class_create(THIS_MODULE, PROBE_DEVICE_NAME);
g_ppm_class = class_create(THIS_MODULE, DRIVER_DEVICE_NAME);
if (IS_ERR(g_ppm_class)) {
pr_err("can't allocate device class\n");
ret = -EFAULT;
@ -2506,7 +2518,7 @@ int sysdig_init(void)
g_ppm_devs[j].dev = MKDEV(g_ppm_major, j);
if (cdev_add(&g_ppm_devs[j].cdev, g_ppm_devs[j].dev, 1) < 0) {
pr_err("could not allocate chrdev for %s\n", PROBE_DEVICE_NAME);
pr_err("could not allocate chrdev for %s\n", DRIVER_DEVICE_NAME);
ret = -EFAULT;
goto init_module_err;
}
@ -2519,11 +2531,11 @@ int sysdig_init(void)
g_ppm_class, NULL, /* no parent device */
g_ppm_devs[j].dev,
NULL, /* no additional data */
PROBE_DEVICE_NAME "%d",
DRIVER_DEVICE_NAME "%d",
j);
if (IS_ERR(device)) {
pr_err("error creating the device for %s\n", PROBE_DEVICE_NAME);
pr_err("error creating the device for %s\n", DRIVER_DEVICE_NAME);
cdev_del(&g_ppm_devs[j].cdev);
ret = -EFAULT;
goto init_module_err;
@ -2550,9 +2562,9 @@ int sysdig_init(void)
*/
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0))
hp_ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
"sysdig/probe:online",
sysdig_cpu_online,
sysdig_cpu_offline);
DRIVER_NAME "/driver:online",
scap_cpu_online,
scap_cpu_offline);
if (hp_ret <= 0) {
pr_err("error registering cpu hotplug callback\n");
ret = hp_ret;
@ -2593,7 +2605,7 @@ init_module_err:
return ret;
}
void sysdig_exit(void)
void scap_exit(void)
{
int j;
@ -2629,9 +2641,12 @@ void sysdig_exit(void)
#endif
}
module_init(sysdig_init);
module_exit(sysdig_exit);
MODULE_VERSION(PROBE_VERSION);
module_init(scap_init);
module_exit(scap_exit);
MODULE_VERSION(DRIVER_VERSION);
MODULE_INFO(build_commit, DRIVER_COMMIT);
MODULE_INFO(api_version, PPM_API_CURRENT_VERSION_STRING);
MODULE_INFO(schema_version, PPM_SCHEMA_CURRENT_VERSION_STRING);
module_param(max_consumers, uint, 0444);
MODULE_PARM_DESC(max_consumers, "Maximum number of consumers that can simultaneously open the devices");

51
driver/ppm_api_version.h Normal file
View File

@ -0,0 +1,51 @@
#ifndef PPM_API_VERSION_H
#define PPM_API_VERSION_H
/*
* API version component macros
*
* The version is a single uint64_t, structured as follows:
* bit 63: unused (so the version number is always positive)
* bits 44-62: major version
* bits 24-43: minor version
* bits 0-23: patch version
*/
#define PPM_VERSION_PACK(val, bits, shift) ((((unsigned long long)(val)) & ((1ULL << (bits)) - 1)) << (shift))
#define PPM_VERSION_UNPACK(val, bits, shift) ((((unsigned long long)(val)) >> (shift)) & ((1ULL << (bits)) - 1))
/* extract components from an API version number */
#define PPM_API_VERSION_MAJOR(ver) PPM_VERSION_UNPACK(ver, 19, 44)
#define PPM_API_VERSION_MINOR(ver) PPM_VERSION_UNPACK(ver, 20, 24)
#define PPM_API_VERSION_PATCH(ver) PPM_VERSION_UNPACK(ver, 24, 0)
/* build an API version number from components */
#define PPM_API_VERSION(major, minor, patch) \
PPM_VERSION_PACK(major, 19, 44) | \
PPM_VERSION_PACK(minor, 20, 24) | \
PPM_VERSION_PACK(patch, 24, 0)
#define PPM_API_CURRENT_VERSION PPM_API_VERSION( \
PPM_API_CURRENT_VERSION_MAJOR, \
PPM_API_CURRENT_VERSION_MINOR, \
PPM_API_CURRENT_VERSION_PATCH)
#define PPM_SCHEMA_CURRENT_VERSION PPM_API_VERSION( \
PPM_SCHEMA_CURRENT_VERSION_MAJOR, \
PPM_SCHEMA_CURRENT_VERSION_MINOR, \
PPM_SCHEMA_CURRENT_VERSION_PATCH)
#define __PPM_STRINGIFY1(x) #x
#define __PPM_STRINGIFY(x) __PPM_STRINGIFY1(x)
#define PPM_API_CURRENT_VERSION_STRING \
__PPM_STRINGIFY(PPM_API_CURRENT_VERSION_MAJOR) "." \
__PPM_STRINGIFY(PPM_API_CURRENT_VERSION_MINOR) "." \
__PPM_STRINGIFY(PPM_API_CURRENT_VERSION_PATCH)
#define PPM_SCHEMA_CURRENT_VERSION_STRING \
__PPM_STRINGIFY(PPM_SCHEMA_CURRENT_VERSION_MAJOR) "." \
__PPM_STRINGIFY(PPM_SCHEMA_CURRENT_VERSION_MINOR) "." \
__PPM_STRINGIFY(PPM_SCHEMA_CURRENT_VERSION_PATCH)
#endif

View File

@ -358,10 +358,12 @@
#define __NR_ia32_userfaultfd 350
#define __NR_ia32_openat2 351
#define __NR_ia32_execveat 352
#define __NR_ia32_copy_file_range 353
#define __NR_ia32_clone3 354
#ifdef __KERNEL__
#define NR_ia32_syscalls 353
#define NR_ia32_syscalls 355
#define __ARCH_WANT_IPC_PARSE_VERSION
#define __ARCH_WANT_OLD_READDIR

View File

@ -606,7 +606,7 @@ or GPL2.txt for full copies of the license.
#define PPM_RESOLVE_CACHED (1 << 5)
/*
* Execve additional flags
* Execve family additional flags.
*/
#define PPM_EXE_WRITABLE (1 << 0)
@ -992,7 +992,11 @@ enum ppm_event_type {
PPME_SYSCALL_MPROTECT_X = 329,
PPME_SYSCALL_EXECVEAT_E = 330,
PPME_SYSCALL_EXECVEAT_X = 331,
PPM_EVENT_MAX = 332
PPME_SYSCALL_COPY_FILE_RANGE_E = 332,
PPME_SYSCALL_COPY_FILE_RANGE_X = 333,
PPME_SYSCALL_CLONE3_E = 334,
PPME_SYSCALL_CLONE3_X = 335,
PPM_EVENT_MAX = 336
};
/*@}*/
@ -1326,7 +1330,10 @@ enum ppm_syscall_code {
PPM_SC_UMOUNT2 = 323,
PPM_SC_EXECVE = 324,
PPM_SC_EXECVEAT = 325,
PPM_SC_MAX = 326,
PPM_SC_COPY_FILE_RANGE = 326,
PPM_SC_CLONE = 327,
PPM_SC_CLONE3 = 328,
PPM_SC_MAX = 329,
};
/*
@ -1518,9 +1525,11 @@ struct ppm_evt_hdr {
#define PPM_IOCTL_SET_SIMPLE_MODE _IO(PPM_IOCTL_MAGIC, 18)
#define PPM_IOCTL_ENABLE_PAGE_FAULTS _IO(PPM_IOCTL_MAGIC, 19)
#define PPM_IOCTL_GET_N_TRACEPOINT_HIT _IO(PPM_IOCTL_MAGIC, 20)
#define PPM_IOCTL_GET_PROBE_VERSION _IO(PPM_IOCTL_MAGIC, 21)
#define PPM_IOCTL_GET_DRIVER_VERSION _IO(PPM_IOCTL_MAGIC, 21)
#define PPM_IOCTL_SET_FULLCAPTURE_PORT_RANGE _IO(PPM_IOCTL_MAGIC, 22)
#define PPM_IOCTL_SET_STATSD_PORT _IO(PPM_IOCTL_MAGIC, 23)
#define PPM_IOCTL_GET_API_VERSION _IO(PPM_IOCTL_MAGIC, 24)
#define PPM_IOCTL_GET_SCHEMA_VERSION _IO(PPM_IOCTL_MAGIC, 25)
#endif // CYGWING_AGENT
extern const struct ppm_name_value socket_families[];
@ -1663,6 +1672,7 @@ struct ppm_event_entry {
#define PPM_FAILURE_INVALID_USER_MEMORY -2
#define PPM_FAILURE_BUG -3
#define PPM_SKIP_EVENT -4
#define PPM_FAILURE_FRAME_SCRATCH_MAP_FULL -5 /* this is used only inside bpf, kernel module does not have a frame scratch map*/
#define RW_SNAPLEN 80
#define RW_MAX_SNAPLEN PPM_MAX_ARG_SIZE

View File

@ -236,6 +236,47 @@ out_unlock:
#endif /* UDIG */
}
int f_sys_open_e(struct event_filler_arguments *args)
{
syscall_arg_t val;
syscall_arg_t flags;
syscall_arg_t modes;
char *name = NULL;
int res;
/*
* name
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
if(likely(ppm_strncpy_from_user(args->str_storage, (const void __user *)val, PPM_MAX_PATH_SIZE) >= 0))
{
name = args->str_storage;
name[PPM_MAX_PATH_SIZE - 1] = '\0';
}
res = val_to_ring(args, (int64_t)(long)name, 0, false, 0);
if(unlikely(res != PPM_SUCCESS))
return res;
/*
* Flags
* Note that we convert them into the ppm portable representation before pushing them to the ring
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &flags);
res = val_to_ring(args, open_flags_to_scap(flags), 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* mode
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &modes);
res = val_to_ring(args, open_modes_to_scap(flags, modes), 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_open_x(struct event_filler_arguments *args)
{
syscall_arg_t val;
@ -759,6 +800,10 @@ int f_proc_startupdate(struct event_filler_arguments *args)
long swap = 0;
int available = STR_STORAGE_SIZE;
#ifdef __NR_clone3
struct clone_args cl_args;
#endif
/*
* Make sure the operation was successful
*/
@ -837,6 +882,7 @@ int f_proc_startupdate(struct event_filler_arguments *args)
case PPME_SYSCALL_EXECVEAT_X:
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &val);
break;
default:
val = 0;
@ -993,7 +1039,9 @@ cgroups_error:
if (args->event_type == PPME_SYSCALL_CLONE_20_X ||
args->event_type == PPME_SYSCALL_FORK_20_X ||
args->event_type == PPME_SYSCALL_VFORK_20_X) {
args->event_type == PPME_SYSCALL_VFORK_20_X ||
args->event_type == PPME_SYSCALL_CLONE3_X)
{
/*
* clone-only parameters
*/
@ -1015,14 +1063,34 @@ cgroups_error:
/*
* flags
*/
if (args->event_type == PPME_SYSCALL_CLONE_20_X) {
switch (args->event_type)
{
case PPME_SYSCALL_CLONE_20_X:
#ifdef CONFIG_S390
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
#else
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
#endif
} else
break;
case PPME_SYSCALL_CLONE3_X:
#ifdef __NR_clone3
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
res = ppm_copy_from_user(&cl_args, (void *)val, sizeof(struct clone_args));
if (unlikely(res != 0))
{
return PPM_FAILURE_INVALID_USER_MEMORY;
}
val = cl_args.flags;
#else
val = 0;
#endif
break;
default:
val = 0;
break;
}
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
if(pidns != &init_pid_ns || pid_ns_for_children(current) != pidns)
@ -1073,7 +1141,7 @@ cgroups_error:
} else if (args->event_type == PPME_SYSCALL_EXECVE_19_X ||
args->event_type == PPME_SYSCALL_EXECVEAT_X) {
/*
* execve-only parameters
* execve family parameters.
*/
long env_len = 0;
int tty_nr = 0;
@ -1193,9 +1261,10 @@ cgroups_error:
flags |= PPM_EXE_WRITABLE;
}
// write all the additional flags for execve family here...
/*
* flags
* Write all the additional flags for execve
*/
res = val_to_ring(args, flags, 0, false, 0);
@ -1347,6 +1416,84 @@ int f_sys_socket_bind_x(struct event_filler_arguments *args)
return add_sentinel(args);
}
int f_sys_connect_e(struct event_filler_arguments *args)
{
int res;
int err = 0;
int fd;
struct sockaddr __user *usrsockaddr;
u16 size = 0;
char *targetbuf = args->str_storage;
struct sockaddr_storage address;
syscall_arg_t val;
if (!args->is_socketcall) {
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
fd = (int)val;
}
#ifndef UDIG
else
fd = (int)args->socketcall_args[0];
#endif
res = val_to_ring(args, fd, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
if (fd >= 0) {
/*
* Get the address
*/
if (!args->is_socketcall)
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
#ifndef UDIG
else
val = args->socketcall_args[1];
#endif
usrsockaddr = (struct sockaddr __user *)val;
/*
* Get the address len
*/
if (!args->is_socketcall)
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &val);
#ifndef UDIG
else
val = args->socketcall_args[2];
#endif
if (usrsockaddr != NULL && val != 0) {
/*
* Copy the address
*/
err = addr_to_kernel(usrsockaddr, val, (struct sockaddr *)&address);
if (likely(err >= 0)) {
/*
* Convert the fd into socket endpoint information
*/
size = pack_addr((struct sockaddr *)&address,
val,
targetbuf,
STR_STORAGE_SIZE);
}
}
}
/*
* Copy the endpoint info into the ring
*/
res = val_to_ring(args,
(uint64_t)targetbuf,
size,
false,
0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_connect_x(struct event_filler_arguments *args)
{
int res;
@ -2585,6 +2732,37 @@ int f_sys_recvmsg_x(struct event_filler_arguments *args)
return add_sentinel(args);
}
int f_sys_creat_e(struct event_filler_arguments *args)
{
unsigned long val;
unsigned long modes;
char *name = NULL;
int res;
/*
* name
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
if(likely(ppm_strncpy_from_user(args->str_storage, (const void __user *)val, PPM_MAX_PATH_SIZE) >= 0))
{
name = args->str_storage;
name[PPM_MAX_PATH_SIZE - 1] = '\0';
}
res = val_to_ring(args, (int64_t)(long)name, 0, false, 0);
if(unlikely(res != PPM_SUCCESS))
return res;
/*
* mode
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &modes);
res = val_to_ring(args, open_modes_to_scap(O_CREAT, modes), 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_creat_x(struct event_filler_arguments *args)
{
unsigned long val;
@ -3057,6 +3235,59 @@ int f_sys_mount_e(struct event_filler_arguments *args)
}
#ifndef WDIG
int f_sys_openat_e(struct event_filler_arguments *args)
{
unsigned long val;
unsigned long flags;
unsigned long modes;
char *name = NULL;
int res;
/*
* dirfd
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
if ((int)val == AT_FDCWD)
val = PPM_AT_FDCWD;
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* name
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
if(likely(ppm_strncpy_from_user(args->str_storage, (const void __user *)val, PPM_MAX_PATH_SIZE) >= 0))
{
name = args->str_storage;
name[PPM_MAX_PATH_SIZE - 1] = '\0';
}
res = val_to_ring(args, (int64_t)(long)name, 0, false, 0);
if(unlikely(res != PPM_SUCCESS))
return res;
/*
* Flags
* Note that we convert them into the ppm portable representation before pushing them to the ring
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &flags);
res = val_to_ring(args, open_flags_to_scap(flags), 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* mode
*/
syscall_get_arguments_deprecated(current, args->regs, 3, 1, &modes);
res = val_to_ring(args, open_modes_to_scap(flags, modes), 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_openat_x(struct event_filler_arguments *args)
{
unsigned long val;
@ -4373,6 +4604,88 @@ int f_sys_symlinkat_x(struct event_filler_arguments *args)
return add_sentinel(args);
}
int f_sys_openat2_e(struct event_filler_arguments *args)
{
unsigned long resolve;
unsigned long flags;
unsigned long val;
unsigned long mode;
char *name = NULL;
int res;
#ifdef __NR_openat2
struct open_how how;
#endif
/*
* dirfd
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
if ((int)val == AT_FDCWD)
val = PPM_AT_FDCWD;
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* name
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
if(likely(ppm_strncpy_from_user(args->str_storage, (const void __user *)val, PPM_MAX_PATH_SIZE) >= 0))
{
name = args->str_storage;
name[PPM_MAX_PATH_SIZE - 1] = '\0';
}
res = val_to_ring(args, (int64_t)(long)name, 0, false, 0);
if(unlikely(res != PPM_SUCCESS))
return res;
#ifdef __NR_openat2
/*
* how: we get the data structure, and put its fields in the buffer one by one
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &val);
res = ppm_copy_from_user(&how, (void *)val, sizeof(struct open_how));
if (unlikely(res != 0))
return PPM_FAILURE_INVALID_USER_MEMORY;
flags = open_flags_to_scap(how.flags);
mode = open_modes_to_scap(how.flags, how.mode);
resolve = openat2_resolve_to_scap(how.resolve);
#else
flags = 0;
mode = 0;
resolve = 0;
#endif
/*
* flags (extracted from open_how structure)
* Note that we convert them into the ppm portable representation before pushing them to the ring
*/
res = val_to_ring(args, flags, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* mode (extracted from open_how structure)
* Note that we convert them into the ppm portable representation before pushing them to the ring
*/
res = val_to_ring(args, mode, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* resolve (extracted from open_how structure)
* Note that we convert them into the ppm portable representation before pushing them to the ring
*/
res = val_to_ring(args, resolve, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_openat2_x(struct event_filler_arguments *args)
{
unsigned long resolve;
@ -4454,6 +4767,71 @@ int f_sys_openat2_x(struct event_filler_arguments *args)
return add_sentinel(args);
}
int f_sys_copy_file_range_e(struct event_filler_arguments *args)
{
unsigned long fdin;
unsigned long offin;
unsigned long len;
int res;
/*
* fdin
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &fdin);
res = val_to_ring(args, fdin, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* offin
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &offin);
res = val_to_ring(args, offin, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* len
*/
syscall_get_arguments_deprecated(current, args->regs, 4, 1, &len);
res = val_to_ring(args, len, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_copy_file_range_x(struct event_filler_arguments *args)
{
unsigned long fdout;
unsigned long offout;
int64_t retval;
int res;
retval = (int64_t)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* fdout
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &fdout);
res = val_to_ring(args, fdout, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* offout
*/
syscall_get_arguments_deprecated(current, args->regs, 3, 1, &offout);
res = val_to_ring(args, offout, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
#endif /* WDIG */
int f_sys_procexit_e(struct event_filler_arguments *args)

View File

@ -33,6 +33,7 @@ or GPL2.txt for full copies of the license.
FN(sys_empty) \
FN(sys_single) \
FN(sys_single_x) \
FN(sys_open_e) \
FN(sys_open_x) \
FN(sys_read_x) \
FN(sys_write_x) \
@ -56,6 +57,7 @@ or GPL2.txt for full copies of the license.
FN(sys_recvmsg_x) \
FN(sys_recvmsg_x_2) \
FN(sys_shutdown_e) \
FN(sys_creat_e) \
FN(sys_creat_x) \
FN(sys_pipe_x) \
FN(sys_eventfd_e) \
@ -113,13 +115,18 @@ or GPL2.txt for full copies of the license.
FN(sys_chmod_x) \
FN(sys_fchmod_x) \
FN(sys_mkdirat_x) \
FN(sys_openat_e) \
FN(sys_openat_x) \
FN(sys_openat2_e) \
FN(sys_openat2_x) \
FN(sys_linkat_x) \
FN(sys_mprotect_e) \
FN(sys_mprotect_x) \
FN(sys_execveat_e) \
FN(execve_family_flags) \
FN(sys_copy_file_range_e) \
FN(sys_copy_file_range_x) \
FN(sys_connect_e) \
FN(terminate_filler)
#define FILLER_ENUM_FN(x) PPM_FILLER_##x,

View File

@ -361,12 +361,18 @@ const struct syscall_evt_pair g_syscall_table[SYSCALL_TABLE_SIZE] = {
#ifdef __NR_openat2
[__NR_openat2 - SYSCALL_TABLE_ID0] = {UF_USED, PPME_SYSCALL_OPENAT2_E, PPME_SYSCALL_OPENAT2_X},
#endif
#ifdef __NR_clone3
[__NR_clone3 - SYSCALL_TABLE_ID0] = {UF_USED | UF_NEVER_DROP | UF_SIMPLEDRIVER_KEEP, PPME_SYSCALL_CLONE3_E, PPME_SYSCALL_CLONE3_X},
#endif
#ifdef __NR_mprotect
[__NR_mprotect - SYSCALL_TABLE_ID0] = {UF_USED, PPME_SYSCALL_MPROTECT_E, PPME_SYSCALL_MPROTECT_X},
#endif
#ifdef __NR_execveat
[__NR_execveat - SYSCALL_TABLE_ID0] = {UF_USED | UF_NEVER_DROP | UF_SIMPLEDRIVER_KEEP, PPME_SYSCALL_EXECVEAT_E, PPME_SYSCALL_EXECVEAT_X},
#endif
#ifdef __NR_copy_file_range
[__NR_copy_file_range - SYSCALL_TABLE_ID0] = {UF_USED, PPME_SYSCALL_COPY_FILE_RANGE_E, PPME_SYSCALL_COPY_FILE_RANGE_X},
#endif
};
/*
@ -994,6 +1000,13 @@ const enum ppm_syscall_code g_syscall_code_routing_table[SYSCALL_TABLE_SIZE] = {
#ifdef __NR_execveat
[__NR_execveat - SYSCALL_TABLE_ID0] = PPM_SC_EXECVEAT,
#endif
#ifdef __NR_copy_file_range
[__NR_copy_file_range - SYSCALL_TABLE_ID0] = PPM_SC_COPY_FILE_RANGE,
#endif
[__NR_clone - SYSCALL_TABLE_ID0] = PPM_SC_CLONE,
#ifdef __NR_clone3
[__NR_clone3 - SYSCALL_TABLE_ID0] = PPM_SC_CLONE3,
#endif
};
#ifdef CONFIG_IA32_EMULATION
@ -1236,12 +1249,18 @@ const struct syscall_evt_pair g_syscall_ia32_table[SYSCALL_TABLE_SIZE] = {
#ifdef __NR_ia32_openat2
[__NR_ia32_openat2 - SYSCALL_TABLE_ID0] = {UF_USED, PPME_SYSCALL_OPENAT2_E, PPME_SYSCALL_OPENAT2_X},
#endif
#ifdef __NR_ia32_clone3
[__NR_ia32_clone3 - SYSCALL_TABLE_ID0] = {UF_USED | UF_NEVER_DROP | UF_SIMPLEDRIVER_KEEP, PPME_SYSCALL_CLONE3_E, PPME_SYSCALL_CLONE3_X},
#endif
#ifdef __NR_ia32_mprotect
[__NR_ia32_mprotect - SYSCALL_TABLE_ID0] = {UF_USED, PPME_SYSCALL_MPROTECT_E, PPME_SYSCALL_MPROTECT_X},
#endif
#ifdef __NR_ia32_execveat
[__NR_ia32_execveat - SYSCALL_TABLE_ID0] = {UF_USED | UF_NEVER_DROP | UF_SIMPLEDRIVER_KEEP, PPME_SYSCALL_EXECVEAT_E, PPME_SYSCALL_EXECVEAT_X},
#endif
#ifdef __NR_ia32_copy_file_range
[__NR_ia32_copy_file_range - SYSCALL_TABLE_ID0] = {UF_USED, PPME_SYSCALL_COPY_FILE_RANGE_E, PPME_SYSCALL_COPY_FILE_RANGE_X},
#endif
};
/*
@ -1804,6 +1823,13 @@ const enum ppm_syscall_code g_syscall_ia32_code_routing_table[SYSCALL_TABLE_SIZE
#ifdef __NR_ia32_execveat
[__NR_ia32_execveat - SYSCALL_TABLE_ID0] = PPM_SC_EXECVEAT,
#endif
#ifdef __NR_ia32_copy_file_range
[__NR_ia32_copy_file_range - SYSCALL_TABLE_ID0] = PPM_SC_COPY_FILE_RANGE,
#endif
[__NR_ia32_clone - SYSCALL_TABLE_ID0] = PPM_SC_CLONE,
#ifdef __NR_ia32_clone3
[__NR_ia32_clone3 - SYSCALL_TABLE_ID0] = PPM_SC_CLONE3,
#endif
};
#endif /* CONFIG_IA32_EMULATION */

View File

@ -40,6 +40,8 @@ This proposal intends to extend on points 10-12 for the libsinsp and libscap pla
### Versioning Scheme
**Superseeded by**: [versioning-schema-amendment proposal](20220203-versioning-schema-amendment.md).
This document proposes to version libscap, libsinsp, and the Falco drivers - all residing in `falcosecurity/libs` - with a single [SemVer 2.0](https://semver.org/spec/v2.0.0.html) string.
While libscap and libsinsp - to do not mention the drivers - have different API surfaces, this document proposes to version them as one single machinery to avoid further maintenance burdens and version compatibility matrices (read dependency hell) between all the floating pieces.

View File

@ -0,0 +1,64 @@
# Versioning schema
**Supersedes**: [20210524-versioning-and-release-of-the-libs-artifacts.md#versioning-scheme](20210524-versioning-and-release-of-the-libs-artifacts.md#versioning-scheme)
## Summary
This proposal extends and improves the two previous proposals regarding the versioning and the release process of the `falcosecurity/libs` repository (which includes libscap, libsinsp, and the two drivers).
In particular, the [20210524-versioning-and-release-of-the-libs-artifacts.md#versioning-scheme](20210524-versioning-and-release-of-the-libs-artifacts.md#versioning-scheme) proposal mandated to version all the artifacts as one single machinery with the spirit of simplicity. Although that was a good idea at the time of the first proposal, the new [20210818-driver-semver.md](20210818-driver-semver.md) proposal introduced an effective API versioning solution for the user/kernel boundary in order to make the drivers reusable across libscap consumers and their versions (when version compatibility allows).
This amendment introduces two different version numbers for releasing artifacts (instead of one single version number):
- The **libs version number** which represents the build version of the user-space libraries (i.e., libscap, libsinsp, and possibly any other further user-space library)
- The **driver version number** which represents the build version of kernel-space drivers (i.e., the kernel module, the eBPF probe, and possibly any other kernel-space driver)
This proposal does not aim to introduce changes other than using two different version numbers. Moreover, this proposal is only about the versions string used at build time, so no code changes are expected outside the build system context.
## Motivation
The [20210818-driver-semver.md](20210818-driver-semver.md#motivation) proposal is already fully implemented. The advantages introduced by that proposal would be lost if we used a single versioning number for all the artifacts as mandated by [20210524-versioning-and-release-of-the-libs-artifacts.md#versioning-scheme](20210524-versioning-and-release-of-the-libs-artifacts.md#versioning-scheme). Furthermore, that proposal is only about versioning the APIs that sits between the kernel and the user-space components. It does not mandate any specification regarding the versioning of artifacts.
This amendment is required to fill the gap between the two proposals and allow our users to reuse the same driver version across a range of compatible consumers.
## Goals
* Document the two versioning schemes (one for the libs and another for the drivers)
* Allow releasing libs and drivers separately (different timing and versioning)
* Make the drivers reusable across libscap consumers and their versions
## Non-goals
* Introduce code changes other than in the build system and in the documentation
* Indicate how the distribution of the artifacts must be implemented
## Proposed solution
### Userspace libs artifacts
Libscap and libsinsp are two distinct artifacts. They will be released with the same version number (a single [SemVer 2.0](https://semver.org/spec/v2.0.0.html) string). This proposal does not aim to change what already proposed by [20210524-versioning-and-release-of-the-libs-artifacts.md#versioning-scheme](20210524-versioning-and-release-of-the-libs-artifacts.md#versioning-scheme) with respect to the user-space components residing in `falcosecurity/libs`.
### Drivers artifacts
The kernel module and the eBPF probe are two components that can be built for any supported Kernel version. The source code of both drivers will be released with the same version number (a single [SemVer 2.0](https://semver.org/spec/v2.0.0.html) string).
However, a few considerations need to be taken into account. The public API is composed of two different characteristics in the driver context: the API functions (exposed to the consumer) and the data schema (delivered to the consumer). Our implementation versions those two characteristics directly in the source code (you can find the current versions respectively in [/driver/API_VERSION](/driver/API_VERSION) and [/driver/SCHEMA_VERSION](/driver/SCHEMA_VERSION)). Those versions use a SemVer compatible scheme.
For this reason, the **driver version number** must represent both characteristics, which form the public API for the drivers.
For that purpose, this document proposes to use `1.0.0` as the starting point for the driver version number, then to use the following rules to bump such version number:
- *major* increases either when `API_VERSION`s major or `SCHEMA_VERSION`s major number has been increased
- *minor* increases either when `API_VERSION`s minor or `SCHEMA_VERSION`s minor number has been increased
- *patch* increases either when `API_VERSION`s patch or `SCHEMA_VERSION`s patch number has been increased or when any other code changes have been introduced (for example, the support for a new kernel)
Note that no backward-incompatible changes can be introduced without bumping the *major* number of `API_VERSION` or `SCHEMA_VERSION` first. Similar logic applies for the *minor* and *patch* numbers. Since both `API_VERSION` and `SCHEMA_VERSION` follow the SemVer scheme, with this method also, the resulting driver version is guaranteed to respect what the SemVer specification mandates.
### Other considerations
When releasing the artifacts, maintainers will use these versioning schemes (i.e., when git tagging libs or drivers).
However, consumers are free to use any versioning scheme they want by overriding those values at build time (e.g., via cmake options).
Steps described in the
[20210524-versioning-and-release-of-the-libs-artifacts.md#steps](20210524-versioning-and-release-of-the-libs-artifacts.md#steps) section will need to be adapted to accommodate the two different release processes (one for the libs and another for the drivers).

View File

@ -119,7 +119,7 @@ const static struct luaL_Reg ll_sysdig [] =
{"make_ts", &lua_cbacks::make_ts},
{"add_ts", &lua_cbacks::add_ts},
{"subtract_ts", &lua_cbacks::subtract_ts},
{"run_sysdig", &lua_cbacks::run_sysdig},
{"run_app", &lua_cbacks::run_app},
{"end_capture", &lua_cbacks::end_capture},
{"log", &lua_cbacks::log},
{"udp_setpeername", &lua_cbacks::udp_setpeername},
@ -245,7 +245,7 @@ void chiselinfo::set_callback_precise_interval(uint64_t interval)
///////////////////////////////////////////////////////////////////////////////
// chisel implementation
///////////////////////////////////////////////////////////////////////////////
sinsp_chisel::sinsp_chisel(sinsp* inspector, string filename)
sinsp_chisel::sinsp_chisel(sinsp* inspector, string filename, bool is_file)
{
m_inspector = inspector;
m_ls = NULL;
@ -256,7 +256,7 @@ sinsp_chisel::sinsp_chisel(sinsp* inspector, string filename)
m_lua_last_interval_ts = 0;
m_udp_socket = 0;
load(filename);
load(filename, is_file);
}
sinsp_chisel::~sinsp_chisel()
@ -1170,33 +1170,42 @@ bool sinsp_chisel::openfile(string filename, OUT ifstream* is)
return false;
}
void sinsp_chisel::load(string cmdstr)
void sinsp_chisel::load(string cmdstr, bool is_file)
{
m_filename = cmdstr;
trim(cmdstr);
ifstream is;
//
// Try to open the file with lua extension
//
if(!openfile(m_filename + ".lua", &is))
{
//
// Try to open the file as is
//
if(!openfile(m_filename, &is))
{
throw sinsp_exception("can't open file " + m_filename);
}
if (is_file) {
trim(cmdstr);
m_filename = cmdstr;
} else {
m_filename = "<in-memory-string>";
}
ifstream is;
std::string scriptstr;
if (is_file) {
//
// Try to open the file with lua extension
//
if(!openfile(m_filename + ".lua", &is))
{
//
// Try to open the file as is
//
if(!openfile(m_filename, &is))
{
throw sinsp_exception("can't open file " + m_filename);
}
}
//
// Load the file
//
std::istreambuf_iterator<char> eos;
scriptstr.assign(std::istreambuf_iterator<char>(is), eos);
} else {
scriptstr = cmdstr;
}
#ifdef HAS_LUA_CHISELS
//
// Load the file
//
std::istreambuf_iterator<char> eos;
std::string scriptstr(std::istreambuf_iterator<char>(is), eos);
//
// Open the script

View File

@ -110,11 +110,11 @@ private:
class SINSP_PUBLIC sinsp_chisel
{
public:
sinsp_chisel(sinsp* inspector, string filename);
sinsp_chisel(sinsp* inspector, string filename, bool is_file = true);
~sinsp_chisel();
static void add_lua_package_path(lua_State* ls, const char* path);
static void get_chisel_list(vector<chisel_desc>* chisel_descs);
void load(string cmdstr);
void load(string cmdstr, bool is_file = true);
string get_name()
{
return m_filename;

View File

@ -562,7 +562,7 @@ int lua_cbacks::subtract_ts(lua_State *ls)
return 1;
}
int lua_cbacks::run_sysdig(lua_State *ls)
int lua_cbacks::run_app(lua_State *ls)
{
lua_getglobal(ls, "sichisel");

View File

@ -36,7 +36,7 @@ public:
static int make_ts(lua_State *ls);
static int add_ts(lua_State *ls);
static int subtract_ts(lua_State *ls);
static int run_sysdig(lua_State *ls);
static int run_app(lua_State *ls);
static int end_capture(lua_State *ls);
static int is_live(lua_State *ls);
static int is_tty(lua_State *ls);

View File

@ -1,5 +1,5 @@
#
# Copyright (C) 2021 The Falco Authors.
# Copyright (C) 2022 The Falco Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -30,24 +30,24 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux")
set(KBUILD_FLAGS "${FALCOSECURITY_LIBS_DEBUG_FLAGS}")
endif()
if(NOT DEFINED PROBE_VERSION)
set(PROBE_VERSION "${FALCOSECURITY_LIBS_VERSION}")
if(NOT DEFINED DRIVER_VERSION)
set(DRIVER_VERSION "${FALCOSECURITY_LIBS_VERSION}")
endif()
if(NOT DEFINED PROBE_NAME)
set(PROBE_NAME "scap")
if(NOT DEFINED DRIVER_NAME)
set(DRIVER_NAME "scap")
endif()
if(NOT DEFINED PROBE_DEVICE_NAME)
set(PROBE_DEVICE_NAME "${PROBE_NAME}")
if(NOT DEFINED DRIVER_DEVICE_NAME)
set(DRIVER_DEVICE_NAME "${DRIVER_NAME}")
endif()
string(REPLACE "-" "_" SCAP_PROBE_MODULE_NAME "${PROBE_NAME}")
add_definitions(-DSCAP_PROBE_MODULE_NAME="${SCAP_PROBE_MODULE_NAME}")
string(REPLACE "-" "_" SCAP_KERNEL_MODULE_NAME "${DRIVER_NAME}")
add_definitions(-DSCAP_KERNEL_MODULE_NAME="${SCAP_KERNEL_MODULE_NAME}")
if(NOT DEFINED SCAP_PROBE_BPF_FILEPATH)
# note that the home folder is prepended by scap at runtime
set(SCAP_PROBE_BPF_FILEPATH ".${PROBE_NAME}/${PROBE_NAME}-bpf.o")
set(SCAP_PROBE_BPF_FILEPATH ".${DRIVER_NAME}/${DRIVER_NAME}-bpf.o")
endif()
add_definitions(-DSCAP_PROBE_BPF_FILEPATH="${SCAP_PROBE_BPF_FILEPATH}")
endif()

View File

@ -30,6 +30,7 @@ static void signal_callback(int signal)
printf("seen by driver: %" PRIu64 "\n", s.n_evts);
printf("Number of dropped events: %" PRIu64 "\n", s.n_drops);
printf("Number of dropped events caused by full buffer: %" PRIu64 "\n", s.n_drops_buffer);
printf("Number of dropped events caused by full scratch map: %" PRIu64 "\n", s.n_drops_scratch_map);
printf("Number of dropped events caused by invalid memory access: %" PRIu64 "\n", s.n_drops_pf);
printf("Number of dropped events caused by an invalid condition in the kernel instrumentation: %" PRIu64 "\n", s.n_drops_bug);
printf("Number of preemptions: %" PRIu64 "\n", s.n_preemptions);

View File

@ -94,11 +94,6 @@ typedef struct scap_device
struct ppm_ring_buffer_info* m_bufinfo;
struct udig_ring_buffer_status* m_bufstatus; // used by udig
};
// Anonymous struct with bpf stuff
struct
{
uint64_t m_evt_lost;
};
};
}scap_device;
@ -154,6 +149,8 @@ struct scap
uint32_t m_fd_lookup_limit;
uint64_t m_unexpected_block_readsize;
uint32_t m_ncpus;
uint8_t m_cgroup_version;
// Abstraction layer for windows
#if CYGWING_AGENT || _WIN32
wh_t* m_whh;
@ -208,6 +205,16 @@ struct scap
// The return value from the last call to next_batch().
ss_plugin_rc m_input_plugin_last_batch_res;
// API version supported by the driver
// If the API version is unavailable for whatever reason,
// it's equivalent to version 0.0.0
uint64_t m_api_version;
// schema version supported by the driver
// If the schema version is unavailable for whatever reason,
// it's equivalent to version 0.0.0
uint64_t m_schema_version;
};
typedef enum ppm_dumper_type

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2021 The Falco Authors.
Copyright (C) 2022 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -56,11 +56,6 @@ limitations under the License.
//#define NDEBUG
#include <assert.h>
//
// Probe version string size
//
#define SCAP_PROBE_VERSION_SIZE 32
static int32_t plugin_rc_to_scap_rc(ss_plugin_rc plugin_rc)
{
switch(plugin_rc)
@ -145,7 +140,7 @@ static uint32_t get_max_consumers()
{
#ifndef _WIN32
uint32_t max;
FILE *pfile = fopen("/sys/module/" SCAP_PROBE_MODULE_NAME "/parameters/max_consumers", "r");
FILE *pfile = fopen("/sys/module/" SCAP_KERNEL_MODULE_NAME "/parameters/max_consumers", "r");
if(pfile != NULL)
{
int w = fscanf(pfile, "%"PRIu32, &max);
@ -387,6 +382,8 @@ scap_t* scap_open_live_int(char *error, int32_t *rc,
{
int len;
uint32_t all_scanned_devs;
uint64_t api_version;
uint64_t schema_version;
//
// Allocate the device descriptors.
@ -398,7 +395,7 @@ scap_t* scap_open_live_int(char *error, int32_t *rc,
//
// Open the device
//
snprintf(filename, sizeof(filename), "%s/dev/" PROBE_DEVICE_NAME "%d", scap_get_host_root(), all_scanned_devs);
snprintf(filename, sizeof(filename), "%s/dev/" DRIVER_DEVICE_NAME "%d", scap_get_host_root(), all_scanned_devs);
if((handle->m_devs[j].m_fd = open(filename, O_RDWR | O_SYNC)) < 0)
{
@ -412,11 +409,11 @@ scap_t* scap_open_live_int(char *error, int32_t *rc,
else if(errno == EBUSY)
{
uint32_t curr_max_consumers = get_max_consumers();
snprintf(error, SCAP_LASTERR_SIZE, "Too many consumers attached to device %s. Current value for /sys/module/" SCAP_PROBE_MODULE_NAME "/parameters/max_consumers is '%"PRIu32"'.", filename, curr_max_consumers);
snprintf(error, SCAP_LASTERR_SIZE, "Too many consumers attached to device %s. Current value for /sys/module/" SCAP_KERNEL_MODULE_NAME "/parameters/max_consumers is '%"PRIu32"'.", filename, curr_max_consumers);
}
else
{
snprintf(error, SCAP_LASTERR_SIZE, "error opening device %s. Make sure you have root credentials and that the " PROBE_NAME " module is loaded.", filename);
snprintf(error, SCAP_LASTERR_SIZE, "error opening device %s. Make sure you have root credentials and that the " DRIVER_NAME " module is loaded.", filename);
}
scap_close(handle);
@ -427,11 +424,71 @@ scap_t* scap_open_live_int(char *error, int32_t *rc,
// Set close-on-exec for the fd
if (fcntl(handle->m_devs[j].m_fd, F_SETFD, FD_CLOEXEC) == -1) {
snprintf(error, SCAP_LASTERR_SIZE, "Can not set close-on-exec flag for fd for device %s (%s)", filename, scap_strerror(handle, errno));
close(handle->m_devs[j].m_fd);
scap_close(handle);
*rc = SCAP_FAILURE;
return NULL;
}
// Check the API version reported
if (ioctl(handle->m_devs[j].m_fd, PPM_IOCTL_GET_API_VERSION, &api_version) < 0)
{
snprintf(error, SCAP_LASTERR_SIZE, "Kernel module does not support PPM_IOCTL_GET_API_VERSION");
close(handle->m_devs[j].m_fd);
scap_close(handle);
*rc = SCAP_FAILURE;
return NULL;
}
// Make sure all devices report the same API version
if (handle->m_api_version != 0 && handle->m_api_version != api_version)
{
snprintf(error, SCAP_LASTERR_SIZE, "API version mismatch: device %s reports API version %llu.%llu.%llu, expected %llu.%llu.%llu",
filename,
PPM_API_VERSION_MAJOR(api_version),
PPM_API_VERSION_MINOR(api_version),
PPM_API_VERSION_PATCH(api_version),
PPM_API_VERSION_MAJOR(handle->m_api_version),
PPM_API_VERSION_MINOR(handle->m_api_version),
PPM_API_VERSION_PATCH(handle->m_api_version)
);
close(handle->m_devs[j].m_fd);
scap_close(handle);
*rc = SCAP_FAILURE;
return NULL;
}
// Set the API version from the first device
// (for subsequent devices it's a no-op thanks to the check above)
handle->m_api_version = api_version;
// Check the schema version reported
if (ioctl(handle->m_devs[j].m_fd, PPM_IOCTL_GET_SCHEMA_VERSION, &schema_version) < 0)
{
snprintf(error, SCAP_LASTERR_SIZE, "Kernel module does not support PPM_IOCTL_GET_SCHEMA_VERSION");
close(handle->m_devs[j].m_fd);
scap_close(handle);
*rc = SCAP_FAILURE;
return NULL;
}
// Make sure all devices report the same schema version
if (handle->m_schema_version != 0 && handle->m_schema_version != schema_version)
{
snprintf(error, SCAP_LASTERR_SIZE, "Schema version mismatch: device %s reports schema version %llu.%llu.%llu, expected %llu.%llu.%llu",
filename,
PPM_API_VERSION_MAJOR(schema_version),
PPM_API_VERSION_MINOR(schema_version),
PPM_API_VERSION_PATCH(schema_version),
PPM_API_VERSION_MAJOR(handle->m_schema_version),
PPM_API_VERSION_MINOR(handle->m_schema_version),
PPM_API_VERSION_PATCH(handle->m_schema_version)
);
scap_close(handle);
*rc = SCAP_FAILURE;
return NULL;
}
// Set the schema version from the first device
// (for subsequent devices it's a no-op thanks to the check above)
handle->m_schema_version = schema_version;
//
// Map the ring buffer
//
@ -496,6 +553,34 @@ scap_t* scap_open_live_int(char *error, int32_t *rc,
}
}
if(!scap_is_api_compatible(handle->m_api_version, SCAP_MINIMUM_DRIVER_API_VERSION))
{
snprintf(error, SCAP_LASTERR_SIZE, "Driver supports API version %llu.%llu.%llu, but running version needs %d.%d.%d",
PPM_API_VERSION_MAJOR(handle->m_api_version),
PPM_API_VERSION_MINOR(handle->m_api_version),
PPM_API_VERSION_PATCH(handle->m_api_version),
PPM_API_CURRENT_VERSION_MAJOR,
PPM_API_CURRENT_VERSION_MINOR,
PPM_API_CURRENT_VERSION_PATCH);
*rc = SCAP_FAILURE;
scap_close(handle);
return NULL;
}
if(!scap_is_api_compatible(handle->m_schema_version, SCAP_MINIMUM_DRIVER_SCHEMA_VERSION))
{
snprintf(error, SCAP_LASTERR_SIZE, "Driver supports schema version %llu.%llu.%llu, but running version needs %d.%d.%d",
PPM_API_VERSION_MAJOR(handle->m_schema_version),
PPM_API_VERSION_MINOR(handle->m_schema_version),
PPM_API_VERSION_PATCH(handle->m_schema_version),
PPM_SCHEMA_CURRENT_VERSION_MAJOR,
PPM_SCHEMA_CURRENT_VERSION_MINOR,
PPM_SCHEMA_CURRENT_VERSION_PATCH);
*rc = SCAP_FAILURE;
scap_close(handle);
return NULL;
}
for(j = 0; j < handle->m_ndevs; ++j)
{
//
@ -2013,6 +2098,7 @@ int32_t scap_get_stats(scap_t* handle, OUT scap_stats* stats)
stats->n_evts = 0;
stats->n_drops = 0;
stats->n_drops_buffer = 0;
stats->n_drops_scratch_map = 0;
stats->n_drops_pf = 0;
stats->n_drops_bug = 0;
stats->n_preemptions = 0;
@ -2969,3 +3055,42 @@ int32_t scap_set_statsd_port(scap_t* const handle, const uint16_t port)
return SCAP_SUCCESS;
#endif
}
bool scap_is_api_compatible(unsigned long driver_api_version, unsigned long required_api_version)
{
unsigned long driver_major = PPM_API_VERSION_MAJOR(driver_api_version);
unsigned long driver_minor = PPM_API_VERSION_MINOR(driver_api_version);
unsigned long driver_patch = PPM_API_VERSION_PATCH(driver_api_version);
unsigned long required_major = PPM_API_VERSION_MAJOR(required_api_version);
unsigned long required_minor = PPM_API_VERSION_MINOR(required_api_version);
unsigned long required_patch = PPM_API_VERSION_PATCH(required_api_version);
if(driver_major != required_major)
{
// major numbers disagree
return false;
}
if(driver_minor < required_minor)
{
// driver's minor version is < ours
return false;
}
if(driver_minor == required_minor && driver_patch < required_patch)
{
// driver's minor versions match and patch level is < ours
return false;
}
return true;
}
uint64_t scap_get_driver_api_version(scap_t* handle)
{
return handle->m_api_version;
}
uint64_t scap_get_driver_schema_version(scap_t* handle)
{
return handle->m_schema_version;
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2021 The Falco Authors.
Copyright (C) 2022 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -59,6 +59,7 @@ struct iovec;
#include <time.h>
#include "uthash.h"
#include "../common/types.h"
#include "../../driver/ppm_api_version.h"
#include "../../driver/ppm_events_public.h"
#ifdef _WIN32
#include <time.h>
@ -67,6 +68,23 @@ struct iovec;
#include "plugin_info.h"
//
// The minimum API and schema versions the driver has to support before we can use it
//
// The reason to increment these would be a bug in the driver that userspace
// cannot or does not want to work around.
//
// Note: adding new events or event fields should not need a version bump
// here, since libscap has to suport old event formats anyway (for capture
// files).
//
// If a consumer relies on events or APIs added in a new version, it should
// call `scap_get_driver_api_version()` and/or `scap_get_driver_schema_version()`
// and handle the result
//
#define SCAP_MINIMUM_DRIVER_API_VERSION PPM_API_VERSION(1, 0, 0)
#define SCAP_MINIMUM_DRIVER_SCHEMA_VERSION PPM_API_VERSION(1, 0, 0)
//
// Return types
//
@ -94,11 +112,12 @@ typedef struct scap_stats
uint64_t n_evts; ///< Total number of events that were received by the driver.
uint64_t n_drops; ///< Number of dropped events.
uint64_t n_drops_buffer; ///< Number of dropped events caused by full buffer.
uint64_t n_drops_scratch_map; ///< Number of dropped events caused by full frame scratch map.
uint64_t n_drops_pf; ///< Number of dropped events caused by invalid memory access.
uint64_t n_drops_bug; ///< Number of dropped events caused by an invalid condition in the kernel instrumentation.
uint64_t n_preemptions; ///< Number of preemptions.
uint64_t n_suppressed; ///< Number of events skipped due to the tid being in a set of suppressed tids
uint64_t n_tids_suppressed; ///< Number of threads currently being suppressed
uint64_t n_suppressed; ///< Number of events skipped due to the tid being in a set of suppressed tids.
uint64_t n_tids_suppressed; ///< Number of threads currently being suppressed.
}scap_stats;
/*!
@ -1121,6 +1140,21 @@ int32_t scap_set_fullcapture_port_range(scap_t* handle, uint16_t range_start, ui
*/
int32_t scap_set_statsd_port(scap_t* handle, uint16_t port);
/**
* Is `driver_api_version` compatible with `required_api_version`?
*/
bool scap_is_api_compatible(unsigned long driver_api_version, unsigned long required_api_version);
/**
* Get API version supported by the driver
*/
uint64_t scap_get_driver_api_version(scap_t* handle);
/**
* Get schema version supported by the driver
*/
uint64_t scap_get_driver_schema_version(scap_t* handle);
#ifdef __cplusplus
}
#endif

View File

@ -310,10 +310,10 @@ static int32_t load_maps(scap_t *handle, struct bpf_map_data *maps, int nr_maps)
for(j = 0; j < nr_maps; ++j)
{
if(j == SYSDIG_PERF_MAP ||
j == SYSDIG_LOCAL_STATE_MAP ||
j == SYSDIG_FRAME_SCRATCH_MAP ||
j == SYSDIG_TMP_SCRATCH_MAP)
if(j == SCAP_PERF_MAP ||
j == SCAP_LOCAL_STATE_MAP ||
j == SCAP_FRAME_SCRATCH_MAP ||
j == SCAP_TMP_SCRATCH_MAP)
{
maps[j].def.max_entries = handle->m_ncpus;
}
@ -564,6 +564,8 @@ static int32_t load_bpf_file(scap_t *handle, const char *path)
struct bpf_map_data maps[BPF_MAPS_MAX];
struct utsname osname;
int32_t res = SCAP_FAILURE;
bool got_api_version = false;
bool got_schema_version = false;
if(uname(&osname))
{
@ -622,13 +624,13 @@ static int32_t load_bpf_file(scap_t *handle, const char *path)
goto cleanup;
}
}
else if(strcmp(shname, "probe_version") == 0) {
if(strcmp(PROBE_VERSION, data->d_buf))
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "BPF probe version is %s, but running version is %s",
(char *) data->d_buf, PROBE_VERSION);
goto cleanup;
}
else if(strcmp(shname, "api_version") == 0) {
got_api_version = true;
memcpy(&handle->m_api_version, data->d_buf, sizeof(handle->m_api_version));
}
else if(strcmp(shname, "schema_version") == 0) {
got_schema_version = true;
memcpy(&handle->m_schema_version, data->d_buf, sizeof(handle->m_schema_version));
}
else if(strcmp(shname, "license") == 0)
{
@ -637,6 +639,18 @@ static int32_t load_bpf_file(scap_t *handle, const char *path)
}
}
if(!got_api_version)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "missing api_version section");
goto cleanup;
}
if(!got_schema_version)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "missing schema_version section");
goto cleanup;
}
if(!symbols)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "missing SHT_SYMTAB section");
@ -756,14 +770,14 @@ static int32_t populate_syscall_routing_table_map(scap_t *handle)
for(j = 0; j < SYSCALL_TABLE_SIZE; ++j)
{
long code = g_syscall_code_routing_table[j];
if(bpf_map_update_elem(handle->m_bpf_map_fds[SYSDIG_SYSCALL_CODE_ROUTING_TABLE], &j, &code, BPF_ANY) != 0)
if(bpf_map_update_elem(handle->m_bpf_map_fds[SCAP_SYSCALL_CODE_ROUTING_TABLE], &j, &code, BPF_ANY) != 0)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SYSDIG_SYSCALL_CODE_ROUTING_TABLE bpf_map_update_elem < 0");
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_SYSCALL_CODE_ROUTING_TABLE bpf_map_update_elem < 0");
return SCAP_FAILURE;
}
}
return bpf_map_freeze(handle->m_bpf_map_fds[SYSDIG_SYSCALL_CODE_ROUTING_TABLE]);
return bpf_map_freeze(handle->m_bpf_map_fds[SCAP_SYSCALL_CODE_ROUTING_TABLE]);
}
static int32_t populate_syscall_table_map(scap_t *handle)
@ -779,9 +793,9 @@ static int32_t populate_syscall_table_map(scap_t *handle)
p = &uninterested_pair;
}
if(bpf_map_update_elem(handle->m_bpf_map_fds[SYSDIG_SYSCALL_TABLE], &j, p, BPF_ANY) != 0)
if(bpf_map_update_elem(handle->m_bpf_map_fds[SCAP_SYSCALL_TABLE], &j, p, BPF_ANY) != 0)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SYSDIG_SYSCALL_TABLE bpf_map_update_elem < 0");
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_SYSCALL_TABLE bpf_map_update_elem < 0");
return SCAP_FAILURE;
}
}
@ -796,14 +810,14 @@ static int32_t populate_event_table_map(scap_t *handle)
for(j = 0; j < PPM_EVENT_MAX; ++j)
{
const struct ppm_event_info *e = &g_event_info[j];
if(bpf_map_update_elem(handle->m_bpf_map_fds[SYSDIG_EVENT_INFO_TABLE], &j, e, BPF_ANY) != 0)
if(bpf_map_update_elem(handle->m_bpf_map_fds[SCAP_EVENT_INFO_TABLE], &j, e, BPF_ANY) != 0)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SYSDIG_EVENT_INFO_TABLE bpf_map_update_elem < 0");
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_EVENT_INFO_TABLE bpf_map_update_elem < 0");
return SCAP_FAILURE;
}
}
return bpf_map_freeze(handle->m_bpf_map_fds[SYSDIG_EVENT_INFO_TABLE]);
return bpf_map_freeze(handle->m_bpf_map_fds[SCAP_EVENT_INFO_TABLE]);
}
static int32_t populate_fillers_table_map(scap_t *handle)
@ -813,9 +827,9 @@ static int32_t populate_fillers_table_map(scap_t *handle)
for(j = 0; j < PPM_EVENT_MAX; ++j)
{
const struct ppm_event_entry *e = &g_ppm_events[j];
if(bpf_map_update_elem(handle->m_bpf_map_fds[SYSDIG_FILLERS_TABLE], &j, e, BPF_ANY) != 0)
if(bpf_map_update_elem(handle->m_bpf_map_fds[SCAP_FILLERS_TABLE], &j, e, BPF_ANY) != 0)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SYSDIG_FILLERS_TABLE bpf_map_update_elem < 0");
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_FILLERS_TABLE bpf_map_update_elem < 0");
return SCAP_FAILURE;
}
}
@ -829,7 +843,7 @@ static int32_t populate_fillers_table_map(scap_t *handle)
}
}
return bpf_map_freeze(handle->m_bpf_map_fds[SYSDIG_FILLERS_TABLE]);
return bpf_map_freeze(handle->m_bpf_map_fds[SCAP_FILLERS_TABLE]);
}
//
@ -852,19 +866,19 @@ static int32_t calibrate_socket_file_ops()
int32_t scap_bpf_start_capture(scap_t *handle)
{
struct sysdig_bpf_settings settings;
struct scap_bpf_settings settings;
int k = 0;
if(bpf_map_lookup_elem(handle->m_bpf_map_fds[SYSDIG_SETTINGS_MAP], &k, &settings) != 0)
if(bpf_map_lookup_elem(handle->m_bpf_map_fds[SCAP_SETTINGS_MAP], &k, &settings) != 0)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SYSDIG_SETTINGS_MAP bpf_map_lookup_elem < 0");
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_SETTINGS_MAP bpf_map_lookup_elem < 0");
return SCAP_FAILURE;
}
settings.capture_enabled = true;
if(bpf_map_update_elem(handle->m_bpf_map_fds[SYSDIG_SETTINGS_MAP], &k, &settings, BPF_ANY) != 0)
if(bpf_map_update_elem(handle->m_bpf_map_fds[SCAP_SETTINGS_MAP], &k, &settings, BPF_ANY) != 0)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SYSDIG_SETTINGS_MAP bpf_map_update_elem < 0");
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_SETTINGS_MAP bpf_map_update_elem < 0");
return SCAP_FAILURE;
}
@ -880,19 +894,19 @@ int32_t scap_bpf_start_capture(scap_t *handle)
int32_t scap_bpf_stop_capture(scap_t *handle)
{
struct sysdig_bpf_settings settings;
struct scap_bpf_settings settings;
int k = 0;
if(bpf_map_lookup_elem(handle->m_bpf_map_fds[SYSDIG_SETTINGS_MAP], &k, &settings) != 0)
if(bpf_map_lookup_elem(handle->m_bpf_map_fds[SCAP_SETTINGS_MAP], &k, &settings) != 0)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SYSDIG_SETTINGS_MAP bpf_map_lookup_elem < 0");
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_SETTINGS_MAP bpf_map_lookup_elem < 0");
return SCAP_FAILURE;
}
settings.capture_enabled = false;
if(bpf_map_update_elem(handle->m_bpf_map_fds[SYSDIG_SETTINGS_MAP], &k, &settings, BPF_ANY) != 0)
if(bpf_map_update_elem(handle->m_bpf_map_fds[SCAP_SETTINGS_MAP], &k, &settings, BPF_ANY) != 0)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SYSDIG_SETTINGS_MAP bpf_map_update_elem < 0");
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_SETTINGS_MAP bpf_map_update_elem < 0");
return SCAP_FAILURE;
}
@ -901,7 +915,7 @@ int32_t scap_bpf_stop_capture(scap_t *handle)
int32_t scap_bpf_set_snaplen(scap_t* handle, uint32_t snaplen)
{
struct sysdig_bpf_settings settings;
struct scap_bpf_settings settings;
int k = 0;
if(snaplen > RW_MAX_SNAPLEN)
@ -910,16 +924,16 @@ int32_t scap_bpf_set_snaplen(scap_t* handle, uint32_t snaplen)
return SCAP_FAILURE;
}
if(bpf_map_lookup_elem(handle->m_bpf_map_fds[SYSDIG_SETTINGS_MAP], &k, &settings) != 0)
if(bpf_map_lookup_elem(handle->m_bpf_map_fds[SCAP_SETTINGS_MAP], &k, &settings) != 0)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SYSDIG_SETTINGS_MAP bpf_map_lookup_elem < 0");
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_SETTINGS_MAP bpf_map_lookup_elem < 0");
return SCAP_FAILURE;
}
settings.snaplen = snaplen;
if(bpf_map_update_elem(handle->m_bpf_map_fds[SYSDIG_SETTINGS_MAP], &k, &settings, BPF_ANY) != 0)
if(bpf_map_update_elem(handle->m_bpf_map_fds[SCAP_SETTINGS_MAP], &k, &settings, BPF_ANY) != 0)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SYSDIG_SETTINGS_MAP bpf_map_update_elem < 0");
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_SETTINGS_MAP bpf_map_update_elem < 0");
return SCAP_FAILURE;
}
@ -928,20 +942,20 @@ int32_t scap_bpf_set_snaplen(scap_t* handle, uint32_t snaplen)
int32_t scap_bpf_set_fullcapture_port_range(scap_t* handle, uint16_t range_start, uint16_t range_end)
{
struct sysdig_bpf_settings settings;
struct scap_bpf_settings settings;
int k = 0;
if(bpf_map_lookup_elem(handle->m_bpf_map_fds[SYSDIG_SETTINGS_MAP], &k, &settings) != 0)
if(bpf_map_lookup_elem(handle->m_bpf_map_fds[SCAP_SETTINGS_MAP], &k, &settings) != 0)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SYSDIG_SETTINGS_MAP bpf_map_lookup_elem < 0");
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_SETTINGS_MAP bpf_map_lookup_elem < 0");
return SCAP_FAILURE;
}
settings.fullcapture_port_range_start = range_start;
settings.fullcapture_port_range_end = range_end;
if(bpf_map_update_elem(handle->m_bpf_map_fds[SYSDIG_SETTINGS_MAP], &k, &settings, BPF_ANY) != 0)
if(bpf_map_update_elem(handle->m_bpf_map_fds[SCAP_SETTINGS_MAP], &k, &settings, BPF_ANY) != 0)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SYSDIG_SETTINGS_MAP bpf_map_update_elem < 0");
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_SETTINGS_MAP bpf_map_update_elem < 0");
return SCAP_FAILURE;
}
@ -950,20 +964,20 @@ int32_t scap_bpf_set_fullcapture_port_range(scap_t* handle, uint16_t range_start
int32_t scap_bpf_set_statsd_port(scap_t* const handle, const uint16_t port)
{
struct sysdig_bpf_settings settings = {};
struct scap_bpf_settings settings = {};
int k = 0;
if(bpf_map_lookup_elem(handle->m_bpf_map_fds[SYSDIG_SETTINGS_MAP], &k, &settings) != 0)
if(bpf_map_lookup_elem(handle->m_bpf_map_fds[SCAP_SETTINGS_MAP], &k, &settings) != 0)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SYSDIG_SETTINGS_MAP bpf_map_lookup_elem < 0");
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_SETTINGS_MAP bpf_map_lookup_elem < 0");
return SCAP_FAILURE;
}
settings.statsd_port = port;
if(bpf_map_update_elem(handle->m_bpf_map_fds[SYSDIG_SETTINGS_MAP], &k, &settings, BPF_ANY) != 0)
if(bpf_map_update_elem(handle->m_bpf_map_fds[SCAP_SETTINGS_MAP], &k, &settings, BPF_ANY) != 0)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SYSDIG_SETTINGS_MAP bpf_map_update_elem < 0");
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_SETTINGS_MAP bpf_map_update_elem < 0");
return SCAP_FAILURE;
}
@ -972,19 +986,19 @@ int32_t scap_bpf_set_statsd_port(scap_t* const handle, const uint16_t port)
int32_t scap_bpf_disable_dynamic_snaplen(scap_t* handle)
{
struct sysdig_bpf_settings settings;
struct scap_bpf_settings settings;
int k = 0;
if(bpf_map_lookup_elem(handle->m_bpf_map_fds[SYSDIG_SETTINGS_MAP], &k, &settings) != 0)
if(bpf_map_lookup_elem(handle->m_bpf_map_fds[SCAP_SETTINGS_MAP], &k, &settings) != 0)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SYSDIG_SETTINGS_MAP bpf_map_lookup_elem < 0");
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_SETTINGS_MAP bpf_map_lookup_elem < 0");
return SCAP_FAILURE;
}
settings.do_dynamic_snaplen = false;
if(bpf_map_update_elem(handle->m_bpf_map_fds[SYSDIG_SETTINGS_MAP], &k, &settings, BPF_ANY) != 0)
if(bpf_map_update_elem(handle->m_bpf_map_fds[SCAP_SETTINGS_MAP], &k, &settings, BPF_ANY) != 0)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SYSDIG_SETTINGS_MAP bpf_map_update_elem < 0");
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_SETTINGS_MAP bpf_map_update_elem < 0");
return SCAP_FAILURE;
}
@ -1009,20 +1023,20 @@ int32_t scap_bpf_start_dropping_mode(scap_t* handle, uint32_t sampling_ratio)
return SCAP_FAILURE;
}
struct sysdig_bpf_settings settings;
struct scap_bpf_settings settings;
int k = 0;
if(bpf_map_lookup_elem(handle->m_bpf_map_fds[SYSDIG_SETTINGS_MAP], &k, &settings) != 0)
if(bpf_map_lookup_elem(handle->m_bpf_map_fds[SCAP_SETTINGS_MAP], &k, &settings) != 0)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SYSDIG_SETTINGS_MAP bpf_map_lookup_elem < 0");
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_SETTINGS_MAP bpf_map_lookup_elem < 0");
return SCAP_FAILURE;
}
settings.sampling_ratio = sampling_ratio;
settings.dropping_mode = true;
if(bpf_map_update_elem(handle->m_bpf_map_fds[SYSDIG_SETTINGS_MAP], &k, &settings, BPF_ANY) != 0)
if(bpf_map_update_elem(handle->m_bpf_map_fds[SCAP_SETTINGS_MAP], &k, &settings, BPF_ANY) != 0)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SYSDIG_SETTINGS_MAP bpf_map_update_elem < 0");
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_SETTINGS_MAP bpf_map_update_elem < 0");
return SCAP_FAILURE;
}
@ -1031,20 +1045,20 @@ int32_t scap_bpf_start_dropping_mode(scap_t* handle, uint32_t sampling_ratio)
int32_t scap_bpf_stop_dropping_mode(scap_t* handle)
{
struct sysdig_bpf_settings settings;
struct scap_bpf_settings settings;
int k = 0;
if(bpf_map_lookup_elem(handle->m_bpf_map_fds[SYSDIG_SETTINGS_MAP], &k, &settings) != 0)
if(bpf_map_lookup_elem(handle->m_bpf_map_fds[SCAP_SETTINGS_MAP], &k, &settings) != 0)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SYSDIG_SETTINGS_MAP bpf_map_lookup_elem < 0");
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_SETTINGS_MAP bpf_map_lookup_elem < 0");
return SCAP_FAILURE;
}
settings.sampling_ratio = 1;
settings.dropping_mode = false;
if(bpf_map_update_elem(handle->m_bpf_map_fds[SYSDIG_SETTINGS_MAP], &k, &settings, BPF_ANY) != 0)
if(bpf_map_update_elem(handle->m_bpf_map_fds[SCAP_SETTINGS_MAP], &k, &settings, BPF_ANY) != 0)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SYSDIG_SETTINGS_MAP bpf_map_update_elem < 0");
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_SETTINGS_MAP bpf_map_update_elem < 0");
return SCAP_FAILURE;
}
@ -1053,19 +1067,19 @@ int32_t scap_bpf_stop_dropping_mode(scap_t* handle)
int32_t scap_bpf_enable_dynamic_snaplen(scap_t* handle)
{
struct sysdig_bpf_settings settings;
struct scap_bpf_settings settings;
int k = 0;
if(bpf_map_lookup_elem(handle->m_bpf_map_fds[SYSDIG_SETTINGS_MAP], &k, &settings) != 0)
if(bpf_map_lookup_elem(handle->m_bpf_map_fds[SCAP_SETTINGS_MAP], &k, &settings) != 0)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SYSDIG_SETTINGS_MAP bpf_map_lookup_elem < 0");
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_SETTINGS_MAP bpf_map_lookup_elem < 0");
return SCAP_FAILURE;
}
settings.do_dynamic_snaplen = true;
if(bpf_map_update_elem(handle->m_bpf_map_fds[SYSDIG_SETTINGS_MAP], &k, &settings, BPF_ANY) != 0)
if(bpf_map_update_elem(handle->m_bpf_map_fds[SCAP_SETTINGS_MAP], &k, &settings, BPF_ANY) != 0)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SYSDIG_SETTINGS_MAP bpf_map_update_elem < 0");
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_SETTINGS_MAP bpf_map_update_elem < 0");
return SCAP_FAILURE;
}
@ -1074,19 +1088,19 @@ int32_t scap_bpf_enable_dynamic_snaplen(scap_t* handle)
int32_t scap_bpf_enable_page_faults(scap_t* handle)
{
struct sysdig_bpf_settings settings;
struct scap_bpf_settings settings;
int k = 0;
if(bpf_map_lookup_elem(handle->m_bpf_map_fds[SYSDIG_SETTINGS_MAP], &k, &settings) != 0)
if(bpf_map_lookup_elem(handle->m_bpf_map_fds[SCAP_SETTINGS_MAP], &k, &settings) != 0)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SYSDIG_SETTINGS_MAP bpf_map_lookup_elem < 0");
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_SETTINGS_MAP bpf_map_lookup_elem < 0");
return SCAP_FAILURE;
}
settings.page_faults = true;
if(bpf_map_update_elem(handle->m_bpf_map_fds[SYSDIG_SETTINGS_MAP], &k, &settings, BPF_ANY) != 0)
if(bpf_map_update_elem(handle->m_bpf_map_fds[SCAP_SETTINGS_MAP], &k, &settings, BPF_ANY) != 0)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SYSDIG_SETTINGS_MAP bpf_map_update_elem < 0");
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_SETTINGS_MAP bpf_map_update_elem < 0");
return SCAP_FAILURE;
}
@ -1095,19 +1109,19 @@ int32_t scap_bpf_enable_page_faults(scap_t* handle)
int32_t scap_bpf_enable_tracers_capture(scap_t* handle)
{
struct sysdig_bpf_settings settings;
struct scap_bpf_settings settings;
int k = 0;
if(bpf_map_lookup_elem(handle->m_bpf_map_fds[SYSDIG_SETTINGS_MAP], &k, &settings) != 0)
if(bpf_map_lookup_elem(handle->m_bpf_map_fds[SCAP_SETTINGS_MAP], &k, &settings) != 0)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SYSDIG_SETTINGS_MAP bpf_map_lookup_elem < 0");
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_SETTINGS_MAP bpf_map_lookup_elem < 0");
return SCAP_FAILURE;
}
settings.tracers_enabled = true;
if(bpf_map_update_elem(handle->m_bpf_map_fds[SYSDIG_SETTINGS_MAP], &k, &settings, BPF_ANY) != 0)
if(bpf_map_update_elem(handle->m_bpf_map_fds[SCAP_SETTINGS_MAP], &k, &settings, BPF_ANY) != 0)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SYSDIG_SETTINGS_MAP bpf_map_update_elem < 0");
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_SETTINGS_MAP bpf_map_update_elem < 0");
return SCAP_FAILURE;
}
@ -1274,7 +1288,7 @@ static int32_t set_runtime_params(scap_t *handle)
static int32_t set_default_settings(scap_t *handle)
{
struct sysdig_bpf_settings settings;
struct scap_bpf_settings settings;
if(set_boot_time(handle, &settings.boot_time) != SCAP_SUCCESS)
{
@ -1295,9 +1309,9 @@ static int32_t set_default_settings(scap_t *handle)
settings.statsd_port = 8125;
int k = 0;
if(bpf_map_update_elem(handle->m_bpf_map_fds[SYSDIG_SETTINGS_MAP], &k, &settings, BPF_ANY) != 0)
if(bpf_map_update_elem(handle->m_bpf_map_fds[SCAP_SETTINGS_MAP], &k, &settings, BPF_ANY) != 0)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SYSDIG_SETTINGS_MAP bpf_map_update_elem < 0");
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_SETTINGS_MAP bpf_map_update_elem < 0");
return SCAP_FAILURE;
}
@ -1410,9 +1424,9 @@ int32_t scap_bpf_load(scap_t *handle, const char *bpf_probe)
handle->m_devs[online_cpu].m_fd = pmu_fd;
if(bpf_map_update_elem(handle->m_bpf_map_fds[SYSDIG_PERF_MAP], &j, &pmu_fd, BPF_ANY) != 0)
if(bpf_map_update_elem(handle->m_bpf_map_fds[SCAP_PERF_MAP], &j, &pmu_fd, BPF_ANY) != 0)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SYSDIG_PERF_MAP bpf_map_update_elem < 0: %s", scap_strerror(handle, errno));
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "SCAP_PERF_MAP bpf_map_update_elem < 0: %s", scap_strerror(handle, errno));
return SCAP_FAILURE;
}
@ -1455,19 +1469,20 @@ int32_t scap_bpf_get_stats(scap_t* handle, OUT scap_stats* stats)
for(j = 0; j < handle->m_ncpus; j++)
{
struct sysdig_bpf_per_cpu_state v;
if(bpf_map_lookup_elem(handle->m_bpf_map_fds[SYSDIG_LOCAL_STATE_MAP], &j, &v))
struct scap_bpf_per_cpu_state v;
if(bpf_map_lookup_elem(handle->m_bpf_map_fds[SCAP_LOCAL_STATE_MAP], &j, &v))
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "Error looking up local state %d\n", j);
return SCAP_FAILURE;
}
stats->n_evts += v.n_evts;
stats->n_drops_buffer += handle->m_devs[j].m_evt_lost + v.n_drops_buffer;
stats->n_drops_buffer += v.n_drops_buffer;
stats->n_drops_scratch_map += v.n_drops_scratch_map;
stats->n_drops_pf += v.n_drops_pf;
stats->n_drops_bug += v.n_drops_bug;
stats->n_drops += handle->m_devs[j].m_evt_lost +
v.n_drops_buffer +
stats->n_drops += v.n_drops_buffer +
v.n_drops_scratch_map +
v.n_drops_pf +
v.n_drops_bug;
}
@ -1481,8 +1496,8 @@ int32_t scap_bpf_get_n_tracepoint_hit(scap_t* handle, long* ret)
for(j = 0; j < handle->m_ncpus; j++)
{
struct sysdig_bpf_per_cpu_state v;
if(bpf_map_lookup_elem(handle->m_bpf_map_fds[SYSDIG_LOCAL_STATE_MAP], &j, &v))
struct scap_bpf_per_cpu_state v;
if(bpf_map_lookup_elem(handle->m_bpf_map_fds[SCAP_LOCAL_STATE_MAP], &j, &v))
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "Error looking up local state %d\n", j);
return SCAP_FAILURE;

View File

@ -124,13 +124,7 @@ static inline int32_t scap_bpf_advance_to_evt(scap_t *handle, uint16_t cpuid, bo
break;
}
}
else if(e->type == PERF_RECORD_LOST)
{
struct perf_lost_sample *lost = (struct perf_lost_sample *) e;
ASSERT(*len >= sizeof(*lost));
dev->m_evt_lost += lost->lost;
}
else
else if(e->type != PERF_RECORD_LOST)
{
printf("Unknown event type=%d size=%d\n",
e->type, e->size);

View File

@ -378,6 +378,9 @@ int32_t scap_proc_fill_cgroups(scap_t *handle, struct scap_threadinfo* tinfo, co
char* subsys_list;
char* cgroup;
char* scratch;
// Default subsys list for cgroups v2 unified hierarchy.
// These are the ones we actually use in cri container engine.
char default_subsys_list[] = "cpu,memory,cpuset";
// id
token = strtok_r(line, ":", &scratch);
@ -406,20 +409,52 @@ int32_t scap_proc_fill_cgroups(scap_t *handle, struct scap_threadinfo* tinfo, co
// on CentOS 6 (has been added from Glibc 2.19)
if(subsys_list-token-strlen(token) > 1)
{
// skip cgroups like this:
// 0::/init.scope
continue;
}
// cgroup should be the only thing remaining so use newline as the delimiter.
cgroup = strtok_r(NULL, "\n", &scratch);
if(cgroup == NULL)
// Subsys list empty (ie: it contains cgroup path instead)!
//
// See https://man7.org/linux/man-pages/man7/cgroups.7.html:
// 5:cpuacct,cpu,cpuset:/daemons
//
// The colon-separated fields are, from left to right:
//
// 1. For cgroups version 1 hierarchies, this field contains
// a unique hierarchy ID number that can be matched to a
// hierarchy ID in /proc/cgroups. For the cgroups version
// 2 hierarchy, this field contains the value 0.
//
// 2. For cgroups version 1 hierarchies, this field contains
// a comma-separated list of the controllers bound to the
// hierarchy. For the cgroups version 2 hierarchy, this
// field is empty.
//
// 3. This field contains the pathname of the control group
// in the hierarchy to which the process belongs. This
// pathname is relative to the mount point of the
// hierarchy.
//
// -> for cgroup2: id is always 0 and subsys list is always empty (single unified hierarchy)
// -> for cgroup1: skip subsys empty because it means controller is not mounted on any hierarchy
if (handle->m_cgroup_version == 2 && strcmp(token, "0") == 0)
{
cgroup = subsys_list;
subsys_list = default_subsys_list; // force-set a default subsys list
} else
{
// skip cgroups like this:
// 0::/init.scope
continue;
}
} else
{
ASSERT(false);
fclose(f);
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "Did not find cgroup in cgroup file %s",
filename);
return SCAP_FAILURE;
// cgroup should be the only thing remaining so use newline as the delimiter.
cgroup = strtok_r(NULL, "\n", &scratch);
if(cgroup == NULL)
{
ASSERT(false);
fclose(f);
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "Did not find cgroup in cgroup file %s",
filename);
return SCAP_FAILURE;
}
}
while((token = strtok_r(subsys_list, ",", &scratch)) != NULL)
@ -642,6 +677,36 @@ static int32_t scap_proc_add_from_proc(scap_t* handle, uint32_t tid, char* procd
int32_t res = SCAP_SUCCESS;
struct stat dirstat;
if (handle->m_cgroup_version == 0)
{
snprintf(dir_name, sizeof(dir_name), "%s/filesystems", procdirname);
f = fopen(dir_name, "r");
if (f)
{
while(fgets(line, sizeof(line), f) != NULL)
{
// NOTE: we do not support mixing cgroups v1 v2 controllers.
// Neither docker nor podman support this: https://github.com/docker/for-linux/issues/1256
if (strstr(line, "cgroup2"))
{
handle->m_cgroup_version = 2;
break;
}
if (strstr(line, "cgroup"))
{
handle->m_cgroup_version = 1;
}
}
fclose(f);
} else
{
ASSERT(false);
snprintf(error, SCAP_LASTERR_SIZE, "failed to fetch cgroup version information");
return SCAP_FAILURE;
}
}
snprintf(dir_name, sizeof(dir_name), "%s/%u/", procdirname, tid);
snprintf(filename, sizeof(filename), "%sexe", dir_name);
@ -1520,6 +1585,7 @@ int32_t scap_check_suppressed(scap_t *handle, scap_evt *pevent, bool *suppressed
case PPME_SYSCALL_VFORK_20_X:
case PPME_SYSCALL_EXECVE_19_X:
case PPME_SYSCALL_EXECVEAT_X:
case PPME_SYSCALL_CLONE3_X:
lens = (uint16_t *)((char *)pevent + sizeof(struct ppm_evt_hdr));
valptr = (char *)lens + pevent->nparams * sizeof(uint16_t);

View File

@ -355,6 +355,9 @@ const struct ppm_syscall_desc g_syscall_info_table[PPM_SC_MAX] = {
/*PPM_SC_UMOUNT2*/ { EC_FILE, (enum ppm_event_flags)(EF_NONE), "umount2" },
/*PPM_SC_EXECVE*/ { EC_SYSTEM, (enum ppm_event_flags)(EF_NONE), "execve" },
/*PPM_SC_EXECVEAT*/ { EC_SYSTEM, (enum ppm_event_flags)(EF_NONE), "execveat" },
/*PPM_SC_COPY_FILE_RANGE*/ {EC_FILE, (enum ppm_event_flags)(EF_NONE), "copy_file_range" },
/*PPM_SC_CLONE*/ {EC_PROCESS, (enum ppm_event_flags)(EF_NONE), "clone" },
/*PPM_SC_CLONE3*/ {EC_PROCESS, (enum ppm_event_flags)(EF_NONE), "clone3" },
};
bool validate_info_table_size()

View File

@ -149,11 +149,13 @@ if(NOT MINIMAL_BUILD)
list(APPEND SINSP_SOURCES
container_engine/docker/docker_linux.cpp
container_engine/docker/connection_linux.cpp
container_engine/docker/podman.cpp
container_engine/libvirt_lxc.cpp
container_engine/lxc.cpp
container_engine/mesos.cpp
container_engine/rkt.cpp
container_engine/bpm.cpp
procfs_utils.cpp
runc.cpp)
endif()

View File

@ -25,6 +25,7 @@ limitations under the License.
#include "container_engine/docker/docker_win.h"
#else
#include "container_engine/docker/docker_linux.h"
#include "container_engine/docker/podman.h"
#endif
#include "container_engine/rkt.h"
#include "container_engine/libvirt_lxc.h"
@ -534,6 +535,11 @@ void sinsp_container_manager::create_engines()
}
#else
#ifndef _WIN32
{
auto podman_engine = std::make_shared<container_engine::podman>(*this);
m_container_engines.push_back(podman_engine);
m_container_engine_by_type[CT_PODMAN] = podman_engine;
}
{
auto docker_engine = std::make_shared<container_engine::docker_linux>(*this);
m_container_engines.push_back(docker_engine);
@ -634,6 +640,13 @@ void sinsp_container_manager::set_cri_socket_path(const std::string &path)
#endif
}
void sinsp_container_manager::add_cri_socket_path(const std::string &path)
{
#if !defined(MINIMAL_BUILD) && defined(HAS_CAPTURE)
libsinsp::container_engine::cri::add_cri_socket_path(path);
#endif
}
void sinsp_container_manager::set_cri_timeout(int64_t timeout_ms)
{
#if !defined(MINIMAL_BUILD) && defined(HAS_CAPTURE)

View File

@ -151,6 +151,7 @@ public:
void set_query_docker_image_info(bool query_image_info);
void set_cri_extra_queries(bool extra_queries);
void set_cri_socket_path(const std::string& path);
void add_cri_socket_path(const std::string &path);
void set_cri_timeout(int64_t timeout_ms);
void set_cri_async(bool async);
void set_cri_delay(uint64_t delay_ms);

View File

@ -207,20 +207,42 @@ bool cri_async_source::lookup_sync(const libsinsp::cgroup_limits::cgroup_limits_
cri::cri(container_cache_interface &cache) : container_engine_base(cache)
{
if(s_cri_unix_socket_path.empty()) {
return;
}
auto cri_path = scap_get_host_root() + s_cri_unix_socket_path;
struct stat s = {};
if(stat(cri_path.c_str(), &s) != 0 || (s.st_mode & S_IFMT) != S_IFSOCK) {
return;
}
m_cri = std::unique_ptr<libsinsp::cri::cri_interface>(new libsinsp::cri::cri_interface(cri_path));
if(!m_cri->is_ok())
if (s_cri_unix_socket_paths.empty())
{
m_cri.reset(nullptr);
// Default value when empty
s_cri_unix_socket_paths.emplace_back("/run/containerd/containerd.sock");
}
// Try all specified unix socket paths
// NOTE: having multiple container runtimes on the same host is a sporadic case,
// so we wouldn't make things complex to support that.
// On the other hand, specifying multiple unix socket paths (and using only the first match)
// will solve the "same config, multiple hosts" use case.
for (auto &p : s_cri_unix_socket_paths)
{
if(p.empty())
{
continue;
}
auto cri_path = scap_get_host_root() + p;
struct stat s = {};
if(stat(cri_path.c_str(), &s) != 0 || (s.st_mode & S_IFMT) != S_IFSOCK)
{
continue;
}
m_cri = std::unique_ptr<libsinsp::cri::cri_interface>(new libsinsp::cri::cri_interface(cri_path));
if(!m_cri->is_ok())
{
m_cri.reset(nullptr);
}
else
{
// Store used unix_socket_path
s_cri_unix_socket_path = p;
break;
}
}
}
@ -235,7 +257,13 @@ void cri::cleanup()
void cri::set_cri_socket_path(const std::string& path)
{
s_cri_unix_socket_path = path;
s_cri_unix_socket_paths.clear();
add_cri_socket_path(path);
}
void cri::add_cri_socket_path(const std::string& path)
{
s_cri_unix_socket_paths.push_back(path);
}
void cri::set_cri_timeout(int64_t timeout_ms)
@ -260,9 +288,9 @@ void cri::set_cri_delay(uint64_t delay_ms)
bool cri::resolve(sinsp_threadinfo *tinfo, bool query_os_for_missing_info)
{
container_cache_interface *cache = &container_cache();
std::string container_id;
std::string container_id, cgroup;
if(!matches_runc_cgroups(tinfo, CRI_CGROUP_LAYOUT, container_id))
if(!matches_runc_cgroups(tinfo, CRI_CGROUP_LAYOUT, container_id, cgroup))
{
return false;
}

View File

@ -82,6 +82,7 @@ public:
void update_with_size(const std::string& container_id) override;
void cleanup() override;
static void set_cri_socket_path(const std::string& path);
static void add_cri_socket_path(const std::string& path);
static void set_cri_timeout(int64_t timeout_ms);
static void set_extra_queries(bool extra_queries);
static void set_async(bool async_limits);

View File

@ -55,7 +55,7 @@ void docker_async_source::run_impl()
sinsp_container_info res;
res.m_lookup_state = sinsp_container_lookup_state::SUCCESSFUL;
res.m_type = CT_DOCKER;
res.m_type = request.container_type;
res.m_id = request.container_id;
if(!parse_docker(request, res))
@ -391,7 +391,7 @@ void docker_async_source::fetch_image_info(const docker_lookup_request& request,
"docker_async url: %s",
url.c_str());
if(!(m_connection.get_docker(request, url, img_json) == docker_connection::RESP_OK))
if(m_connection.get_docker(request, url, img_json) != docker_connection::RESP_OK)
{
g_logger.format(sinsp_logger::SEV_ERROR,
"docker_async (%s) image (%s): Could not fetch image info",
@ -420,44 +420,122 @@ void docker_async_source::fetch_image_info(const docker_lookup_request& request,
parse_image_info(container, img_root);
}
void docker_async_source::parse_image_info(sinsp_container_info& container, const Json::Value& img)
void docker_async_source::fetch_image_info_from_list(const docker_lookup_request& request, sinsp_container_info& container)
{
// img_root["RepoDigests"] contains only digests for images pulled from registries.
// If an image gets retagged and is never pushed to any registry, we will not find
// that entry in container.m_imagerepo. Also, for locally built images we have the
// same issue. This leads to container.m_imagedigest being empty as well.
//
// Each individual digest looks like e.g.
// "docker.io/library/redis@sha256:b6a9fc3535388a6fc04f3bdb83fb4d9d0b4ffd85e7609a6ff2f0f731427823e3"
// so we need to split it at the `@` (the part before is the repo,
// the part after is the digest)
std::unordered_set<std::string> imageDigestSet;
for(const auto& rdig : img["RepoDigests"])
Json::Reader reader;
g_logger.format(sinsp_logger::SEV_DEBUG,
"docker_async (%s): Fetching image list",
request.container_id.c_str());
std::string img_json;
std::string url = "/images/json?digests=1";
g_logger.format(sinsp_logger::SEV_DEBUG,
"docker_async url: %s",
url.c_str());
if(!(m_connection.get_docker(request, url, img_json) == docker_connection::RESP_OK))
{
if(rdig.isString())
g_logger.format(sinsp_logger::SEV_ERROR,
"docker_async (%s): Could not fetch image list",
request.container_id.c_str());
return;
}
g_logger.format(sinsp_logger::SEV_DEBUG,
"docker_async (%s): Image list fetch returned \"%s\"",
request.container_id.c_str(),
img_json.c_str());
Json::Value img_root;
if(!reader.parse(img_json, img_root))
{
g_logger.format(sinsp_logger::SEV_ERROR,
"docker_async (%s): Could not parse json image list \"%s\"",
request.container_id.c_str(),
img_json.c_str());
return;
}
const std::string match_name = container.m_imagerepo + ':' + container.m_imagetag;
for(const auto& img : img_root)
{
// the "Names" field is podman specific. we could parse repotags
// twice but this is less effort and we only call this function
// for podman anyway
const auto& names = img["Names"];
if(!names.isArray())
{
std::string repodigest = rdig.asString();
std::string digest = repodigest.substr(repodigest.find('@')+1);
imageDigestSet.insert(digest);
if(container.m_imagerepo.empty())
return;
}
for(const auto& name : names)
{
if(name == match_name)
{
container.m_imagerepo = repodigest.substr(0, repodigest.find('@'));
}
if(repodigest.find(container.m_imagerepo) != std::string::npos)
{
container.m_imagedigest = digest;
break;
std::string imgstr = img["Id"].asString();
size_t cpos = imgstr.find(':');
if(cpos != std::string::npos)
{
imgstr = imgstr.substr(cpos + 1);
}
container.m_imageid = std::move(imgstr);
parse_image_info(container, img);
return;
}
}
}
}
// fix image digest for locally tagged images or multiple repo digests.
// Case 1: One repo digest with many tags.
// Case 2: Many repo digests with the same digest value.
if(container.m_imagedigest.empty() && imageDigestSet.size() == 1) {
container.m_imagedigest = *imageDigestSet.begin();
void docker_async_source::parse_image_info(sinsp_container_info& container, const Json::Value& img)
{
const auto& podman_digest = img["Digest"];
if(podman_digest.isString())
{
// img["Digest"] if present is the digest in the form we need it
// e.g. "sha256:b6a9fc3535388a6fc04f3bdb83fb4d9d0b4ffd85e7609a6ff2f0f731427823e3"
// so just use it directly
container.m_imagedigest = podman_digest.asString();
}
else
{
// img_root["RepoDigests"] contains only digests for images pulled from registries.
// If an image gets retagged and is never pushed to any registry, we will not find
// that entry in container.m_imagerepo. Also, for locally built images we have the
// same issue. This leads to container.m_imagedigest being empty as well.
//
// Each individual digest looks like e.g.
// "docker.io/library/redis@sha256:b6a9fc3535388a6fc04f3bdb83fb4d9d0b4ffd85e7609a6ff2f0f731427823e3"
// so we need to split it at the `@` (the part before is the repo,
// the part after is the digest)
std::unordered_set<std::string> imageDigestSet;
for(const auto& rdig : img["RepoDigests"])
{
if(rdig.isString())
{
std::string repodigest = rdig.asString();
std::string digest = repodigest.substr(repodigest.find('@')+1);
imageDigestSet.insert(digest);
if(container.m_imagerepo.empty())
{
container.m_imagerepo = repodigest.substr(0, repodigest.find('@'));
}
if(repodigest.find(container.m_imagerepo) != std::string::npos)
{
container.m_imagedigest = digest;
break;
}
}
}
// fix image digest for locally tagged images or multiple repo digests.
// Case 1: One repo digest with many tags.
// Case 2: Many repo digests with the same digest value.
if(container.m_imagedigest.empty() && imageDigestSet.size() == 1) {
container.m_imagedigest = *imageDigestSet.begin();
}
}
for(const auto& rtag : img["RepoTags"])
{
if(rtag.isString())
@ -480,54 +558,87 @@ void docker_async_source::get_image_info(const docker_lookup_request& request, s
{
container.m_image = root["Config"]["Image"].asString();
// podman has the image *name*, not the *id* in the Image field
// detect that with the presence of '/' in the field
std::string imgstr = root["Image"].asString();
size_t cpos = imgstr.find(':');
if(cpos != std::string::npos)
if(imgstr.find('/') == std::string::npos)
{
container.m_imageid = imgstr.substr(cpos + 1);
// no '/' in the Image field, assume it's a Docker image id
size_t cpos = imgstr.find(':');
if(cpos != std::string::npos)
{
container.m_imageid = imgstr.substr(cpos + 1);
}
// containers can be spawned using just the imageID as image name,
// with or without the hash prefix (e.g. sha256:)
//
// e.g. an image with the id `sha256:ddcca4b8a6f0367b5de2764dfe76b0a4bfa6d75237932185923705da47004347`
// can be used to run a container as:
// - docker run sha256:ddcca4b8a6f0367b5de2764dfe76b0a4bfa6d75237932185923705da47004347
// - docker run ddcca4b8a6f0367b5de2764dfe76b0a4bfa6d75237932185923705da47004347
// - docker run sha256:ddcca4
// - docker run ddcca4
//
// in all these cases we need to determine the image repo/tag
// via the API (in `fetch_image_info()`)
//
// otherwise we assume the name passed to `docker run`
// (available in container.m_image) is the repo name like `redis`
// and use that to determine the name and tag
bool no_name = sinsp_utils::startswith(container.m_imageid, container.m_image) ||
sinsp_utils::startswith(imgstr, container.m_image);
if(!no_name || !m_query_image_info)
{
std::string hostname, port;
sinsp_utils::split_container_image(container.m_image,
hostname,
port,
container.m_imagerepo,
container.m_imagetag,
container.m_imagedigest,
false);
}
if(m_query_image_info && !container.m_imageid.empty() &&
(no_name || container.m_imagedigest.empty() || container.m_imagetag.empty()))
{
fetch_image_info(request, container);
}
if(container.m_imagetag.empty())
{
container.m_imagetag = "latest";
}
}
// containers can be spawned using just the imageID as image name,
// with or without the hash prefix (e.g. sha256:)
//
// e.g. an image with the id `sha256:ddcca4b8a6f0367b5de2764dfe76b0a4bfa6d75237932185923705da47004347`
// can be used to run a container as:
// - docker run sha256:ddcca4b8a6f0367b5de2764dfe76b0a4bfa6d75237932185923705da47004347
// - docker run ddcca4b8a6f0367b5de2764dfe76b0a4bfa6d75237932185923705da47004347
// - docker run sha256:ddcca4
// - docker run ddcca4
//
// in all these cases we need to determine the image repo/tag
// via the API (in `fetch_image_info()`)
//
// otherwise we assume the name passed to `docker run`
// (available in container.m_image) is the repo name like `redis`
// and use that to determine the name and tag
bool no_name = sinsp_utils::startswith(container.m_imageid, container.m_image) ||
sinsp_utils::startswith(imgstr, container.m_image);
if(!no_name || !m_query_image_info)
else
{
// a '/' is present in the Image field. Parse it into parts
std::string hostname, port;
sinsp_utils::split_container_image(container.m_image,
sinsp_utils::split_container_image(imgstr,
hostname,
port,
container.m_imagerepo,
container.m_imagetag,
container.m_imagedigest,
false);
// we need the tag set in the call to `fetch_image_from_list`
// so set it here instead of after the if/else
if(container.m_imagetag.empty())
{
container.m_imagetag = "latest";
}
// we don't have the image id so we need to list all images
// and find the matching one by comparing the repo names
if(m_query_image_info)
{
fetch_image_info_from_list(request, container);
}
}
if(m_query_image_info && !container.m_imageid.empty() &&
(no_name || container.m_imagedigest.empty() || container.m_imagetag.empty()))
{
fetch_image_info(request, container);
}
if(container.m_imagetag.empty())
{
container.m_imagetag = "latest";
}
}
void docker_async_source::parse_json_mounts(const Json::Value &mnt_obj, vector<sinsp_container_info::container_mount_info> &mounts)
{
@ -549,8 +660,8 @@ bool docker_async_source::parse_docker(const docker_lookup_request& request, sin
string json;
g_logger.format(sinsp_logger::SEV_DEBUG,
"docker_async (%s): Looking up info for container",
request.container_id.c_str());
"docker_async (%s): Looking up info for container via socket %s",
request.container_id.c_str(), request.docker_socket.c_str());
std::string api_request = "/containers/" + request.container_id + "/json";
if(request.request_rw_size)
@ -651,6 +762,8 @@ bool docker_async_source::parse_docker(const docker_lookup_request& request, sin
if(parse_docker(docker_lookup_request(secondary_container_id,
request.docker_socket,
request.container_type,
request.uid,
false /*don't request size since we just need the IP*/),
pcnt))
{
@ -722,6 +835,18 @@ bool docker_async_source::parse_docker(const docker_lookup_request& request, sin
}
}
if(request.container_type == sinsp_container_type::CT_PODMAN)
{
if(request.uid == 0)
{
container.m_labels.erase("podman_owner_uid");
}
else
{
container.m_labels["podman_owner_uid"] = to_string(request.uid);
}
}
const Json::Value& env_vars = config_obj["Env"];
for(const auto& env_var : env_vars)

View File

@ -74,6 +74,11 @@ private:
// Fetch the image info for the current container's m_imageid
void fetch_image_info(const docker_lookup_request& request, sinsp_container_info& container);
// Podman reports image repository/tag instead of the image id,
// so to fetch the image digest we need to list all the images,
// find one with matching repository/tag and get the digest from there
void fetch_image_info_from_list(const docker_lookup_request& request, sinsp_container_info& container);
container_cache_interface *m_cache;
docker_connection m_connection;
static bool m_query_image_info;

View File

@ -18,7 +18,7 @@ docker_base::resolve_impl(sinsp_threadinfo *tinfo, const docker_lookup_request&
g_logger.log("docker_async: Creating docker async source",
sinsp_logger::SEV_DEBUG);
uint64_t max_wait_ms = 10000;
docker_async_source *src = new docker_async_source(docker_async_source::NO_WAIT_LOOKUP, max_wait_ms, cache);
auto src = new docker_async_source(docker_async_source::NO_WAIT_LOOKUP, max_wait_ms, cache);
m_docker_info_source.reset(src);
}
@ -31,21 +31,21 @@ docker_base::resolve_impl(sinsp_threadinfo *tinfo, const docker_lookup_request&
if(!query_os_for_missing_info)
{
auto container = std::make_shared<sinsp_container_info>();
container->m_type = CT_DOCKER;
container->m_type = request.container_type;
container->m_id = request.container_id;
cache->notify_new_container(*container);
return true;
}
#ifdef HAS_CAPTURE
if(cache->should_lookup(request.container_id, CT_DOCKER))
if(cache->should_lookup(request.container_id, request.container_type))
{
g_logger.format(sinsp_logger::SEV_DEBUG,
"docker_async (%s): No existing container info",
request.container_id.c_str());
// give docker a chance to return metadata for this container
cache->set_lookup_status(request.container_id, CT_DOCKER, sinsp_container_lookup_state::STARTED);
cache->set_lookup_status(request.container_id, request.container_type, sinsp_container_lookup_state::STARTED);
parse_docker_async(request, cache);
}
#endif

View File

@ -35,9 +35,9 @@ std::string docker_linux::m_docker_sock = "/var/run/docker.sock";
bool docker_linux::resolve(sinsp_threadinfo *tinfo, bool query_os_for_missing_info)
{
std::string container_id;
std::string container_id, cgroup;
if(!matches_runc_cgroups(tinfo, DOCKER_CGROUP_LAYOUT, container_id))
if(!matches_runc_cgroups(tinfo, DOCKER_CGROUP_LAYOUT, container_id, cgroup))
{
return false;
}
@ -45,6 +45,8 @@ bool docker_linux::resolve(sinsp_threadinfo *tinfo, bool query_os_for_missing_in
return resolve_impl(tinfo, docker_lookup_request(
container_id,
m_docker_sock,
CT_DOCKER,
0,
false), query_os_for_missing_info);
}
@ -65,6 +67,6 @@ void docker_linux::update_with_size(const std::string &container_id)
container_id.c_str());
sinsp_container_info result;
docker_lookup_request instruction(container_id, m_docker_sock, true /*request rw size*/);
docker_lookup_request instruction(container_id, m_docker_sock, CT_DOCKER, 0, true /*request rw size*/);
(void)m_docker_info_source->lookup(instruction, result, cb);
}

View File

@ -42,12 +42,9 @@ bool docker_win::resolve(sinsp_threadinfo *tinfo, bool query_os_for_missing_info
return resolve_impl(tinfo, docker_async_instruction(
container_id,
"",
CT_DOCKER,
0,
false), query_os_for_missing_info);
}
void docker_win::update_with_size(const std::string &container_id)
{
// not supported
}
#endif // CYGWING_AGENT

View File

@ -13,7 +13,6 @@ public:
// implement container_engine_base
bool resolve(sinsp_threadinfo *tinfo, bool query_os_for_missing_info) override;
void update_with_size(const std::string& container_id) override;
private:
static std::string s_incomplete_info_name;

View File

@ -1,19 +1,27 @@
#pragma once
#include "container_engine/sinsp_container_type.h"
namespace libsinsp {
namespace container_engine {
struct docker_lookup_request
{
docker_lookup_request() :
container_type(CT_DOCKER),
uid(0),
request_rw_size(false)
{}
docker_lookup_request(const std::string& container_id_value,
const std::string& docker_socket_value,
sinsp_container_type container_type_value,
unsigned long uid_value,
bool rw_size_value) :
container_id(container_id_value),
docker_socket(docker_socket_value),
container_type(container_type_value),
uid(uid_value),
request_rw_size(rw_size_value)
{}
@ -29,6 +37,16 @@ struct docker_lookup_request
return docker_socket < rhs.docker_socket;
}
if(container_type != rhs.container_type)
{
return container_type < rhs.container_type;
}
if(uid != rhs.uid)
{
return uid < rhs.uid;
}
return request_rw_size < rhs.request_rw_size;
}
@ -36,11 +54,15 @@ struct docker_lookup_request
{
return container_id == rhs.container_id &&
docker_socket == rhs.docker_socket &&
container_type == rhs.container_type &&
uid == rhs.uid &&
request_rw_size == rhs.request_rw_size;
}
std::string container_id;
std::string docker_socket;
sinsp_container_type container_type;
unsigned long uid;
bool request_rw_size;
};

View File

@ -0,0 +1,144 @@
/*
Copyright (C) 2021 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "podman.h"
#include "container_engine/docker/lookup_request.h"
#include "procfs_utils.h"
#include "runc.h"
#include "sinsp.h"
#include <fstream>
using namespace libsinsp::container_engine;
using namespace libsinsp::runc;
std::string podman::m_api_sock = "/run/podman/podman.sock";
namespace {
constexpr const cgroup_layout ROOT_PODMAN_CGROUP_LAYOUT[] = {
{"/libpod-", ".scope"}, // podman
{nullptr, nullptr}
};
std::string get_systemd_cgroup(const sinsp_threadinfo *tinfo)
{
// the kernel driver does not return cgroups without subsystems (e.g. name=systemd)
// in the cgroups field, so we have to do a check here, and load /proc/pid/cgroups
// ourselves if needed
for(const auto& it : tinfo->m_cgroups)
{
if(it.first == "name=systemd")
{
return it.second;
}
}
std::stringstream cgroups_file;
cgroups_file << scap_get_host_root() << "/proc/" << tinfo->m_tid << "/cgroup";
std::ifstream cgroups(cgroups_file.str());
return libsinsp::procfs_utils::get_systemd_cgroup(cgroups);
}
int get_userns_root_uid(const sinsp_threadinfo *tinfo)
{
std::stringstream uid_map_file;
uid_map_file << scap_get_host_root() << "/proc/" << tinfo->m_tid << "/uid_map";
std::ifstream uid_map(uid_map_file.str());
return libsinsp::procfs_utils::get_userns_root_uid(uid_map);
}
// Check whether `tinfo` belongs to a podman container
//
// Returns the uid of the container owner:
// 0 for root containers,
// >0 for rootless containers,
// NO_MATCH if the process is not in a podman container
int detect_podman(const sinsp_threadinfo *tinfo, std::string& container_id)
{
std::string cgroup;
if(matches_runc_cgroups(tinfo, ROOT_PODMAN_CGROUP_LAYOUT, container_id, cgroup))
{
// User: /user.slice/user-1000.slice/user@1000.service/user.slice/libpod-$ID.scope/container
// Root: /machine.slice/libpod-$ID.scope/container
int uid;
if (sscanf(cgroup.c_str(), "/user.slice/user-%d.slice/", &uid) == 1)
{
return uid;
}
return 0; // root
}
std::string systemd_cgroup = get_systemd_cgroup(tinfo);
if(systemd_cgroup.empty())
{
// can't get the cgroup name
return libsinsp::procfs_utils::NO_MATCH;
}
size_t pos = systemd_cgroup.find("podman-");
if(pos == std::string::npos)
{
return libsinsp::procfs_utils::NO_MATCH;
}
int podman_pid; // unused except to set the sscanf return value
char c; // ^ same
if(sscanf(systemd_cgroup.c_str() + pos, "podman-%d.scope/%c", &podman_pid, &c) != 2)
{
// cgroup doesn't match the expected pattern
return libsinsp::procfs_utils::NO_MATCH;
}
if(!match_one_container_id(systemd_cgroup, ".scope/", "", container_id))
{
return libsinsp::procfs_utils::NO_MATCH;
}
int uid = get_userns_root_uid(tinfo);
if(uid == 0)
{
// root doesn't spawn rootless containers
return libsinsp::procfs_utils::NO_MATCH;
}
return uid;
}
}
bool podman::resolve(sinsp_threadinfo *tinfo, bool query_os_for_missing_info)
{
std::string container_id, api_sock;
int uid = detect_podman(tinfo, container_id);
switch(uid)
{
case 0: // root, use the default socket
api_sock = m_api_sock;
break;
case libsinsp::procfs_utils::NO_MATCH:
return false;
default: // rootless container, use the user's socket
api_sock = "/run/user/" + std::to_string(uid) + "/podman/podman.sock";
break;
}
docker_lookup_request request(container_id, api_sock, CT_PODMAN, uid, false);
return resolve_impl(tinfo, request, query_os_for_missing_info);
}

View File

@ -0,0 +1,21 @@
#pragma once
#include "container_engine/docker/base.h"
namespace libsinsp {
namespace container_engine {
class podman : public docker_base
{
public:
podman(container_cache_interface& cache): docker_base(cache) {}
private:
static std::string m_api_sock;
// implement container_engine_base
bool resolve(sinsp_threadinfo *tinfo, bool query_os_for_missing_info) override;
};
}
}

View File

@ -30,4 +30,5 @@ enum sinsp_container_type
CT_CRIO = 8,
CT_BPM = 9,
CT_STATIC = 10,
CT_PODMAN = 11,
};

View File

@ -45,7 +45,8 @@ static inline bool is_docker_compatible(sinsp_container_type t)
return t == CT_DOCKER ||
t == CT_CRI ||
t == CT_CONTAINERD ||
t == CT_CRIO;
t == CT_CRIO ||
t == CT_PODMAN;
}
/**

View File

@ -33,10 +33,11 @@ bool pod_uses_host_netns(const runtime::v1alpha2::PodSandboxStatusResponse& resp
namespace libsinsp {
namespace cri {
std::string s_cri_unix_socket_path = "/run/containerd/containerd.sock";
std::vector<std::string> s_cri_unix_socket_paths;
int64_t s_cri_timeout = 1000;
int64_t s_cri_size_timeout = 10000;
sinsp_container_type s_cri_runtime_type = CT_CRI;
std::string s_cri_unix_socket_path;
bool s_cri_extra_queries = true;
cri_interface::cri_interface(const std::string& cri_path)
@ -57,9 +58,8 @@ cri_interface::cri_interface(const std::string& cri_path)
if (!status.ok())
{
g_logger.format(sinsp_logger::SEV_NOTICE, "cri: CRI runtime returned an error after version check at %s: %s",
s_cri_unix_socket_path.c_str(), status.error_message().c_str());
cri_path.c_str(), status.error_message().c_str());
m_cri.reset(nullptr);
s_cri_unix_socket_path = "";
return;
}
@ -78,7 +78,6 @@ cri_interface::cri_interface(const std::string& cri_path)
{
m_cri_runtime_type = CT_CRI;
}
s_cri_runtime_type = m_cri_runtime_type;
}

View File

@ -37,8 +37,10 @@ namespace libsinsp {
namespace cri {
// these shouldn't be globals but we still need references to *the* CRI runtime
extern std::string s_cri_unix_socket_path;
extern std::vector<std::string> s_cri_unix_socket_paths;
extern int64_t s_cri_timeout;
// TODO: drop these 2 below
extern std::string s_cri_unix_socket_path;
extern sinsp_container_type s_cri_runtime_type;
extern bool s_cri_extra_queries;

View File

@ -48,6 +48,8 @@ typedef enum filtercheck_field_flags
EPF_PRINT_ONLY = 1 << 1, ///< this field can only be printed.
EPF_REQUIRES_ARGUMENT = 1 << 2, ///< this field includes an argument, under the form 'property.argument'.
EPF_TABLE_ONLY = 1 << 3, ///< this field is designed to be used in a table and won't appear in the field listing.
EPF_INFO = 1 << 4, ///< this field contains summary information about the event.
EPF_CONVERSATION = 1 << 5, ///< this field can be used to identify conversations.
}filtercheck_field_flags;
/*!
@ -59,6 +61,7 @@ typedef struct filtercheck_field_info
filtercheck_field_flags m_flags; ///< Field flags.
ppm_print_format m_print_format; ///< If this is a numeric field, this flag specifies if it should be rendered as octal, decimal or hex.
char m_name[64]; ///< Field name.
char m_display[64]; ///< Field display name (short description). May be empty.
char m_description[1024]; ///< Field description.
}filtercheck_field_info;
@ -532,7 +535,6 @@ VISIBILITY_PRIVATE
friend class sinsp_analyzer;
friend class sinsp_filter_check_event;
friend class sinsp_filter_check_thread;
friend class sinsp_evttype_filter;
friend class sinsp_dumper;
friend class sinsp_analyzer_fd_listener;
friend class sinsp_analyzer_parsers;

View File

@ -218,6 +218,8 @@ std::string get_event_type(uint16_t type)
case PPME_SYSCALL_CLONE_16_X:
case PPME_SYSCALL_CLONE_17_X:
case PPME_SYSCALL_CLONE_20_X: return "clone";
case PPME_SYSCALL_CLONE3_E:
case PPME_SYSCALL_CLONE3_X: return "clone3";
case PPME_SYSCALL_EXECVE_8_E:
case PPME_SYSCALL_EXECVE_13_E:
case PPME_SYSCALL_EXECVE_14_E:

View File

@ -2029,298 +2029,6 @@ sinsp_filter* sinsp_filter_compiler::compile_()
return m_filter;
}
sinsp_evttype_filter::sinsp_evttype_filter()
{
}
sinsp_evttype_filter::~sinsp_evttype_filter()
{
for(const auto &val : m_filters)
{
delete val.second->filter;
delete val.second;
}
for(auto &ruleset : m_rulesets)
{
delete ruleset;
}
m_filters.clear();
}
sinsp_evttype_filter::ruleset_filters::ruleset_filters()
{
memset(m_filter_by_evttype, 0, PPM_EVENT_MAX * sizeof(list<filter_wrapper *> *));
memset(m_filter_by_syscall, 0, PPM_SC_MAX * sizeof(list<filter_wrapper *> *));
}
sinsp_evttype_filter::ruleset_filters::~ruleset_filters()
{
for(int i = 0; i < PPM_EVENT_MAX; i++)
{
if(m_filter_by_evttype[i])
{
delete m_filter_by_evttype[i];
m_filter_by_evttype[i] = NULL;
}
}
for(int i = 0; i < PPM_SC_MAX; i++)
{
if(m_filter_by_syscall[i])
{
delete m_filter_by_syscall[i];
m_filter_by_syscall[i] = NULL;
}
}
}
void sinsp_evttype_filter::ruleset_filters::add_filter(filter_wrapper *wrap)
{
for(uint32_t etype = 0; etype < PPM_EVENT_MAX; etype++)
{
if(wrap->evttypes[etype])
{
if(!m_filter_by_evttype[etype])
{
m_filter_by_evttype[etype] = new std::list<filter_wrapper *>();
}
m_filter_by_evttype[etype]->push_back(wrap);
}
}
for(uint32_t syscall = 0; syscall < PPM_SC_MAX; syscall++)
{
if(wrap->syscalls[syscall])
{
if(!m_filter_by_syscall[syscall])
{
m_filter_by_syscall[syscall] = new std::list<filter_wrapper *>();
}
m_filter_by_syscall[syscall]->push_back(wrap);
}
}
}
void sinsp_evttype_filter::ruleset_filters::remove_filter(filter_wrapper *wrap)
{
for(uint32_t etype = 0; etype < PPM_EVENT_MAX; etype++)
{
if(wrap->evttypes[etype])
{
if(m_filter_by_evttype[etype])
{
m_filter_by_evttype[etype]->erase(std::remove(m_filter_by_evttype[etype]->begin(),
m_filter_by_evttype[etype]->end(),
wrap),
m_filter_by_evttype[etype]->end());
if(m_filter_by_evttype[etype]->size() == 0)
{
delete m_filter_by_evttype[etype];
m_filter_by_evttype[etype] = NULL;
}
}
}
}
for(uint32_t syscall = 0; syscall < PPM_SC_MAX; syscall++)
{
if(wrap->syscalls[syscall])
{
if(m_filter_by_syscall[syscall])
{
m_filter_by_syscall[syscall]->erase(std::remove(m_filter_by_syscall[syscall]->begin(),
m_filter_by_syscall[syscall]->end(),
wrap),
m_filter_by_syscall[syscall]->end());
if(m_filter_by_syscall[syscall]->size() == 0)
{
delete m_filter_by_syscall[syscall];
m_filter_by_syscall[syscall] = NULL;
}
}
}
}
}
bool sinsp_evttype_filter::ruleset_filters::run(sinsp_evt *evt)
{
list<filter_wrapper *> *filters;
uint16_t etype = evt->m_pevt->type;
if(etype == PPME_GENERIC_E || etype == PPME_GENERIC_X)
{
sinsp_evt_param *parinfo = evt->get_param(0);
ASSERT(parinfo->m_len == sizeof(uint16_t));
uint16_t evid = *(uint16_t *)parinfo->m_val;
filters = m_filter_by_syscall[evid];
}
else
{
filters = m_filter_by_evttype[etype];
}
if (!filters) {
return false;
}
for (auto &wrap : *filters)
{
if(wrap->filter->run(evt))
{
return true;
}
}
return false;
}
void sinsp_evttype_filter::ruleset_filters::evttypes_for_ruleset(std::vector<bool> &evttypes)
{
evttypes.assign(PPM_EVENT_MAX+1, false);
for(uint32_t etype = 0; etype < PPM_EVENT_MAX; etype++)
{
list<filter_wrapper *> *filters = m_filter_by_evttype[etype];
if(filters)
{
evttypes[etype] = true;
}
}
}
void sinsp_evttype_filter::ruleset_filters::syscalls_for_ruleset(std::vector<bool> &syscalls)
{
syscalls.assign(PPM_SC_MAX+1, false);
for(uint32_t evid = 0; evid < PPM_SC_MAX; evid++)
{
list<filter_wrapper *> *filters = m_filter_by_syscall[evid];
if(filters)
{
syscalls[evid] = true;
}
}
}
void sinsp_evttype_filter::add(string &name,
set<uint32_t> &evttypes,
set<uint32_t> &syscalls,
set<string> &tags,
sinsp_filter *filter)
{
filter_wrapper *wrap = new filter_wrapper();
wrap->filter = filter;
// If no evttypes or syscalls are specified, the filter is
// enabled for all evttypes/syscalls.
bool def = ((evttypes.size() == 0 && syscalls.size() == 0) ? true : false);
wrap->evttypes.assign(PPM_EVENT_MAX+1, def);
for(auto &evttype : evttypes)
{
wrap->evttypes[evttype] = true;
}
wrap->syscalls.assign(PPM_SC_MAX+1, def);
for(auto &syscall : syscalls)
{
wrap->syscalls[syscall] = true;
}
m_filters.insert(pair<string,filter_wrapper *>(name, wrap));
for(const auto &tag: tags)
{
auto it = m_filter_by_tag.lower_bound(tag);
if(it == m_filter_by_tag.end() ||
it->first != tag)
{
it = m_filter_by_tag.emplace_hint(it,
std::make_pair(tag, std::list<filter_wrapper*>()));
}
it->second.push_back(wrap);
}
}
void sinsp_evttype_filter::enable(const string &pattern, bool enabled, uint16_t ruleset)
{
regex re(pattern);
while (m_rulesets.size() < (size_t) ruleset + 1)
{
m_rulesets.push_back(new ruleset_filters());
}
for(const auto &val : m_filters)
{
if (regex_match(val.first, re))
{
if(enabled)
{
m_rulesets[ruleset]->add_filter(val.second);
}
else
{
m_rulesets[ruleset]->remove_filter(val.second);
}
}
}
}
void sinsp_evttype_filter::enable_tags(const set<string> &tags, bool enabled, uint16_t ruleset)
{
while (m_rulesets.size() < (size_t) ruleset + 1)
{
m_rulesets.push_back(new ruleset_filters());
}
for(const auto &tag : tags)
{
for(const auto &wrap : m_filter_by_tag[tag])
{
if(enabled)
{
m_rulesets[ruleset]->add_filter(wrap);
}
else
{
m_rulesets[ruleset]->remove_filter(wrap);
}
}
}
}
bool sinsp_evttype_filter::run(sinsp_evt *evt, uint16_t ruleset)
{
if(m_rulesets.size() < (size_t) ruleset + 1)
{
return false;
}
return m_rulesets[ruleset]->run(evt);
}
void sinsp_evttype_filter::evttypes_for_ruleset(std::vector<bool> &evttypes, uint16_t ruleset)
{
return m_rulesets[ruleset]->evttypes_for_ruleset(evttypes);
}
void sinsp_evttype_filter::syscalls_for_ruleset(std::vector<bool> &syscalls, uint16_t ruleset)
{
return m_rulesets[ruleset]->syscalls_for_ruleset(syscalls);
}
sinsp_filter_factory::sinsp_filter_factory(sinsp *inspector,
filter_check_list &available_checks)
: m_inspector(inspector), m_available_checks(available_checks)

View File

@ -103,105 +103,6 @@ private:
friend class sinsp_evt_formatter;
};
/*!
\brief This class represents a filter optimized using event
types. It actually consists of collections of sinsp_filter objects
grouped by event type.
*/
class SINSP_PUBLIC sinsp_evttype_filter
{
public:
sinsp_evttype_filter();
virtual ~sinsp_evttype_filter();
void add(std::string &name,
std::set<uint32_t> &evttypes,
std::set<uint32_t> &syscalls,
std::set<string> &tags,
sinsp_filter* filter);
// rulesets are arbitrary numbers and should be managed by the caller.
// Note that rulesets are used to index into a std::vector so
// specifying unnecessarily large rulesets will result in
// unnecessarily large vectors.
// Find those rules matching the provided pattern and set
// their enabled status to enabled.
void enable(const std::string &pattern, bool enabled, uint16_t ruleset = 0);
// Find those rules that have a tag in the set of tags and set
// their enabled status to enabled. Note that the enabled
// status is on the rules, and not the tags--if a rule R has
// tags (a, b), and you call enable_tags([a], true) and then
// enable_tags([b], false), R will be disabled despite the
// fact it has tag a and was enabled by the first call to
// enable_tags.
void enable_tags(const std::set<string> &tags, bool enabled, uint16_t ruleset = 0);
// Match all filters against the provided event.
bool run(sinsp_evt *evt, uint16_t ruleset = 0);
// Populate the provided vector, indexed by event type, of the
// event types associated with the given ruleset id. For
// example, evttypes[10] = true would mean that this ruleset
// relates to event type 10.
void evttypes_for_ruleset(std::vector<bool> &evttypes, uint16_t ruleset);
// Populate the provided vector, indexed by syscall code, of the
// syscall codes associated with the given ruleset id. For
// example, syscalls[10] = true would mean that this ruleset
// relates to syscall code 10.
void syscalls_for_ruleset(std::vector<bool> &syscalls, uint16_t ruleset);
private:
struct filter_wrapper {
sinsp_filter *filter;
// Indexes from event type to enabled/disabled.
std::vector<bool> evttypes;
// Indexes from syscall code to enabled/disabled.
std::vector<bool> syscalls;
};
// A group of filters all having the same ruleset
class ruleset_filters {
public:
ruleset_filters();
virtual ~ruleset_filters();
void add_filter(filter_wrapper *wrap);
void remove_filter(filter_wrapper *wrap);
bool run(sinsp_evt *evt);
void evttypes_for_ruleset(std::vector<bool> &evttypes);
void syscalls_for_ruleset(std::vector<bool> &syscalls);
private:
// Maps from event type to filter. There can be multiple
// filters per event type.
std::list<filter_wrapper *> *m_filter_by_evttype[PPM_EVENT_MAX];
// Maps from syscall number to filter. There can be multiple
// filters per syscall number
std::list<filter_wrapper *> *m_filter_by_syscall[PPM_SC_MAX];
};
std::vector<ruleset_filters *> m_rulesets;
// Maps from tag to list of filters having that tag.
std::map<std::string, std::list<filter_wrapper *>> m_filter_by_tag;
// This holds all the filters passed to add(), so they can
// be cleaned up.
map<std::string,filter_wrapper *> m_filters;
};
/*@}*/
class sinsp_filter_factory : public gen_event_filter_factory

View File

@ -95,47 +95,47 @@ int32_t gmt2local(time_t t)
///////////////////////////////////////////////////////////////////////////////
const filtercheck_field_info sinsp_filter_check_fd_fields[] =
{
{PT_INT64, EPF_NONE, PF_ID, "fd.num", "the unique number identifying the file descriptor."},
{PT_CHARBUF, EPF_NONE, PF_DEC, "fd.type", "type of FD. Can be 'file', 'directory', 'ipv4', 'ipv6', 'unix', 'pipe', 'event', 'signalfd', 'eventpoll', 'inotify' or 'signalfd'."},
{PT_CHARBUF, EPF_NONE, PF_DEC, "fd.typechar", "type of FD as a single character. Can be 'f' for file, 4 for IPv4 socket, 6 for IPv6 socket, 'u' for unix socket, p for pipe, 'e' for eventfd, 's' for signalfd, 'l' for eventpoll, 'i' for inotify, 'o' for unknown."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.name", "FD full name. If the fd is a file, this field contains the full path. If the FD is a socket, this field contain the connection tuple."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.directory", "If the fd is a file, the directory that contains it."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.filename", "If the fd is a file, the filename without the path."},
{PT_IPADDR, EPF_FILTER_ONLY, PF_NA, "fd.ip", "matches the ip address (client or server) of the fd."},
{PT_IPADDR, EPF_NONE, PF_NA, "fd.cip", "client IP address."},
{PT_IPADDR, EPF_NONE, PF_NA, "fd.sip", "server IP address."},
{PT_IPADDR, EPF_NONE, PF_NA, "fd.lip", "local IP address."},
{PT_IPADDR, EPF_NONE, PF_NA, "fd.rip", "remote IP address."},
{PT_PORT, EPF_FILTER_ONLY, PF_DEC, "fd.port", "matches the port (either client or server) of the fd."},
{PT_PORT, EPF_NONE, PF_DEC, "fd.cport", "for TCP/UDP FDs, the client port."},
{PT_PORT, EPF_NONE, PF_DEC, "fd.sport", "for TCP/UDP FDs, server port."},
{PT_PORT, EPF_NONE, PF_DEC, "fd.lport", "for TCP/UDP FDs, the local port."},
{PT_PORT, EPF_NONE, PF_DEC, "fd.rport", "for TCP/UDP FDs, the remote port."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.l4proto", "the IP protocol of a socket. Can be 'tcp', 'udp', 'icmp' or 'raw'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.sockfamily", "the socket family for socket events. Can be 'ip' or 'unix'."},
{PT_BOOL, EPF_NONE, PF_NA, "fd.is_server", "'true' if the process owning this FD is the server endpoint in the connection."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.uid", "a unique identifier for the FD, created by chaining the FD number and the thread ID."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.containername", "chaining of the container ID and the FD name. Useful when trying to identify which container an FD belongs to."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.containerdirectory", "chaining of the container ID and the directory name. Useful when trying to identify which container a directory belongs to."},
{PT_PORT, EPF_FILTER_ONLY, PF_NA, "fd.proto", "matches the protocol (either client or server) of the fd."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.cproto", "for TCP/UDP FDs, the client protocol."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.sproto", "for TCP/UDP FDs, server protocol."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.lproto", "for TCP/UDP FDs, the local protocol."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.rproto", "for TCP/UDP FDs, the remote protocol."},
{PT_IPNET, EPF_FILTER_ONLY, PF_NA, "fd.net", "matches the IP network (client or server) of the fd."},
{PT_IPNET, EPF_FILTER_ONLY, PF_NA, "fd.cnet", "matches the client IP network of the fd."},
{PT_IPNET, EPF_FILTER_ONLY, PF_NA, "fd.snet", "matches the server IP network of the fd."},
{PT_IPNET, EPF_FILTER_ONLY, PF_NA, "fd.lnet", "matches the local IP network of the fd."},
{PT_IPNET, EPF_FILTER_ONLY, PF_NA, "fd.rnet", "matches the remote IP network of the fd."},
{PT_BOOL, EPF_NONE, PF_NA, "fd.connected", "for TCP/UDP FDs, 'true' if the socket is connected."},
{PT_BOOL, EPF_NONE, PF_NA, "fd.name_changed", "True when an event changes the name of an fd used by this event. This can occur in some cases such as udp connections where the connection tuple changes."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.cip.name", "Domain name associated with the client IP address."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.sip.name", "Domain name associated with the server IP address."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.lip.name", "Domain name associated with the local IP address."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.rip.name", "Domain name associated with the remote IP address."},
{PT_INT32, EPF_NONE, PF_HEX, "fd.dev", "device number (major/minor) containing the referenced file"},
{PT_INT32, EPF_NONE, PF_DEC, "fd.dev.major", "major device number containing the referenced file"},
{PT_INT32, EPF_NONE, PF_DEC, "fd.dev.minor", "minor device number containing the referenced file"},
{PT_INT64, EPF_NONE, PF_ID, "fd.num", "FD Number", "the unique number identifying the file descriptor."},
{PT_CHARBUF, EPF_NONE, PF_DEC, "fd.type", "FD Type", "type of FD. Can be 'file', 'directory', 'ipv4', 'ipv6', 'unix', 'pipe', 'event', 'signalfd', 'eventpoll', 'inotify' or 'signalfd'."},
{PT_CHARBUF, EPF_NONE, PF_DEC, "fd.typechar", "FD Type Char", "type of FD as a single character. Can be 'f' for file, 4 for IPv4 socket, 6 for IPv6 socket, 'u' for unix socket, p for pipe, 'e' for eventfd, 's' for signalfd, 'l' for eventpoll, 'i' for inotify, 'o' for unknown."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.name", "FD Name", "FD full name. If the fd is a file, this field contains the full path. If the FD is a socket, this field contain the connection tuple."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.directory", "FD Directory", "If the fd is a file, the directory that contains it."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.filename", "FD Filename", "If the fd is a file, the filename without the path."},
{PT_IPADDR, EPF_FILTER_ONLY, PF_NA, "fd.ip", "FD IP Address", "matches the ip address (client or server) of the fd."},
{PT_IPADDR, EPF_NONE, PF_NA, "fd.cip", "FD Client Address", "client IP address."},
{PT_IPADDR, EPF_NONE, PF_NA, "fd.sip", "FD Server Address", "server IP address."},
{PT_IPADDR, EPF_NONE, PF_NA, "fd.lip", "FD Local Address", "local IP address."},
{PT_IPADDR, EPF_NONE, PF_NA, "fd.rip", "FD Remote Address", "remote IP address."},
{PT_PORT, EPF_FILTER_ONLY, PF_DEC, "fd.port", "FD Port", "matches the port (either client or server) of the fd."},
{PT_PORT, EPF_NONE, PF_DEC, "fd.cport", "FD Client Port", "for TCP/UDP FDs, the client port."},
{PT_PORT, EPF_NONE, PF_DEC, "fd.sport", "FD Server Port", "for TCP/UDP FDs, server port."},
{PT_PORT, EPF_NONE, PF_DEC, "fd.lport", "FD Local Port", "for TCP/UDP FDs, the local port."},
{PT_PORT, EPF_NONE, PF_DEC, "fd.rport", "FD Remote Port", "for TCP/UDP FDs, the remote port."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.l4proto", "FD IP Protocol", "the IP protocol of a socket. Can be 'tcp', 'udp', 'icmp' or 'raw'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.sockfamily", "FD Socket Family", "the socket family for socket events. Can be 'ip' or 'unix'."},
{PT_BOOL, EPF_NONE, PF_NA, "fd.is_server", "FD Server", "'true' if the process owning this FD is the server endpoint in the connection."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.uid", "FD ID", "a unique identifier for the FD, created by chaining the FD number and the thread ID."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.containername", "FD Container Name", "chaining of the container ID and the FD name. Useful when trying to identify which container an FD belongs to."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.containerdirectory", "FD Container Directory", "chaining of the container ID and the directory name. Useful when trying to identify which container a directory belongs to."},
{PT_PORT, EPF_FILTER_ONLY, PF_NA, "fd.proto", "FD Protocol", "matches the protocol (either client or server) of the fd."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.cproto", "FD Client Protocol", "for TCP/UDP FDs, the client protocol."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.sproto", "FD Server Protocol", "for TCP/UDP FDs, server protocol."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.lproto", "FD Local Protocol", "for TCP/UDP FDs, the local protocol."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.rproto", "FD Remote Protocol", "for TCP/UDP FDs, the remote protocol."},
{PT_IPNET, EPF_FILTER_ONLY, PF_NA, "fd.net", "FD IP Network", "matches the IP network (client or server) of the fd."},
{PT_IPNET, EPF_FILTER_ONLY, PF_NA, "fd.cnet", "FD Client Network", "matches the client IP network of the fd."},
{PT_IPNET, EPF_FILTER_ONLY, PF_NA, "fd.snet", "FD Server Network", "matches the server IP network of the fd."},
{PT_IPNET, EPF_FILTER_ONLY, PF_NA, "fd.lnet", "FD Local Network", "matches the local IP network of the fd."},
{PT_IPNET, EPF_FILTER_ONLY, PF_NA, "fd.rnet", "FD Remote Network", "matches the remote IP network of the fd."},
{PT_BOOL, EPF_NONE, PF_NA, "fd.connected", "FD Connected", "for TCP/UDP FDs, 'true' if the socket is connected."},
{PT_BOOL, EPF_NONE, PF_NA, "fd.name_changed", "FD Name Changed", "True when an event changes the name of an fd used by this event. This can occur in some cases such as udp connections where the connection tuple changes."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.cip.name", "FD Client Domain Name", "Domain name associated with the client IP address."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.sip.name", "FD Server Domain Name", "Domain name associated with the server IP address."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.lip.name", "FD Local Domain Name", "Domain name associated with the local IP address."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fd.rip.name", "FD Remote Domain Name", "Domain name associated with the remote IP address."},
{PT_INT32, EPF_NONE, PF_HEX, "fd.dev", "FD Device", "device number (major/minor) containing the referenced file"},
{PT_INT32, EPF_NONE, PF_DEC, "fd.dev.major", "FD Major Device", "major device number containing the referenced file"},
{PT_INT32, EPF_NONE, PF_DEC, "fd.dev.minor", "FD Minor Device", "minor device number containing the referenced file"},
};
sinsp_filter_check_fd::sinsp_filter_check_fd()
@ -1810,56 +1810,56 @@ bool sinsp_filter_check_fd::compare(sinsp_evt *evt)
///////////////////////////////////////////////////////////////////////////////
const filtercheck_field_info sinsp_filter_check_thread_fields[] =
{
{PT_INT64, EPF_NONE, PF_ID, "proc.pid", "the id of the process generating the event."},
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.exe", "the first command line argument (usually the executable name or a custom one)."},
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.name", "the name (excluding the path) of the executable generating the event."},
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.args", "the arguments passed on the command line when starting the process generating the event."},
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.env", "the environment variables of the process generating the event."},
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.cmdline", "full process command line, i.e. proc.name + proc.args."},
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.exeline", "full process command line, with exe as first argument, i.e. proc.exe + proc.args."},
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.cwd", "the current working directory of the event."},
{PT_UINT32, EPF_NONE, PF_DEC, "proc.nthreads", "the number of threads that the process generating the event currently has, including the main process thread."},
{PT_UINT32, EPF_NONE, PF_DEC, "proc.nchilds", "the number of child threads that the process generating the event currently has. This excludes the main process thread."},
{PT_INT64, EPF_NONE, PF_ID, "proc.ppid", "the pid of the parent of the process generating the event."},
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.pname", "the name (excluding the path) of the parent of the process generating the event."},
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.pcmdline", "the full command line (proc.name + proc.args) of the parent of the process generating the event."},
{PT_INT64, EPF_NONE, PF_ID, "proc.apid", "the pid of one of the process ancestors. E.g. proc.apid[1] returns the parent pid, proc.apid[2] returns the grandparent pid, and so on. proc.apid[0] is the pid of the current process. proc.apid without arguments can be used in filters only and matches any of the process ancestors, e.g. proc.apid=1234."},
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.aname", "the name (excluding the path) of one of the process ancestors. E.g. proc.aname[1] returns the parent name, proc.aname[2] returns the grandparent name, and so on. proc.aname[0] is the name of the current process. proc.aname without arguments can be used in filters only and matches any of the process ancestors, e.g. proc.aname=bash."},
{PT_INT64, EPF_NONE, PF_ID, "proc.loginshellid", "the pid of the oldest shell among the ancestors of the current process, if there is one. This field can be used to separate different user sessions, and is useful in conjunction with chisels like spy_user."},
{PT_RELTIME, EPF_NONE, PF_DEC, "proc.duration", "number of nanoseconds since the process started."},
{PT_UINT64, EPF_NONE, PF_DEC, "proc.fdopencount", "number of open FDs for the process"},
{PT_INT64, EPF_NONE, PF_DEC, "proc.fdlimit", "maximum number of FDs the process can open."},
{PT_DOUBLE, EPF_NONE, PF_DEC, "proc.fdusage", "the ratio between open FDs and maximum available FDs for the process."},
{PT_UINT64, EPF_NONE, PF_DEC, "proc.vmsize", "total virtual memory for the process (as kb)."},
{PT_UINT64, EPF_NONE, PF_DEC, "proc.vmrss", "resident non-swapped memory for the process (as kb)."},
{PT_UINT64, EPF_NONE, PF_DEC, "proc.vmswap", "swapped memory for the process (as kb)."},
{PT_UINT64, EPF_NONE, PF_DEC, "thread.pfmajor", "number of major page faults since thread start."},
{PT_UINT64, EPF_NONE, PF_DEC, "thread.pfminor", "number of minor page faults since thread start."},
{PT_INT64, EPF_NONE, PF_ID, "thread.tid", "the id of the thread generating the event."},
{PT_BOOL, EPF_NONE, PF_NA, "thread.ismain", "'true' if the thread generating the event is the main one in the process."},
{PT_RELTIME, EPF_NONE, PF_DEC, "thread.exectime", "CPU time spent by the last scheduled thread, in nanoseconds. Exported by switch events only."},
{PT_RELTIME, EPF_NONE, PF_DEC, "thread.totexectime", "Total CPU time, in nanoseconds since the beginning of the capture, for the current thread. Exported by switch events only."},
{PT_CHARBUF, EPF_NONE, PF_NA, "thread.cgroups", "all the cgroups the thread belongs to, aggregated into a single string."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "thread.cgroup", "the cgroup the thread belongs to, for a specific subsystem. E.g. thread.cgroup.cpuacct."},
{PT_INT64, EPF_NONE, PF_ID, "thread.vtid", "the id of the thread generating the event as seen from its current PID namespace."},
{PT_INT64, EPF_NONE, PF_ID, "proc.vpid", "the id of the process generating the event as seen from its current PID namespace."},
{PT_DOUBLE, EPF_NONE, PF_NA, "thread.cpu", "the CPU consumed by the thread in the last second."},
{PT_DOUBLE, EPF_NONE, PF_NA, "thread.cpu.user", "the user CPU consumed by the thread in the last second."},
{PT_DOUBLE, EPF_NONE, PF_NA, "thread.cpu.system", "the system CPU consumed by the thread in the last second."},
{PT_UINT64, EPF_NONE, PF_DEC, "thread.vmsize", "For the process main thread, this is the total virtual memory for the process (as kb). For the other threads, this field is zero."},
{PT_UINT64, EPF_NONE, PF_DEC, "thread.vmrss", "For the process main thread, this is the resident non-swapped memory for the process (as kb). For the other threads, this field is zero."},
{PT_UINT64, EPF_TABLE_ONLY, PF_DEC, "thread.vmsize.b", "For the process main thread, this is the total virtual memory for the process (in bytes). For the other threads, this field is zero."},
{PT_UINT64, EPF_TABLE_ONLY, PF_DEC, "thread.vmrss.b", "For the process main thread, this is the resident non-swapped memory for the process (in bytes). For the other threads, this field is zero."},
{PT_INT64, EPF_NONE, PF_ID, "proc.sid", "the session id of the process generating the event."},
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.sname", "the name of the current process's session leader. This is either the process with pid=proc.sid or the eldest ancestor that has the same sid as the current process."},
{PT_INT32, EPF_NONE, PF_ID, "proc.tty", "The controlling terminal of the process. 0 for processes without a terminal."},
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.exepath", "The full executable path of the process."},
{PT_CHARBUF, EPF_TABLE_ONLY, PF_NA, "thread.nametid", "this field chains the process name and tid of a thread and can be used as a specific identifier of a thread for a specific execve."},
{PT_INT64, EPF_NONE, PF_ID, "proc.vpgid", "the process group id of the process generating the event, as seen from its current PID namespace."},
{PT_BOOL, EPF_NONE, PF_NA, "proc.is_container_healthcheck", "true if this process is running as a part of the container's health check."},
{PT_BOOL, EPF_NONE, PF_NA, "proc.is_container_liveness_probe", "true if this process is running as a part of the container's liveness probe."},
{PT_BOOL, EPF_NONE, PF_NA, "proc.is_container_readiness_probe", "true if this process is running as a part of the container's readiness probe."},
{PT_BOOL, EPF_NONE, PF_NA, "proc.is_exe_writable", "true if this process' executable file is writable by the same user that spawned the process."},
{PT_INT64, EPF_NONE, PF_ID, "proc.pid", "Process ID", "the id of the process generating the event."},
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.exe", "First Argument", "the first command line argument (usually the executable name or a custom one)."},
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.name", "Name", "the name (excluding the path) of the executable generating the event."},
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.args", "Arguments", "the arguments passed on the command line when starting the process generating the event."},
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.env", "Environment", "the environment variables of the process generating the event."},
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.cmdline", "Command Line", "full process command line, i.e. proc.name + proc.args."},
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.exeline", "Executable Command Line", "full process command line, with exe as first argument, i.e. proc.exe + proc.args."},
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.cwd", "Current Working Directory", "the current working directory of the event."},
{PT_UINT32, EPF_NONE, PF_DEC, "proc.nthreads", "Threads", "the number of threads that the process generating the event currently has, including the main process thread."},
{PT_UINT32, EPF_NONE, PF_DEC, "proc.nchilds", "Children", "the number of child threads that the process generating the event currently has. This excludes the main process thread."},
{PT_INT64, EPF_NONE, PF_ID, "proc.ppid", "Parent Process ID", "the pid of the parent of the process generating the event."},
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.pname", "Parent Name", "the name (excluding the path) of the parent of the process generating the event."},
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.pcmdline", "Parent Command Line", "the full command line (proc.name + proc.args) of the parent of the process generating the event."},
{PT_INT64, EPF_NONE, PF_ID, "proc.apid", "Ancestor Process ID", "the pid of one of the process ancestors. E.g. proc.apid[1] returns the parent pid, proc.apid[2] returns the grandparent pid, and so on. proc.apid[0] is the pid of the current process. proc.apid without arguments can be used in filters only and matches any of the process ancestors, e.g. proc.apid=1234."},
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.aname", "Ancestor Name", "the name (excluding the path) of one of the process ancestors. E.g. proc.aname[1] returns the parent name, proc.aname[2] returns the grandparent name, and so on. proc.aname[0] is the name of the current process. proc.aname without arguments can be used in filters only and matches any of the process ancestors, e.g. proc.aname=bash."},
{PT_INT64, EPF_NONE, PF_ID, "proc.loginshellid", "Login Shell ID", "the pid of the oldest shell among the ancestors of the current process, if there is one. This field can be used to separate different user sessions, and is useful in conjunction with chisels like spy_user."},
{PT_RELTIME, EPF_NONE, PF_DEC, "proc.duration", "Duration", "number of nanoseconds since the process started."},
{PT_UINT64, EPF_NONE, PF_DEC, "proc.fdopencount", "FD Count", "number of open FDs for the process"},
{PT_INT64, EPF_NONE, PF_DEC, "proc.fdlimit", "FD Limit", "maximum number of FDs the process can open."},
{PT_DOUBLE, EPF_NONE, PF_DEC, "proc.fdusage", "FD Usage", "the ratio between open FDs and maximum available FDs for the process."},
{PT_UINT64, EPF_NONE, PF_DEC, "proc.vmsize", "VM Size", "total virtual memory for the process (as kb)."},
{PT_UINT64, EPF_NONE, PF_DEC, "proc.vmrss", "VM RSS", "resident non-swapped memory for the process (as kb)."},
{PT_UINT64, EPF_NONE, PF_DEC, "proc.vmswap", "VM Swap", "swapped memory for the process (as kb)."},
{PT_UINT64, EPF_NONE, PF_DEC, "thread.pfmajor", "Major Page Faults", "number of major page faults since thread start."},
{PT_UINT64, EPF_NONE, PF_DEC, "thread.pfminor", "Minor Page Faults", "number of minor page faults since thread start."},
{PT_INT64, EPF_NONE, PF_ID, "thread.tid", "Thread ID", "the id of the thread generating the event."},
{PT_BOOL, EPF_NONE, PF_NA, "thread.ismain", "Main Thread", "'true' if the thread generating the event is the main one in the process."},
{PT_RELTIME, EPF_NONE, PF_DEC, "thread.exectime", "Scheduled Thread CPU Time", "CPU time spent by the last scheduled thread, in nanoseconds. Exported by switch events only."},
{PT_RELTIME, EPF_NONE, PF_DEC, "thread.totexectime", "Current Thread CPU Time", "Total CPU time, in nanoseconds since the beginning of the capture, for the current thread. Exported by switch events only."},
{PT_CHARBUF, EPF_NONE, PF_NA, "thread.cgroups", "Thread Cgroups", "all the cgroups the thread belongs to, aggregated into a single string."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "thread.cgroup", "Thread Cgroup", "the cgroup the thread belongs to, for a specific subsystem. E.g. thread.cgroup.cpuacct."},
{PT_INT64, EPF_NONE, PF_ID, "thread.vtid", "Virtual Thread ID", "the id of the thread generating the event as seen from its current PID namespace."},
{PT_INT64, EPF_NONE, PF_ID, "proc.vpid", "Virtual Process ID", "the id of the process generating the event as seen from its current PID namespace."},
{PT_DOUBLE, EPF_NONE, PF_NA, "thread.cpu", "Thread CPU", "the CPU consumed by the thread in the last second."},
{PT_DOUBLE, EPF_NONE, PF_NA, "thread.cpu.user", "Thread User CPU", "the user CPU consumed by the thread in the last second."},
{PT_DOUBLE, EPF_NONE, PF_NA, "thread.cpu.system", "Thread System CPU", "the system CPU consumed by the thread in the last second."},
{PT_UINT64, EPF_NONE, PF_DEC, "thread.vmsize", "Thread VM Size (kb)", "For the process main thread, this is the total virtual memory for the process (as kb). For the other threads, this field is zero."},
{PT_UINT64, EPF_NONE, PF_DEC, "thread.vmrss", "Thread VM RSS (kb)", "For the process main thread, this is the resident non-swapped memory for the process (as kb). For the other threads, this field is zero."},
{PT_UINT64, EPF_TABLE_ONLY, PF_DEC, "thread.vmsize.b", "Thread VM Size (b)", "For the process main thread, this is the total virtual memory for the process (in bytes). For the other threads, this field is zero."},
{PT_UINT64, EPF_TABLE_ONLY, PF_DEC, "thread.vmrss.b", "Thread VM RSS (b)", "For the process main thread, this is the resident non-swapped memory for the process (in bytes). For the other threads, this field is zero."},
{PT_INT64, EPF_NONE, PF_ID, "proc.sid", "Process Session ID", "the session id of the process generating the event."},
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.sname", "Process Session Name", "the name of the current process's session leader. This is either the process with pid=proc.sid or the eldest ancestor that has the same sid as the current process."},
{PT_INT32, EPF_NONE, PF_ID, "proc.tty", "Process TTY", "The controlling terminal of the process. 0 for processes without a terminal."},
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.exepath", "Process Executable Path", "The full executable path of the process."},
{PT_CHARBUF, EPF_TABLE_ONLY, PF_NA, "thread.nametid", "Thread Name + ID", "this field chains the process name and tid of a thread and can be used as a specific identifier of a thread for a specific execve."},
{PT_INT64, EPF_NONE, PF_ID, "proc.vpgid", "Process Virtual Group ID", "the process group id of the process generating the event, as seen from its current PID namespace."},
{PT_BOOL, EPF_NONE, PF_NA, "proc.is_container_healthcheck", "Process Is Container Healthcheck", "true if this process is running as a part of the container's health check."},
{PT_BOOL, EPF_NONE, PF_NA, "proc.is_container_liveness_probe", "Process Is Container Liveness", "true if this process is running as a part of the container's liveness probe."},
{PT_BOOL, EPF_NONE, PF_NA, "proc.is_container_readiness_probe", "Process Is Container Readiness", "true if this process is running as a part of the container's readiness probe."},
{PT_BOOL, EPF_NONE, PF_NA, "proc.is_exe_writable", "Process Executable Is Writable", "true if this process' executable file is writable by the same user that spawned the process."},
};
sinsp_filter_check_thread::sinsp_filter_check_thread()
@ -2798,20 +2798,20 @@ bool sinsp_filter_check_thread::compare(sinsp_evt *evt)
///////////////////////////////////////////////////////////////////////////////
const filtercheck_field_info sinsp_filter_check_gen_event_fields[] =
{
{PT_UINT64, EPF_NONE, PF_ID, "evt.num", "event number."},
{PT_CHARBUF, EPF_NONE, PF_NA, "evt.time", "event timestamp as a time string that includes the nanosecond part."},
{PT_CHARBUF, EPF_NONE, PF_NA, "evt.time.s", "event timestamp as a time string with no nanoseconds."},
{PT_CHARBUF, EPF_NONE, PF_NA, "evt.time.iso8601", "event timestamp in ISO 8601 format, including nanoseconds and time zone offset (in UTC)."},
{PT_CHARBUF, EPF_NONE, PF_NA, "evt.datetime", "event timestamp as a time string that includes the date."},
{PT_CHARBUF, EPF_NONE, PF_NA, "evt.datetime.s", "event timestamp as a datetime string with no nanoseconds."},
{PT_ABSTIME, EPF_NONE, PF_DEC, "evt.rawtime", "absolute event timestamp, i.e. nanoseconds from epoch."},
{PT_ABSTIME, EPF_NONE, PF_DEC, "evt.rawtime.s", "integer part of the event timestamp (e.g. seconds since epoch)."},
{PT_ABSTIME, EPF_NONE, PF_10_PADDED_DEC, "evt.rawtime.ns", "fractional part of the absolute event timestamp."},
{PT_RELTIME, EPF_NONE, PF_10_PADDED_DEC, "evt.reltime", "number of nanoseconds from the beginning of the capture."},
{PT_RELTIME, EPF_NONE, PF_DEC, "evt.reltime.s", "number of seconds from the beginning of the capture."},
{PT_RELTIME, EPF_NONE, PF_10_PADDED_DEC, "evt.reltime.ns", "fractional part (in ns) of the time from the beginning of the capture."},
{PT_CHARBUF, EPF_NONE, PF_NA, "evt.pluginname", "if the event comes from a plugin, the name of the plugin that generated it. The plugin must be currently loaded."},
{PT_CHARBUF, EPF_NONE, PF_NA, "evt.plugininfo", "if the event comes from a plugin, a summary of the event as formatted by the plugin. The plugin must be currently loaded."},
{PT_UINT64, EPF_NONE, PF_ID, "evt.num", "Event Number", "event number."},
{PT_CHARBUF, EPF_NONE, PF_NA, "evt.time", "Time", "event timestamp as a time string that includes the nanosecond part."},
{PT_CHARBUF, EPF_NONE, PF_NA, "evt.time.s", "Time (s)", "event timestamp as a time string with no nanoseconds."},
{PT_CHARBUF, EPF_NONE, PF_NA, "evt.time.iso8601", "ISO 8601 Time", "event timestamp in ISO 8601 format, including nanoseconds and time zone offset (in UTC)."},
{PT_CHARBUF, EPF_NONE, PF_NA, "evt.datetime", "Datetime", "event timestamp as a time string that includes the date."},
{PT_CHARBUF, EPF_NONE, PF_NA, "evt.datetime.s", "Datetime (s)", "event timestamp as a datetime string with no nanoseconds."},
{PT_ABSTIME, EPF_NONE, PF_DEC, "evt.rawtime", "Absolute Time", "absolute event timestamp, i.e. nanoseconds from epoch."},
{PT_ABSTIME, EPF_NONE, PF_DEC, "evt.rawtime.s", "Absolute Time (s)", "integer part of the event timestamp (e.g. seconds since epoch)."},
{PT_ABSTIME, EPF_NONE, PF_10_PADDED_DEC, "evt.rawtime.ns", "Absolute Time (ns)", "fractional part of the absolute event timestamp."},
{PT_RELTIME, EPF_NONE, PF_10_PADDED_DEC, "evt.reltime", "Relative Time", "number of nanoseconds from the beginning of the capture."},
{PT_RELTIME, EPF_NONE, PF_DEC, "evt.reltime.s", "Relative Time (s)", "number of seconds from the beginning of the capture."},
{PT_RELTIME, EPF_NONE, PF_10_PADDED_DEC, "evt.reltime.ns", "Relative Time (ns)", "fractional part (in ns) of the time from the beginning of the capture."},
{PT_CHARBUF, EPF_NONE, PF_NA, "evt.pluginname", "Plugin Name", "if the event comes from a plugin, the name of the plugin that generated it. The plugin must be currently loaded."},
{PT_CHARBUF, EPF_NONE, PF_NA, "evt.plugininfo", "Plugin Info", "if the event comes from a plugin, a summary of the event as formatted by the plugin. The plugin must be currently loaded."},
};
sinsp_filter_check_gen_event::sinsp_filter_check_gen_event()
@ -2941,63 +2941,63 @@ uint8_t* sinsp_filter_check_gen_event::extract(sinsp_evt *evt, OUT uint32_t* len
const filtercheck_field_info sinsp_filter_check_event_fields[] =
{
{PT_RELTIME, EPF_NONE, PF_DEC, "evt.latency", "delta between an exit event and the correspondent enter event, in nanoseconds."},
{PT_RELTIME, EPF_NONE, PF_DEC, "evt.latency.s", "integer part of the event latency delta."},
{PT_RELTIME, EPF_NONE, PF_10_PADDED_DEC, "evt.latency.ns", "fractional part of the event latency delta."},
{PT_UINT64, EPF_TABLE_ONLY, PF_DEC, "evt.latency.quantized", "10-base log of the delta between an exit event and the correspondent enter event."},
{PT_CHARBUF, EPF_NONE, PF_NA, "evt.latency.human", "delta between an exit event and the correspondent enter event, as a human readable string (e.g. 10.3ms)."},
{PT_RELTIME, EPF_NONE, PF_DEC, "evt.deltatime", "delta between this event and the previous event, in nanoseconds."},
{PT_RELTIME, EPF_NONE, PF_DEC, "evt.deltatime.s", "integer part of the delta between this event and the previous event."},
{PT_RELTIME, EPF_NONE, PF_10_PADDED_DEC, "evt.deltatime.ns", "fractional part of the delta between this event and the previous event."},
{PT_CHARBUF, EPF_PRINT_ONLY, PF_NA, "evt.outputtime", "this depends on -t param, default is %evt.time ('h')."},
{PT_CHARBUF, EPF_NONE, PF_DIR, "evt.dir", "event direction can be either '>' for enter events or '<' for exit events."},
{PT_CHARBUF, EPF_NONE, PF_NA, "evt.type", "The name of the event (e.g. 'open')."},
{PT_UINT32, EPF_REQUIRES_ARGUMENT, PF_NA, "evt.type.is", "allows one to specify an event type, and returns 1 for events that are of that type. For example, evt.type.is.open returns 1 for open events, 0 for any other event."},
{PT_CHARBUF, EPF_NONE, PF_NA, "syscall.type", "For system call events, the name of the system call (e.g. 'open'). Unset for other events (e.g. switch or internal events). Use this field instead of evt.type if you need to make sure that the filtered/printed value is actually a system call."},
{PT_CHARBUF, EPF_NONE, PF_NA, "evt.category", "The event category. Example values are 'file' (for file operations like open and close), 'net' (for network operations like socket and bind), memory (for things like brk or mmap), and so on."},
{PT_INT16, EPF_NONE, PF_ID, "evt.cpu", "number of the CPU where this event happened."},
{PT_CHARBUF, EPF_NONE, PF_NA, "evt.args", "all the event arguments, aggregated into a single string."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "evt.arg", "one of the event arguments specified by name or by number. Some events (e.g. return codes or FDs) will be converted into a text representation when possible. E.g. 'evt.arg.fd' or 'evt.arg[0]'."},
{PT_DYN, EPF_REQUIRES_ARGUMENT, PF_NA, "evt.rawarg", "one of the event arguments specified by name. E.g. 'evt.rawarg.fd'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "evt.info", "for most events, this field returns the same value as evt.args. However, for some events (like writes to /dev/log) it provides higher level information coming from decoding the arguments."},
{PT_BYTEBUF, EPF_NONE, PF_NA, "evt.buffer", "the binary data buffer for events that have one, like read(), recvfrom(), etc. Use this field in filters with 'contains' to search into I/O data buffers."},
{PT_UINT64, EPF_NONE, PF_DEC, "evt.buflen", "the length of the binary data buffer for events that have one, like read(), recvfrom(), etc."},
{PT_CHARBUF, EPF_NONE, PF_DEC, "evt.res", "event return value, as a string. If the event failed, the result is an error code string (e.g. 'ENOENT'), otherwise the result is the string 'SUCCESS'."},
{PT_INT64, EPF_NONE, PF_DEC, "evt.rawres", "event return value, as a number (e.g. -2). Useful for range comparisons."},
{PT_BOOL, EPF_NONE, PF_NA, "evt.failed", "'true' for events that returned an error status."},
{PT_BOOL, EPF_NONE, PF_NA, "evt.is_io", "'true' for events that read or write to FDs, like read(), send, recvfrom(), etc."},
{PT_BOOL, EPF_NONE, PF_NA, "evt.is_io_read", "'true' for events that read from FDs, like read(), recv(), recvfrom(), etc."},
{PT_BOOL, EPF_NONE, PF_NA, "evt.is_io_write", "'true' for events that write to FDs, like write(), send(), etc."},
{PT_CHARBUF, EPF_NONE, PF_NA, "evt.io_dir", "'r' for events that read from FDs, like read(); 'w' for events that write to FDs, like write()."},
{PT_BOOL, EPF_NONE, PF_NA, "evt.is_wait", "'true' for events that make the thread wait, e.g. sleep(), select(), poll()."},
{PT_RELTIME, EPF_NONE, PF_DEC, "evt.wait_latency", "for events that make the thread wait (e.g. sleep(), select(), poll()), this is the time spent waiting for the event to return, in nanoseconds."},
{PT_BOOL, EPF_NONE, PF_NA, "evt.is_syslog", "'true' for events that are writes to /dev/log."},
{PT_UINT32, EPF_NONE, PF_DEC, "evt.count", "This filter field always returns 1 and can be used to count events from inside chisels."},
{PT_UINT32, EPF_NONE, PF_DEC, "evt.count.error", "This filter field returns 1 for events that returned with an error, and can be used to count event failures from inside chisels."},
{PT_UINT32, EPF_NONE, PF_DEC, "evt.count.error.file", "This filter field returns 1 for events that returned with an error and are related to file I/O, and can be used to count event failures from inside chisels."},
{PT_UINT32, EPF_NONE, PF_DEC, "evt.count.error.net", "This filter field returns 1 for events that returned with an error and are related to network I/O, and can be used to count event failures from inside chisels."},
{PT_UINT32, EPF_NONE, PF_DEC, "evt.count.error.memory", "This filter field returns 1 for events that returned with an error and are related to memory allocation, and can be used to count event failures from inside chisels."},
{PT_UINT32, EPF_NONE, PF_DEC, "evt.count.error.other", "This filter field returns 1 for events that returned with an error and are related to none of the previous categories, and can be used to count event failures from inside chisels."},
{PT_UINT32, EPF_NONE, PF_DEC, "evt.count.exit", "This filter field returns 1 for exit events, and can be used to count single events from inside chisels."},
{PT_UINT32, EPF_TABLE_ONLY, PF_DEC, "evt.count.procinfo", "This filter field returns 1 for procinfo events generated by process main threads, and can be used to count processes from inside views."},
{PT_UINT32, EPF_TABLE_ONLY, PF_DEC, "evt.count.threadinfo", "This filter field returns 1 for procinfo events, and can be used to count processes from inside views."},
{PT_UINT64, (filtercheck_field_flags) (EPF_FILTER_ONLY | EPF_REQUIRES_ARGUMENT), PF_DEC, "evt.around", "Accepts the event if it's around the specified time interval. The syntax is evt.around[T]=D, where T is the value returned by %evt.rawtime for the event and D is a delta in milliseconds. For example, evt.around[1404996934793590564]=1000 will return the events with timestamp with one second before the timestamp and one second after it, for a total of two seconds of capture."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "evt.abspath", "Absolute path calculated from dirfd and name during syscalls like renameat and symlinkat. Use 'evt.abspath.src' or 'evt.abspath.dst' for syscalls that support multiple paths."},
{PT_UINT64, EPF_TABLE_ONLY, PF_DEC, "evt.buflen.in", "the length of the binary data buffer, but only for input I/O events."},
{PT_UINT64, EPF_TABLE_ONLY, PF_DEC, "evt.buflen.out", "the length of the binary data buffer, but only for output I/O events."},
{PT_UINT64, EPF_TABLE_ONLY, PF_DEC, "evt.buflen.file", "the length of the binary data buffer, but only for file I/O events."},
{PT_UINT64, EPF_TABLE_ONLY, PF_DEC, "evt.buflen.file.in", "the length of the binary data buffer, but only for input file I/O events."},
{PT_UINT64, EPF_TABLE_ONLY, PF_DEC, "evt.buflen.file.out", "the length of the binary data buffer, but only for output file I/O events."},
{PT_UINT64, EPF_TABLE_ONLY, PF_DEC, "evt.buflen.net", "the length of the binary data buffer, but only for network I/O events."},
{PT_UINT64, EPF_TABLE_ONLY, PF_DEC, "evt.buflen.net.in", "the length of the binary data buffer, but only for input network I/O events."},
{PT_UINT64, EPF_TABLE_ONLY, PF_DEC, "evt.buflen.net.out", "the length of the binary data buffer, but only for output network I/O events."},
{PT_BOOL, EPF_NONE, PF_NA, "evt.is_open_read", "'true' for open/openat/openat2 events where the path was opened for reading"},
{PT_BOOL, EPF_NONE, PF_NA, "evt.is_open_write", "'true' for open/openat/openat2 events where the path was opened for writing"},
{PT_CHARBUF, EPF_TABLE_ONLY, PF_NA, "evt.infra.docker.name", "for docker infrastructure events, the name of the event."},
{PT_CHARBUF, EPF_TABLE_ONLY, PF_NA, "evt.infra.docker.container.id", "for docker infrastructure events, the id of the impacted container."},
{PT_CHARBUF, EPF_TABLE_ONLY, PF_NA, "evt.infra.docker.container.name", "for docker infrastructure events, the name of the impacted container."},
{PT_CHARBUF, EPF_TABLE_ONLY, PF_NA, "evt.infra.docker.container.image", "for docker infrastructure events, the image name of the impacted container."},
{PT_BOOL, EPF_NONE, PF_NA, "evt.is_open_exec", "'true' for open/openat/openat2 or creat events where a file is created with execute permissions"},
{PT_RELTIME, EPF_NONE, PF_DEC, "evt.latency", "Latency", "delta between an exit event and the correspondent enter event, in nanoseconds."},
{PT_RELTIME, EPF_NONE, PF_DEC, "evt.latency.s", "Latency (s)", "integer part of the event latency delta."},
{PT_RELTIME, EPF_NONE, PF_10_PADDED_DEC, "evt.latency.ns", "Latency (ns)", "fractional part of the event latency delta."},
{PT_UINT64, EPF_TABLE_ONLY, PF_DEC, "evt.latency.quantized", "Quantized Latency", "10-base log of the delta between an exit event and the correspondent enter event."},
{PT_CHARBUF, EPF_NONE, PF_NA, "evt.latency.human", "Human-Readable Latency", "delta between an exit event and the correspondent enter event, as a human readable string (e.g. 10.3ms)."},
{PT_RELTIME, EPF_NONE, PF_DEC, "evt.deltatime", "Delta", "delta between this event and the previous event, in nanoseconds."},
{PT_RELTIME, EPF_NONE, PF_DEC, "evt.deltatime.s", "Delta (s)", "integer part of the delta between this event and the previous event."},
{PT_RELTIME, EPF_NONE, PF_10_PADDED_DEC, "evt.deltatime.ns", "Delta (ns)", "fractional part of the delta between this event and the previous event."},
{PT_CHARBUF, EPF_PRINT_ONLY, PF_NA, "evt.outputtime", "Output Time", "this depends on -t param, default is %evt.time ('h')."},
{PT_CHARBUF, EPF_NONE, PF_DIR, "evt.dir", "Direction", "event direction can be either '>' for enter events or '<' for exit events."},
{PT_CHARBUF, EPF_NONE, PF_NA, "evt.type", "Type", "The name of the event (e.g. 'open')."},
{PT_UINT32, EPF_REQUIRES_ARGUMENT, PF_NA, "evt.type.is", "Type Is", "allows one to specify an event type, and returns 1 for events that are of that type. For example, evt.type.is.open returns 1 for open events, 0 for any other event."},
{PT_CHARBUF, EPF_NONE, PF_NA, "syscall.type", "Syscall Type", "For system call events, the name of the system call (e.g. 'open'). Unset for other events (e.g. switch or internal events). Use this field instead of evt.type if you need to make sure that the filtered/printed value is actually a system call."},
{PT_CHARBUF, EPF_NONE, PF_NA, "evt.category", "Category", "The event category. Example values are 'file' (for file operations like open and close), 'net' (for network operations like socket and bind), memory (for things like brk or mmap), and so on."},
{PT_INT16, EPF_NONE, PF_ID, "evt.cpu", "CPU Number", "number of the CPU where this event happened."},
{PT_CHARBUF, EPF_NONE, PF_NA, "evt.args", "Arguments", "all the event arguments, aggregated into a single string."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "evt.arg", "Argument", "one of the event arguments specified by name or by number. Some events (e.g. return codes or FDs) will be converted into a text representation when possible. E.g. 'evt.arg.fd' or 'evt.arg[0]'."},
{PT_DYN, EPF_REQUIRES_ARGUMENT, PF_NA, "evt.rawarg", "Raw Argument", "one of the event arguments specified by name. E.g. 'evt.rawarg.fd'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "evt.info", "Information", "for most events, this field returns the same value as evt.args. However, for some events (like writes to /dev/log) it provides higher level information coming from decoding the arguments."},
{PT_BYTEBUF, EPF_NONE, PF_NA, "evt.buffer", "Buffer", "the binary data buffer for events that have one, like read(), recvfrom(), etc. Use this field in filters with 'contains' to search into I/O data buffers."},
{PT_UINT64, EPF_NONE, PF_DEC, "evt.buflen", "Buffer Length", "the length of the binary data buffer for events that have one, like read(), recvfrom(), etc."},
{PT_CHARBUF, EPF_NONE, PF_DEC, "evt.res", "Return Value", "event return value, as a string. If the event failed, the result is an error code string (e.g. 'ENOENT'), otherwise the result is the string 'SUCCESS'."},
{PT_INT64, EPF_NONE, PF_DEC, "evt.rawres", "Raw Return Value", "event return value, as a number (e.g. -2). Useful for range comparisons."},
{PT_BOOL, EPF_NONE, PF_NA, "evt.failed", "Failed", "'true' for events that returned an error status."},
{PT_BOOL, EPF_NONE, PF_NA, "evt.is_io", "Is I/O", "'true' for events that read or write to FDs, like read(), send, recvfrom(), etc."},
{PT_BOOL, EPF_NONE, PF_NA, "evt.is_io_read", "Is Read", "'true' for events that read from FDs, like read(), recv(), recvfrom(), etc."},
{PT_BOOL, EPF_NONE, PF_NA, "evt.is_io_write", "Is Write", "'true' for events that write to FDs, like write(), send(), etc."},
{PT_CHARBUF, EPF_NONE, PF_NA, "evt.io_dir", "I/O Direction", "'r' for events that read from FDs, like read(); 'w' for events that write to FDs, like write()."},
{PT_BOOL, EPF_NONE, PF_NA, "evt.is_wait", "Is Wait", "'true' for events that make the thread wait, e.g. sleep(), select(), poll()."},
{PT_RELTIME, EPF_NONE, PF_DEC, "evt.wait_latency", "Wait Latency", "for events that make the thread wait (e.g. sleep(), select(), poll()), this is the time spent waiting for the event to return, in nanoseconds."},
{PT_BOOL, EPF_NONE, PF_NA, "evt.is_syslog", "Is Syslog", "'true' for events that are writes to /dev/log."},
{PT_UINT32, EPF_NONE, PF_DEC, "evt.count", "Count", "This filter field always returns 1 and can be used to count events from inside chisels."},
{PT_UINT32, EPF_NONE, PF_DEC, "evt.count.error", "Error Count", "This filter field returns 1 for events that returned with an error, and can be used to count event failures from inside chisels."},
{PT_UINT32, EPF_NONE, PF_DEC, "evt.count.error.file", "File Error Count", "This filter field returns 1 for events that returned with an error and are related to file I/O, and can be used to count event failures from inside chisels."},
{PT_UINT32, EPF_NONE, PF_DEC, "evt.count.error.net", "Network Error Count", "This filter field returns 1 for events that returned with an error and are related to network I/O, and can be used to count event failures from inside chisels."},
{PT_UINT32, EPF_NONE, PF_DEC, "evt.count.error.memory", "Memory Error Count", "This filter field returns 1 for events that returned with an error and are related to memory allocation, and can be used to count event failures from inside chisels."},
{PT_UINT32, EPF_NONE, PF_DEC, "evt.count.error.other", "Other Error Count", "This filter field returns 1 for events that returned with an error and are related to none of the previous categories, and can be used to count event failures from inside chisels."},
{PT_UINT32, EPF_NONE, PF_DEC, "evt.count.exit", "Exit Count", "This filter field returns 1 for exit events, and can be used to count single events from inside chisels."},
{PT_UINT32, EPF_TABLE_ONLY, PF_DEC, "evt.count.procinfo", "Procinfo Count", "This filter field returns 1 for procinfo events generated by process main threads, and can be used to count processes from inside views."},
{PT_UINT32, EPF_TABLE_ONLY, PF_DEC, "evt.count.threadinfo", "Thread Info Count", "This filter field returns 1 for procinfo events, and can be used to count processes from inside views."},
{PT_UINT64, (filtercheck_field_flags) (EPF_FILTER_ONLY | EPF_REQUIRES_ARGUMENT), PF_DEC, "evt.around", "Around Interval", "Accepts the event if it's around the specified time interval. The syntax is evt.around[T]=D, where T is the value returned by %evt.rawtime for the event and D is a delta in milliseconds. For example, evt.around[1404996934793590564]=1000 will return the events with timestamp with one second before the timestamp and one second after it, for a total of two seconds of capture."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "evt.abspath", "Absolute Path", "Absolute path calculated from dirfd and name during syscalls like renameat and symlinkat. Use 'evt.abspath.src' or 'evt.abspath.dst' for syscalls that support multiple paths."},
{PT_UINT64, EPF_TABLE_ONLY, PF_DEC, "evt.buflen.in", "Input Buffer Length", "the length of the binary data buffer, but only for input I/O events."},
{PT_UINT64, EPF_TABLE_ONLY, PF_DEC, "evt.buflen.out", "Output Buffer Length", "the length of the binary data buffer, but only for output I/O events."},
{PT_UINT64, EPF_TABLE_ONLY, PF_DEC, "evt.buflen.file", "File Buffer Length", "the length of the binary data buffer, but only for file I/O events."},
{PT_UINT64, EPF_TABLE_ONLY, PF_DEC, "evt.buflen.file.in", "File Input Buffer Length", "the length of the binary data buffer, but only for input file I/O events."},
{PT_UINT64, EPF_TABLE_ONLY, PF_DEC, "evt.buflen.file.out", "File Output Buffer Length", "the length of the binary data buffer, but only for output file I/O events."},
{PT_UINT64, EPF_TABLE_ONLY, PF_DEC, "evt.buflen.net", "Network Buffer Length", "the length of the binary data buffer, but only for network I/O events."},
{PT_UINT64, EPF_TABLE_ONLY, PF_DEC, "evt.buflen.net.in", "Network Input Buffer Length", "the length of the binary data buffer, but only for input network I/O events."},
{PT_UINT64, EPF_TABLE_ONLY, PF_DEC, "evt.buflen.net.out", "Network Output Buffer Length", "the length of the binary data buffer, but only for output network I/O events."},
{PT_BOOL, EPF_NONE, PF_NA, "evt.is_open_read", "Is Opened For Reading", "'true' for open/openat/openat2 events where the path was opened for reading"},
{PT_BOOL, EPF_NONE, PF_NA, "evt.is_open_write", "Is Opened For Writing", "'true' for open/openat/openat2 events where the path was opened for writing"},
{PT_CHARBUF, EPF_TABLE_ONLY, PF_NA, "evt.infra.docker.name", "Docker Name", "for docker infrastructure events, the name of the event."},
{PT_CHARBUF, EPF_TABLE_ONLY, PF_NA, "evt.infra.docker.container.id", "Docker ID", "for docker infrastructure events, the id of the impacted container."},
{PT_CHARBUF, EPF_TABLE_ONLY, PF_NA, "evt.infra.docker.container.name", "Container Name", "for docker infrastructure events, the name of the impacted container."},
{PT_CHARBUF, EPF_TABLE_ONLY, PF_NA, "evt.infra.docker.container.image", "Container Image", "for docker infrastructure events, the image name of the impacted container."},
{PT_BOOL, EPF_NONE, PF_NA, "evt.is_open_exec", "Is Created With Execute Permissions", "'true' for open/openat/openat2 or creat events where a file is created with execute permissions"},
};
sinsp_filter_check_event::sinsp_filter_check_event()
@ -4753,12 +4753,12 @@ bool sinsp_filter_check_event::compare(sinsp_evt *evt)
///////////////////////////////////////////////////////////////////////////////
const filtercheck_field_info sinsp_filter_check_user_fields[] =
{
{PT_UINT32, EPF_NONE, PF_ID, "user.uid", "user ID."},
{PT_CHARBUF, EPF_NONE, PF_NA, "user.name", "user name."},
{PT_CHARBUF, EPF_NONE, PF_NA, "user.homedir", "home directory of the user."},
{PT_CHARBUF, EPF_NONE, PF_NA, "user.shell", "user's shell."},
{PT_INT32, EPF_NONE, PF_ID, "user.loginuid", "audit user id (auid)."},
{PT_CHARBUF, EPF_NONE, PF_NA, "user.loginname", "audit user name (auid)."},
{PT_UINT32, EPF_NONE, PF_ID, "user.uid", "User ID", "user ID."},
{PT_CHARBUF, EPF_NONE, PF_NA, "user.name", "User Name", "user name."},
{PT_CHARBUF, EPF_NONE, PF_NA, "user.homedir", "Home Directory", "home directory of the user."},
{PT_CHARBUF, EPF_NONE, PF_NA, "user.shell", "Shell", "user's shell."},
{PT_INT32, EPF_NONE, PF_ID, "user.loginuid", "Login User ID", "audit user id (auid)."},
{PT_CHARBUF, EPF_NONE, PF_NA, "user.loginname", "Login User Name", "audit user name (auid)."},
};
sinsp_filter_check_user::sinsp_filter_check_user()
@ -4830,8 +4830,8 @@ uint8_t* sinsp_filter_check_user::extract(sinsp_evt *evt, OUT uint32_t* len, boo
///////////////////////////////////////////////////////////////////////////////
const filtercheck_field_info sinsp_filter_check_group_fields[] =
{
{PT_UINT64, EPF_NONE, PF_ID, "group.gid", "group ID."},
{PT_CHARBUF, EPF_NONE, PF_NA, "group.name", "group name."},
{PT_UINT64, EPF_NONE, PF_ID, "group.gid", "Group ID", "group ID."},
{PT_CHARBUF, EPF_NONE, PF_NA, "group.name", "Group Name", "group name."},
};
sinsp_filter_check_group::sinsp_filter_check_group()
@ -4887,26 +4887,26 @@ uint8_t* sinsp_filter_check_group::extract(sinsp_evt *evt, OUT uint32_t* len, bo
///////////////////////////////////////////////////////////////////////////////
const filtercheck_field_info sinsp_filter_check_tracer_fields[] =
{
{PT_INT64, EPF_NONE, PF_ID, "span.id", "ID of the span. This is a unique identifier that is used to match the enter and exit tracer events for this span. It can also be used to match different spans belonging to a trace."},
{PT_CHARBUF, EPF_NONE, PF_NA, "span.time", "time of the span's enter tracer as a human readable string that includes the nanosecond part."},
{PT_UINT32, EPF_NONE, PF_DEC, "span.ntags", "number of tags that this span has."},
{PT_UINT32, EPF_NONE, PF_DEC, "span.nargs", "number of arguments that this span has."},
{PT_CHARBUF, EPF_NONE, PF_NA, "span.tags", "dot-separated list of all of the span's tags."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "span.tag", "one of the span's tags, specified by 0-based offset, e.g. 'span.tag[1]'. You can use a negative offset to pick elements from the end of the tag list. For example, 'span.tag[-1]' returns the last tag."},
{PT_CHARBUF, EPF_NONE, PF_NA, "span.args", "comma-separated list of the span's arguments." },
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "span.arg", "one of the span arguments, specified by name or by 0-based offset. E.g. 'span.arg.xxx' or 'span.arg[1]'. You can use a negative offset to pick elements from the end of the tag list. For example, 'span.arg[-1]' returns the last argument." },
{PT_CHARBUF, EPF_NONE, PF_NA, "span.enterargs", "comma-separated list of the span's enter tracer event arguments. For enter tracers, this is the same as evt.args. For exit tracers, this is the evt.args of the corresponding enter tracer." },
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "span.enterarg", "one of the span's enter arguments, specified by name or by 0-based offset. For enter tracer events, this is the same as evt.arg. For exit tracer events, this is the evt.arg of the corresponding enter event." },
{PT_RELTIME, EPF_NONE, PF_DEC, "span.duration", "delta between this span's exit tracer event and the enter tracer event."},
{PT_UINT64, EPF_TABLE_ONLY, PF_DEC, "span.duration.quantized", "10-base log of the delta between an exit tracer event and the correspondent enter event."},
{PT_CHARBUF, EPF_NONE, PF_NA, "span.duration.human", "delta between this span's exit tracer event and the enter event, as a human readable string (e.g. 10.3ms)."},
{PT_RELTIME, (filtercheck_field_flags) (EPF_TABLE_ONLY | EPF_REQUIRES_ARGUMENT), PF_DEC, "span.duration.fortag", "duration of the span if the number of tags matches the field argument, otherwise 0. For example, span.duration.fortag[1] returns the duration of all the spans with 1 tag, and zero for all the other ones."},
{PT_UINT64, EPF_TABLE_ONLY, PF_DEC, "span.count", "1 for span exit events."},
{PT_UINT64, (filtercheck_field_flags) (EPF_TABLE_ONLY | EPF_REQUIRES_ARGUMENT), PF_DEC, "span.count.fortag", "1 if the span's number of tags matches the field argument, and zero for all the other ones."},
{PT_UINT64, (filtercheck_field_flags) (EPF_TABLE_ONLY | EPF_REQUIRES_ARGUMENT), PF_DEC, "span.childcount.fortag", "1 if the span's number of tags is greater than the field argument, and zero for all the other ones."},
{PT_CHARBUF, (filtercheck_field_flags) (EPF_TABLE_ONLY | EPF_REQUIRES_ARGUMENT), PF_NA, "span.idtag", "id used by the span list view."},
{PT_CHARBUF, EPF_TABLE_ONLY, PF_NA, "span.rawtime", "id used by the span list view."},
{PT_CHARBUF, EPF_TABLE_ONLY, PF_NA, "span.rawparenttime", "id used by the span list view."},
{PT_INT64, EPF_NONE, PF_ID, "span.id", "Span ID", "ID of the span. This is a unique identifier that is used to match the enter and exit tracer events for this span. It can also be used to match different spans belonging to a trace."},
{PT_CHARBUF, EPF_NONE, PF_NA, "span.time", "Time", "time of the span's enter tracer as a human readable string that includes the nanosecond part."},
{PT_UINT32, EPF_NONE, PF_DEC, "span.ntags", "Tag Count", "number of tags that this span has."},
{PT_UINT32, EPF_NONE, PF_DEC, "span.nargs", "Argument Count", "number of arguments that this span has."},
{PT_CHARBUF, EPF_NONE, PF_NA, "span.tags", "Tags", "dot-separated list of all of the span's tags."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "span.tag", "Tag", "one of the span's tags, specified by 0-based offset, e.g. 'span.tag[1]'. You can use a negative offset to pick elements from the end of the tag list. For example, 'span.tag[-1]' returns the last tag."},
{PT_CHARBUF, EPF_NONE, PF_NA, "span.args", "Arguments", "comma-separated list of the span's arguments." },
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "span.arg", "Argument", "one of the span arguments, specified by name or by 0-based offset. E.g. 'span.arg.xxx' or 'span.arg[1]'. You can use a negative offset to pick elements from the end of the tag list. For example, 'span.arg[-1]' returns the last argument." },
{PT_CHARBUF, EPF_NONE, PF_NA, "span.enterargs", "Enter Arguments", "comma-separated list of the span's enter tracer event arguments. For enter tracers, this is the same as evt.args. For exit tracers, this is the evt.args of the corresponding enter tracer." },
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "span.enterarg", "Enter Argument", "one of the span's enter arguments, specified by name or by 0-based offset. For enter tracer events, this is the same as evt.arg. For exit tracer events, this is the evt.arg of the corresponding enter event." },
{PT_RELTIME, EPF_NONE, PF_DEC, "span.duration", "Duration", "delta between this span's exit tracer event and the enter tracer event."},
{PT_UINT64, EPF_TABLE_ONLY, PF_DEC, "span.duration.quantized", "Quantized Duration", "10-base log of the delta between an exit tracer event and the correspondent enter event."},
{PT_CHARBUF, EPF_NONE, PF_NA, "span.duration.human", "Human-Readable Duration", "delta between this span's exit tracer event and the enter event, as a human readable string (e.g. 10.3ms)."},
{PT_RELTIME, (filtercheck_field_flags) (EPF_TABLE_ONLY | EPF_REQUIRES_ARGUMENT), PF_DEC, "span.duration.fortag", "Duration For Tag", "duration of the span if the number of tags matches the field argument, otherwise 0. For example, span.duration.fortag[1] returns the duration of all the spans with 1 tag, and zero for all the other ones."},
{PT_UINT64, EPF_TABLE_ONLY, PF_DEC, "span.count", "Span Count", "1 for span exit events."},
{PT_UINT64, (filtercheck_field_flags) (EPF_TABLE_ONLY | EPF_REQUIRES_ARGUMENT), PF_DEC, "span.count.fortag", "Count For Tag", "1 if the span's number of tags matches the field argument, and zero for all the other ones."},
{PT_UINT64, (filtercheck_field_flags) (EPF_TABLE_ONLY | EPF_REQUIRES_ARGUMENT), PF_DEC, "span.childcount.fortag", "Child Count For Tag", "1 if the span's number of tags is greater than the field argument, and zero for all the other ones."},
{PT_CHARBUF, (filtercheck_field_flags) (EPF_TABLE_ONLY | EPF_REQUIRES_ARGUMENT), PF_NA, "span.idtag", "List View ID", "id used by the span list view."},
{PT_CHARBUF, EPF_TABLE_ONLY, PF_NA, "span.rawtime", "List View Time", "id used by the span list view."},
{PT_CHARBUF, EPF_TABLE_ONLY, PF_NA, "span.rawparenttime", "List View Parent Time", "id used by the span list view."},
};
sinsp_filter_check_tracer::sinsp_filter_check_tracer()
@ -5482,34 +5482,34 @@ uint8_t* sinsp_filter_check_tracer::extract(sinsp_evt *evt, OUT uint32_t* len, b
///////////////////////////////////////////////////////////////////////////////
const filtercheck_field_info sinsp_filter_check_evtin_fields[] =
{
{ PT_INT64, EPF_NONE, PF_ID, "evtin.span.id", "accepts all the events that are between the enter and exit tracers of the spans with the given ID and are generated by the same thread that generated the tracers." },
{ PT_UINT32, EPF_NONE, PF_DEC, "evtin.span.ntags", "accepts all the events that are between the enter and exit tracers of the spans with the given number of tags and are generated by the same thread that generated the tracers." },
{ PT_UINT32, EPF_NONE, PF_DEC, "evtin.span.nargs", "accepts all the events that are between the enter and exit tracers of the spans with the given number of arguments and are generated by the same thread that generated the tracers." },
{ PT_CHARBUF, EPF_NONE, PF_NA, "evtin.span.tags", "accepts all the events that are between the enter and exit tracers of the spans with the given tags and are generated by the same thread that generated the tracers." },
{ PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "evtin.span.tag", "accepts all the events that are between the enter and exit tracers of the spans with the given tag and are generated by the same thread that generated the tracers. See the description of span.tag for information about the syntax accepted by this field." },
{ PT_CHARBUF, EPF_NONE, PF_NA, "evtin.span.args", "accepts all the events that are between the enter and exit tracers of the spans with the given arguments and are generated by the same thread that generated the tracers." },
{ PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "evtin.span.arg", "accepts all the events that are between the enter and exit tracers of the spans with the given argument and are generated by the same thread that generated the tracers. See the description of span.arg for information about the syntax accepted by this field." },
{ PT_INT64, EPF_NONE, PF_ID, "evtin.span.p.id", "same as evtin.span.id, but also accepts events generated by other threads in the same process that produced the span." },
{ PT_UINT32, EPF_NONE, PF_DEC, "evtin.span.p.ntags", "same as evtin.span.ntags, but also accepts events generated by other threads in the same process that produced the span." },
{ PT_UINT32, EPF_NONE, PF_DEC, "evtin.span.p.nargs", "same as evtin.span.nargs, but also accepts events generated by other threads in the same process that produced the span." },
{ PT_CHARBUF, EPF_NONE, PF_NA, "evtin.span.p.tags", "same as evtin.span.tags, but also accepts events generated by other threads in the same process that produced the span." },
{ PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "evtin.span.p.tag", "same as evtin.span.tag, but also accepts events generated by other threads in the same process that produced the span." },
{ PT_CHARBUF, EPF_NONE, PF_NA, "evtin.span.p.args", "same as evtin.span.args, but also accepts events generated by other threads in the same process that produced the span." },
{ PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "evtin.span.p.arg", "same as evtin.span.arg, but also accepts events generated by other threads in the same process that produced the span." },
{ PT_INT64, EPF_NONE, PF_ID, "evtin.span.s.id", "same as evtin.span.id, but also accepts events generated by the script that produced the span, i.e. by the processes whose parent PID is the same as the one of the process generating the span." },
{ PT_UINT32, EPF_NONE, PF_DEC, "evtin.span.s.ntags", "same as evtin.span.id, but also accepts events generated by the script that produced the span, i.e. by the processes whose parent PID is the same as the one of the process generating the span." },
{ PT_UINT32, EPF_NONE, PF_DEC, "evtin.span.s.nargs", "same as evtin.span.id, but also accepts events generated by the script that produced the span, i.e. by the processes whose parent PID is the same as the one of the process generating the span." },
{ PT_CHARBUF, EPF_NONE, PF_NA, "evtin.span.s.tags", "same as evtin.span.id, but also accepts events generated by the script that produced the span, i.e. by the processes whose parent PID is the same as the one of the process generating the span." },
{ PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "evtin.span.s.tag", "same as evtin.span.id, but also accepts events generated by the script that produced the span, i.e. by the processes whose parent PID is the same as the one of the process generating the span." },
{ PT_CHARBUF, EPF_NONE, PF_NA, "evtin.span.s.args", "same as evtin.span.id, but also accepts events generated by the script that produced the span, i.e. by the processes whose parent PID is the same as the one of the process generating the span." },
{ PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "evtin.span.s.arg", "same as evtin.span.id, but also accepts events generated by the script that produced the span, i.e. by the processes whose parent PID is the same as the one of the process generating the span." },
{ PT_INT64, EPF_NONE, PF_ID, "evtin.span.m.id", "same as evtin.span.id, but accepts all the events generated on the machine during the span, including other threads and other processes." },
{ PT_UINT32, EPF_NONE, PF_DEC, "evtin.span.m.ntags", "same as evtin.span.id, but accepts all the events generated on the machine during the span, including other threads and other processes." },
{ PT_UINT32, EPF_NONE, PF_DEC, "evtin.span.m.nargs", "same as evtin.span.id, but accepts all the events generated on the machine during the span, including other threads and other processes." },
{ PT_CHARBUF, EPF_NONE, PF_NA, "evtin.span.m.tags", "same as evtin.span.id, but accepts all the events generated on the machine during the span, including other threads and other processes." },
{ PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "evtin.span.m.tag", "same as evtin.span.id, but accepts all the events generated on the machine during the span, including other threads and other processes." },
{ PT_CHARBUF, EPF_NONE, PF_NA, "evtin.span.m.args", "same as evtin.span.id, but accepts all the events generated on the machine during the span, including other threads and other processes." },
{ PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "evtin.span.m.arg", "same as evtin.span.id, but accepts all the events generated on the machine during the span, including other threads and other processes." },
{ PT_INT64, EPF_NONE, PF_ID, "evtin.span.id", "In Span ID", "accepts all the events that are between the enter and exit tracers of the spans with the given ID and are generated by the same thread that generated the tracers." },
{ PT_UINT32, EPF_NONE, PF_DEC, "evtin.span.ntags", "In Span Tag Count", "accepts all the events that are between the enter and exit tracers of the spans with the given number of tags and are generated by the same thread that generated the tracers." },
{ PT_UINT32, EPF_NONE, PF_DEC, "evtin.span.nargs", "In Span Argument Count", "accepts all the events that are between the enter and exit tracers of the spans with the given number of arguments and are generated by the same thread that generated the tracers." },
{ PT_CHARBUF, EPF_NONE, PF_NA, "evtin.span.tags", "In Span Tags", "accepts all the events that are between the enter and exit tracers of the spans with the given tags and are generated by the same thread that generated the tracers." },
{ PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "evtin.span.tag", "In Span Tag", "accepts all the events that are between the enter and exit tracers of the spans with the given tag and are generated by the same thread that generated the tracers. See the description of span.tag for information about the syntax accepted by this field." },
{ PT_CHARBUF, EPF_NONE, PF_NA, "evtin.span.args", "In Span Arguments", "accepts all the events that are between the enter and exit tracers of the spans with the given arguments and are generated by the same thread that generated the tracers." },
{ PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "evtin.span.arg", "In Span Argument", "accepts all the events that are between the enter and exit tracers of the spans with the given argument and are generated by the same thread that generated the tracers. See the description of span.arg for information about the syntax accepted by this field." },
{ PT_INT64, EPF_NONE, PF_ID, "evtin.span.p.id", "In Parent ID", "same as evtin.span.id, but also accepts events generated by other threads in the same process that produced the span." },
{ PT_UINT32, EPF_NONE, PF_DEC, "evtin.span.p.ntags", "In Parent Tag Count", "same as evtin.span.ntags, but also accepts events generated by other threads in the same process that produced the span." },
{ PT_UINT32, EPF_NONE, PF_DEC, "evtin.span.p.nargs", "In Parent Argument Count", "same as evtin.span.nargs, but also accepts events generated by other threads in the same process that produced the span." },
{ PT_CHARBUF, EPF_NONE, PF_NA, "evtin.span.p.tags", "In Parent Tags", "same as evtin.span.tags, but also accepts events generated by other threads in the same process that produced the span." },
{ PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "evtin.span.p.tag", "In Parent Tag", "same as evtin.span.tag, but also accepts events generated by other threads in the same process that produced the span." },
{ PT_CHARBUF, EPF_NONE, PF_NA, "evtin.span.p.args", "In Parent Arguments", "same as evtin.span.args, but also accepts events generated by other threads in the same process that produced the span." },
{ PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "evtin.span.p.arg", "In Parent Argument", "same as evtin.span.arg, but also accepts events generated by other threads in the same process that produced the span." },
{ PT_INT64, EPF_NONE, PF_ID, "evtin.span.s.id", "In Script ID", "same as evtin.span.id, but also accepts events generated by the script that produced the span, i.e. by the processes whose parent PID is the same as the one of the process generating the span." },
{ PT_UINT32, EPF_NONE, PF_DEC, "evtin.span.s.ntags", "In Script Tag Count", "same as evtin.span.id, but also accepts events generated by the script that produced the span, i.e. by the processes whose parent PID is the same as the one of the process generating the span." },
{ PT_UINT32, EPF_NONE, PF_DEC, "evtin.span.s.nargs", "In Script Argument Count", "same as evtin.span.id, but also accepts events generated by the script that produced the span, i.e. by the processes whose parent PID is the same as the one of the process generating the span." },
{ PT_CHARBUF, EPF_NONE, PF_NA, "evtin.span.s.tags", "In Script Tags", "same as evtin.span.id, but also accepts events generated by the script that produced the span, i.e. by the processes whose parent PID is the same as the one of the process generating the span." },
{ PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "evtin.span.s.tag", "In Script Tag", "same as evtin.span.id, but also accepts events generated by the script that produced the span, i.e. by the processes whose parent PID is the same as the one of the process generating the span." },
{ PT_CHARBUF, EPF_NONE, PF_NA, "evtin.span.s.args", "In Script Arguments", "same as evtin.span.id, but also accepts events generated by the script that produced the span, i.e. by the processes whose parent PID is the same as the one of the process generating the span." },
{ PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "evtin.span.s.arg", "In Script Argument", "same as evtin.span.id, but also accepts events generated by the script that produced the span, i.e. by the processes whose parent PID is the same as the one of the process generating the span." },
{ PT_INT64, EPF_NONE, PF_ID, "evtin.span.m.id", "In Machine ID", "same as evtin.span.id, but accepts all the events generated on the machine during the span, including other threads and other processes." },
{ PT_UINT32, EPF_NONE, PF_DEC, "evtin.span.m.ntags", "In Machine Tag Count", "same as evtin.span.id, but accepts all the events generated on the machine during the span, including other threads and other processes." },
{ PT_UINT32, EPF_NONE, PF_DEC, "evtin.span.m.nargs", "In Machine Argument Count", "same as evtin.span.id, but accepts all the events generated on the machine during the span, including other threads and other processes." },
{ PT_CHARBUF, EPF_NONE, PF_NA, "evtin.span.m.tags", "In Machine Tags", "same as evtin.span.id, but accepts all the events generated on the machine during the span, including other threads and other processes." },
{ PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "evtin.span.m.tag", "In Machine Tag", "same as evtin.span.id, but accepts all the events generated on the machine during the span, including other threads and other processes." },
{ PT_CHARBUF, EPF_NONE, PF_NA, "evtin.span.m.args", "In Machine Arguments", "same as evtin.span.id, but accepts all the events generated on the machine during the span, including other threads and other processes." },
{ PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "evtin.span.m.arg", "In Machine Argument", "same as evtin.span.id, but accepts all the events generated on the machine during the span, including other threads and other processes." },
};
sinsp_filter_check_evtin::sinsp_filter_check_evtin()
@ -6037,7 +6037,7 @@ fcec_end:
///////////////////////////////////////////////////////////////////////////////
const filtercheck_field_info rawstring_check_fields[] =
{
{PT_CHARBUF, EPF_NONE, PF_NA, "NA", "INTERNAL."},
{PT_CHARBUF, EPF_NONE, PF_NA, "NA", "NA", "INTERNAL."},
};
rawstring_check::rawstring_check(string text)
@ -6076,11 +6076,11 @@ uint8_t* rawstring_check::extract(sinsp_evt *evt, OUT uint32_t* len, bool saniti
///////////////////////////////////////////////////////////////////////////////
const filtercheck_field_info sinsp_filter_check_syslog_fields[] =
{
{PT_CHARBUF, EPF_NONE, PF_NA, "syslog.facility.str", "facility as a string."},
{PT_UINT32, EPF_NONE, PF_DEC, "syslog.facility", "facility as a number (0-23)."},
{PT_CHARBUF, EPF_NONE, PF_NA, "syslog.severity.str", "severity as a string. Can have one of these values: emerg, alert, crit, err, warn, notice, info, debug"},
{PT_UINT32, EPF_NONE, PF_DEC, "syslog.severity", "severity as a number (0-7)."},
{PT_CHARBUF, EPF_NONE, PF_NA, "syslog.message", "message sent to syslog."},
{PT_CHARBUF, EPF_NONE, PF_NA, "syslog.facility.str", "Facility", "facility as a string."},
{PT_UINT32, EPF_NONE, PF_DEC, "syslog.facility", "Numeric Facility", "facility as a number (0-23)."},
{PT_CHARBUF, EPF_NONE, PF_NA, "syslog.severity.str", "Severity", "severity as a string. Can have one of these values: emerg, alert, crit, err, warn, notice, info, debug"},
{PT_UINT32, EPF_NONE, PF_DEC, "syslog.severity", "Numeric Severity", "severity as a number (0-7)."},
{PT_CHARBUF, EPF_NONE, PF_NA, "syslog.message", "Message", "message sent to syslog."},
};
sinsp_filter_check_syslog::sinsp_filter_check_syslog()
@ -6143,25 +6143,25 @@ uint8_t* sinsp_filter_check_syslog::extract(sinsp_evt *evt, OUT uint32_t* len, b
///////////////////////////////////////////////////////////////////////////////
const filtercheck_field_info sinsp_filter_check_container_fields[] =
{
{PT_CHARBUF, EPF_NONE, PF_NA, "container.id", "the container id."},
{PT_CHARBUF, EPF_NONE, PF_NA, "container.name", "the container name."},
{PT_CHARBUF, EPF_NONE, PF_NA, "container.image", "the container image name (e.g. falcosecurity/falco:latest for docker)."},
{PT_CHARBUF, EPF_NONE, PF_NA, "container.image.id", "the container image id (e.g. 6f7e2741b66b)."},
{PT_CHARBUF, EPF_NONE, PF_NA, "container.type", "the container type, eg: docker or rkt"},
{PT_BOOL, EPF_NONE, PF_NA, "container.privileged", "true for containers running as privileged, false otherwise"},
{PT_CHARBUF, EPF_NONE, PF_NA, "container.mounts", "A space-separated list of mount information. Each item in the list has the format <source>:<dest>:<mode>:<rdrw>:<propagation>"},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "container.mount", "Information about a single mount, specified by number (e.g. container.mount[0]) or mount source (container.mount[/usr/local]). The pathname can be a glob (container.mount[/usr/local/*]), in which case the first matching mount will be returned. The information has the format <source>:<dest>:<mode>:<rdrw>:<propagation>. If there is no mount with the specified index or matching the provided source, returns the string \"none\" instead of a NULL value."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "container.mount.source", "the mount source, specified by number (e.g. container.mount.source[0]) or mount destination (container.mount.source[/host/lib/modules]). The pathname can be a glob."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "container.mount.dest", "the mount destination, specified by number (e.g. container.mount.dest[0]) or mount source (container.mount.dest[/lib/modules]). The pathname can be a glob."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "container.mount.mode", "the mount mode, specified by number (e.g. container.mount.mode[0]) or mount source (container.mount.mode[/usr/local]). The pathname can be a glob."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "container.mount.rdwr", "the mount rdwr value, specified by number (e.g. container.mount.rdwr[0]) or mount source (container.mount.rdwr[/usr/local]). The pathname can be a glob."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "container.mount.propagation", "the mount propagation value, specified by number (e.g. container.mount.propagation[0]) or mount source (container.mount.propagation[/usr/local]). The pathname can be a glob."},
{PT_CHARBUF, EPF_NONE, PF_NA, "container.image.repository", "the container image repository (e.g. falcosecurity/falco)."},
{PT_CHARBUF, EPF_NONE, PF_NA, "container.image.tag", "the container image tag (e.g. stable, latest)."},
{PT_CHARBUF, EPF_NONE, PF_NA, "container.image.digest", "the container image registry digest (e.g. sha256:d977378f890d445c15e51795296e4e5062f109ce6da83e0a355fc4ad8699d27)."},
{PT_CHARBUF, EPF_NONE, PF_NA, "container.healthcheck", "The container's health check. Will be the null value (\"N/A\") if no healthcheck configured, \"NONE\" if configured but explicitly not created, and the healthcheck command line otherwise"},
{PT_CHARBUF, EPF_NONE, PF_NA, "container.liveness_probe", "The container's liveness probe. Will be the null value (\"N/A\") if no liveness probe configured, the liveness probe command line otherwise"},
{PT_CHARBUF, EPF_NONE, PF_NA, "container.readiness_probe", "The container's readiness probe. Will be the null value (\"N/A\") if no readiness probe configured, the readiness probe command line otherwise"}
{PT_CHARBUF, EPF_NONE, PF_NA, "container.id", "Container ID", "the container id."},
{PT_CHARBUF, EPF_NONE, PF_NA, "container.name", "Container Name", "the container name."},
{PT_CHARBUF, EPF_NONE, PF_NA, "container.image", "Image Name", "the container image name (e.g. falcosecurity/falco:latest for docker)."},
{PT_CHARBUF, EPF_NONE, PF_NA, "container.image.id", "Image ID", "the container image id (e.g. 6f7e2741b66b)."},
{PT_CHARBUF, EPF_NONE, PF_NA, "container.type", "Type", "the container type, eg: docker or rkt"},
{PT_BOOL, EPF_NONE, PF_NA, "container.privileged", "Privileged", "true for containers running as privileged, false otherwise"},
{PT_CHARBUF, EPF_NONE, PF_NA, "container.mounts", "Mounts", "A space-separated list of mount information. Each item in the list has the format <source>:<dest>:<mode>:<rdrw>:<propagation>"},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "container.mount", "Mount", "Information about a single mount, specified by number (e.g. container.mount[0]) or mount source (container.mount[/usr/local]). The pathname can be a glob (container.mount[/usr/local/*]), in which case the first matching mount will be returned. The information has the format <source>:<dest>:<mode>:<rdrw>:<propagation>. If there is no mount with the specified index or matching the provided source, returns the string \"none\" instead of a NULL value."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "container.mount.source", "Mount Source", "the mount source, specified by number (e.g. container.mount.source[0]) or mount destination (container.mount.source[/host/lib/modules]). The pathname can be a glob."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "container.mount.dest", "Mount Destination", "the mount destination, specified by number (e.g. container.mount.dest[0]) or mount source (container.mount.dest[/lib/modules]). The pathname can be a glob."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "container.mount.mode", "Mount Mode", "the mount mode, specified by number (e.g. container.mount.mode[0]) or mount source (container.mount.mode[/usr/local]). The pathname can be a glob."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "container.mount.rdwr", "Mount Read/Write", "the mount rdwr value, specified by number (e.g. container.mount.rdwr[0]) or mount source (container.mount.rdwr[/usr/local]). The pathname can be a glob."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "container.mount.propagation", "Mount Propagation", "the mount propagation value, specified by number (e.g. container.mount.propagation[0]) or mount source (container.mount.propagation[/usr/local]). The pathname can be a glob."},
{PT_CHARBUF, EPF_NONE, PF_NA, "container.image.repository", "Repository", "the container image repository (e.g. falcosecurity/falco)."},
{PT_CHARBUF, EPF_NONE, PF_NA, "container.image.tag", "Image Tag", "the container image tag (e.g. stable, latest)."},
{PT_CHARBUF, EPF_NONE, PF_NA, "container.image.digest", "Registry Digest", "the container image registry digest (e.g. sha256:d977378f890d445c15e51795296e4e5062f109ce6da83e0a355fc4ad8699d27)."},
{PT_CHARBUF, EPF_NONE, PF_NA, "container.healthcheck", "Health Check", "The container's health check. Will be the null value (\"N/A\") if no healthcheck configured, \"NONE\" if configured but explicitly not created, and the healthcheck command line otherwise"},
{PT_CHARBUF, EPF_NONE, PF_NA, "container.liveness_probe", "Liveness", "The container's liveness probe. Will be the null value (\"N/A\") if no liveness probe configured, the liveness probe command line otherwise"},
{PT_CHARBUF, EPF_NONE, PF_NA, "container.readiness_probe", "Readiness", "The container's readiness probe. Will be the null value (\"N/A\") if no readiness probe configured, the readiness probe command line otherwise"}
};
sinsp_filter_check_container::sinsp_filter_check_container()
@ -7040,7 +7040,7 @@ Json::Value sinsp_filter_check_reference::tojson(sinsp_evt* evt,
///////////////////////////////////////////////////////////////////////////////
const filtercheck_field_info sinsp_filter_check_utils_fields[] =
{
{PT_UINT64, EPF_NONE, PF_ID, "util.cnt", "incremental counter."},
{PT_UINT64, EPF_NONE, PF_ID, "util.cnt", "Counter", "incremental counter."},
};
sinsp_filter_check_utils::sinsp_filter_check_utils()
@ -7079,12 +7079,12 @@ uint8_t* sinsp_filter_check_utils::extract(sinsp_evt *evt, OUT uint32_t* len, bo
///////////////////////////////////////////////////////////////////////////////
const filtercheck_field_info sinsp_filter_check_fdlist_fields[] =
{
{PT_CHARBUF, EPF_NONE, PF_ID, "fdlist.nums", "for poll events, this is a comma-separated list of the FD numbers in the 'fds' argument, returned as a string."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fdlist.names", "for poll events, this is a comma-separated list of the FD names in the 'fds' argument, returned as a string."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fdlist.cips", "for poll events, this is a comma-separated list of the client IP addresses in the 'fds' argument, returned as a string."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fdlist.sips", "for poll events, this is a comma-separated list of the server IP addresses in the 'fds' argument, returned as a string."},
{PT_CHARBUF, EPF_NONE, PF_DEC, "fdlist.cports", "for TCP/UDP FDs, for poll events, this is a comma-separated list of the client TCP/UDP ports in the 'fds' argument, returned as a string."},
{PT_CHARBUF, EPF_NONE, PF_DEC, "fdlist.sports", "for poll events, this is a comma-separated list of the server TCP/UDP ports in the 'fds' argument, returned as a string."},
{PT_CHARBUF, EPF_NONE, PF_ID, "fdlist.nums", "FD Numbers", "for poll events, this is a comma-separated list of the FD numbers in the 'fds' argument, returned as a string."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fdlist.names", "FD Names", "for poll events, this is a comma-separated list of the FD names in the 'fds' argument, returned as a string."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fdlist.cips", "FD Client Addresses", "for poll events, this is a comma-separated list of the client IP addresses in the 'fds' argument, returned as a string."},
{PT_CHARBUF, EPF_NONE, PF_NA, "fdlist.sips", "FD Source Addresses", "for poll events, this is a comma-separated list of the server IP addresses in the 'fds' argument, returned as a string."},
{PT_CHARBUF, EPF_NONE, PF_DEC, "fdlist.cports", "FD Client Ports", "for TCP/UDP FDs, for poll events, this is a comma-separated list of the client TCP/UDP ports in the 'fds' argument, returned as a string."},
{PT_CHARBUF, EPF_NONE, PF_DEC, "fdlist.sports", "FD Source Ports", "for poll events, this is a comma-separated list of the server TCP/UDP ports in the 'fds' argument, returned as a string."},
};
sinsp_filter_check_fdlist::sinsp_filter_check_fdlist()
@ -7288,30 +7288,30 @@ uint8_t* sinsp_filter_check_fdlist::extract(sinsp_evt *evt, OUT uint32_t* len, b
///////////////////////////////////////////////////////////////////////////////
const filtercheck_field_info sinsp_filter_check_k8s_fields[] =
{
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.pod.name", "Kubernetes pod name."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.pod.id", "Kubernetes pod id."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "k8s.pod.label", "Kubernetes pod label. E.g. 'k8s.pod.label.foo'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.pod.labels", "Kubernetes pod comma-separated key/value labels. E.g. 'foo1:bar1,foo2:bar2'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.rc.name", "Kubernetes replication controller name."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.rc.id", "Kubernetes replication controller id."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "k8s.rc.label", "Kubernetes replication controller label. E.g. 'k8s.rc.label.foo'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.rc.labels", "Kubernetes replication controller comma-separated key/value labels. E.g. 'foo1:bar1,foo2:bar2'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.svc.name", "Kubernetes service name (can return more than one value, concatenated)."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.svc.id", "Kubernetes service id (can return more than one value, concatenated)."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "k8s.svc.label", "Kubernetes service label. E.g. 'k8s.svc.label.foo' (can return more than one value, concatenated)."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.svc.labels", "Kubernetes service comma-separated key/value labels. E.g. 'foo1:bar1,foo2:bar2'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.ns.name", "Kubernetes namespace name."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.ns.id", "Kubernetes namespace id."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "k8s.ns.label", "Kubernetes namespace label. E.g. 'k8s.ns.label.foo'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.ns.labels", "Kubernetes namespace comma-separated key/value labels. E.g. 'foo1:bar1,foo2:bar2'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.rs.name", "Kubernetes replica set name."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.rs.id", "Kubernetes replica set id."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "k8s.rs.label", "Kubernetes replica set label. E.g. 'k8s.rs.label.foo'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.rs.labels", "Kubernetes replica set comma-separated key/value labels. E.g. 'foo1:bar1,foo2:bar2'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.deployment.name", "Kubernetes deployment name."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.deployment.id", "Kubernetes deployment id."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "k8s.deployment.label", "Kubernetes deployment label. E.g. 'k8s.rs.label.foo'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.deployment.labels", "Kubernetes deployment comma-separated key/value labels. E.g. 'foo1:bar1,foo2:bar2'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.pod.name", "Pod Name", "Kubernetes pod name."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.pod.id", "Pod ID", "Kubernetes pod id."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "k8s.pod.label", "Pod Label", "Kubernetes pod label. E.g. 'k8s.pod.label.foo'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.pod.labels", "Pod Labels", "Kubernetes pod comma-separated key/value labels. E.g. 'foo1:bar1,foo2:bar2'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.rc.name", "Replication Controller Name", "Kubernetes replication controller name."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.rc.id", "Replication Controller ID", "Kubernetes replication controller id."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "k8s.rc.label", "Replication Controller Label", "Kubernetes replication controller label. E.g. 'k8s.rc.label.foo'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.rc.labels", "Replication Controller Labels", "Kubernetes replication controller comma-separated key/value labels. E.g. 'foo1:bar1,foo2:bar2'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.svc.name", "Service Name", "Kubernetes service name (can return more than one value, concatenated)."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.svc.id", "Service ID", "Kubernetes service id (can return more than one value, concatenated)."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "k8s.svc.label", "Service Label", "Kubernetes service label. E.g. 'k8s.svc.label.foo' (can return more than one value, concatenated)."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.svc.labels", "Service Labels", "Kubernetes service comma-separated key/value labels. E.g. 'foo1:bar1,foo2:bar2'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.ns.name", "Namespace Name", "Kubernetes namespace name."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.ns.id", "Namespace ID", "Kubernetes namespace id."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "k8s.ns.label", "Namespace Label", "Kubernetes namespace label. E.g. 'k8s.ns.label.foo'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.ns.labels", "Namespace Labels", "Kubernetes namespace comma-separated key/value labels. E.g. 'foo1:bar1,foo2:bar2'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.rs.name", "Replica Set Name", "Kubernetes replica set name."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.rs.id", "Replica Set ID", "Kubernetes replica set id."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "k8s.rs.label", "Replica Set Label", "Kubernetes replica set label. E.g. 'k8s.rs.label.foo'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.rs.labels", "Replica Set Labels", "Kubernetes replica set comma-separated key/value labels. E.g. 'foo1:bar1,foo2:bar2'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.deployment.name", "Deployment Name", "Kubernetes deployment name."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.deployment.id", "Deployment ID", "Kubernetes deployment id."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "k8s.deployment.label", "Deployment Label", "Kubernetes deployment label. E.g. 'k8s.rs.label.foo'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "k8s.deployment.labels", "Deployment Labels", "Kubernetes deployment comma-separated key/value labels. E.g. 'foo1:bar1,foo2:bar2'."},
};
sinsp_filter_check_k8s::sinsp_filter_check_k8s()
@ -7954,18 +7954,18 @@ uint8_t* sinsp_filter_check_k8s::extract(sinsp_evt *evt, OUT uint32_t* len, bool
const filtercheck_field_info sinsp_filter_check_mesos_fields[] =
{
{PT_CHARBUF, EPF_NONE, PF_NA, "mesos.task.name", "Mesos task name."},
{PT_CHARBUF, EPF_NONE, PF_NA, "mesos.task.id", "Mesos task id."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "mesos.task.label", "Mesos task label. E.g. 'mesos.task.label.foo'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "mesos.task.labels", "Mesos task comma-separated key/value labels. E.g. 'foo1:bar1,foo2:bar2'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "mesos.framework.name", "Mesos framework name."},
{PT_CHARBUF, EPF_NONE, PF_NA, "mesos.framework.id", "Mesos framework id."},
{PT_CHARBUF, EPF_NONE, PF_NA, "marathon.app.name", "Marathon app name."},
{PT_CHARBUF, EPF_NONE, PF_NA, "marathon.app.id", "Marathon app id."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "marathon.app.label", "Marathon app label. E.g. 'marathon.app.label.foo'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "marathon.app.labels", "Marathon app comma-separated key/value labels. E.g. 'foo1:bar1,foo2:bar2'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "marathon.group.name", "Marathon group name."},
{PT_CHARBUF, EPF_NONE, PF_NA, "marathon.group.id", "Marathon group id."},
{PT_CHARBUF, EPF_NONE, PF_NA, "mesos.task.name", "Task Name", "Mesos task name."},
{PT_CHARBUF, EPF_NONE, PF_NA, "mesos.task.id", "Task ID", "Mesos task id."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "mesos.task.label", "Task Label", "Mesos task label. E.g. 'mesos.task.label.foo'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "mesos.task.labels", "Task Labels", "Mesos task comma-separated key/value labels. E.g. 'foo1:bar1,foo2:bar2'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "mesos.framework.name", "Framework Name", "Mesos framework name."},
{PT_CHARBUF, EPF_NONE, PF_NA, "mesos.framework.id", "Framework ID", "Mesos framework id."},
{PT_CHARBUF, EPF_NONE, PF_NA, "marathon.app.name", "App Name", "Marathon app name."},
{PT_CHARBUF, EPF_NONE, PF_NA, "marathon.app.id", "App ID", "Marathon app id."},
{PT_CHARBUF, EPF_REQUIRES_ARGUMENT, PF_NA, "marathon.app.label", "App Label", "Marathon app label. E.g. 'marathon.app.label.foo'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "marathon.app.labels", "App Labels", "Marathon app comma-separated key/value labels. E.g. 'foo1:bar1,foo2:bar2'."},
{PT_CHARBUF, EPF_NONE, PF_NA, "marathon.group.name", "Group Name", "Marathon group name."},
{PT_CHARBUF, EPF_NONE, PF_NA, "marathon.group.id", "Group ID", "Marathon group id."},
};
sinsp_filter_check_mesos::sinsp_filter_check_mesos()

View File

@ -399,6 +399,47 @@ void gen_event_filter_factory::filter_fieldclass_info::wrapstring(const std::str
}
}
std::string gen_event_filter_factory::filter_fieldclass_info::as_markdown(const std::set<std::string>& event_sources)
{
std::ostringstream os;
os << "## Field Class: " << name << std::endl << std::endl;
if(desc != "")
{
os << desc << std::endl << std::endl;
}
if(!event_sources.empty())
{
os << "Event Sources: ";
for(const auto &src : event_sources)
{
os << src << " ";
}
os << std::endl << std::endl;
}
os << "Name | Type | Description" << std::endl;
os << ":----|:-----|:-----------" << std::endl;
for(auto &fld_info : fields)
{
// Skip fields that should not be included
// (e.g. hidden fields)
if(fld_info.is_skippable())
{
continue;
}
os << "`" << fld_info.name << "` | " << fld_info.data_type << " | " << fld_info.desc << std::endl;
}
return os.str();
}
std::string gen_event_filter_factory::filter_fieldclass_info::as_string(bool verbose, const std::set<std::string>& event_sources)
{
std::ostringstream os;

View File

@ -280,6 +280,11 @@ public:
// event sources, and the name and description of each field.
std::string as_string(bool verbose, const std::set<std::string>& event_sources = std::set<std::string>());
// Print a markdown representation of this
// field class, suitable for publication on the documentation
// website.
std::string as_markdown(const std::set<std::string>& event_sources = std::set<std::string>());
// How far to right-justify the name/description/etc block.
static uint32_t s_rightblock_start;

View File

@ -179,7 +179,7 @@ void sinsp_parser::process_event(sinsp_evt *evt)
#if defined(HAS_FILTERING) && defined(HAS_CAPTURE_FILTERING)
bool do_filter_later = false;
if(m_inspector->m_filter || m_inspector->m_evttype_filter)
if(m_inspector->m_filter)
{
ppm_event_flags eflags = evt->get_info_flags();
@ -251,12 +251,14 @@ void sinsp_parser::process_event(sinsp_evt *evt)
// FALLTHRU
case PPME_SYSCALL_OPEN_E:
case PPME_SYSCALL_CREAT_E:
case PPME_SYSCALL_OPENAT_E:
case PPME_SYSCALL_OPENAT_2_E:
case PPME_SYSCALL_OPENAT2_E:
case PPME_SOCKET_SOCKET_E:
case PPME_SYSCALL_EVENTFD_E:
case PPME_SYSCALL_CHDIR_E:
case PPME_SYSCALL_FCHDIR_E:
case PPME_SYSCALL_CREAT_E:
case PPME_SYSCALL_OPENAT_E:
case PPME_SOCKET_SHUTDOWN_E:
case PPME_SYSCALL_GETRLIMIT_E:
case PPME_SYSCALL_SETRLIMIT_E:
@ -329,6 +331,7 @@ void sinsp_parser::process_event(sinsp_evt *evt)
case PPME_SYSCALL_VFORK_X:
case PPME_SYSCALL_VFORK_17_X:
case PPME_SYSCALL_VFORK_20_X:
case PPME_SYSCALL_CLONE3_X:
parse_clone_exit(evt);
break;
case PPME_SYSCALL_EXECVE_8_X:
@ -606,6 +609,7 @@ bool sinsp_parser::reset(sinsp_evt *evt)
etype == PPME_SYSCALL_VFORK_X ||
etype == PPME_SYSCALL_VFORK_17_X ||
etype == PPME_SYSCALL_VFORK_20_X ||
etype == PPME_SYSCALL_CLONE3_X ||
etype == PPME_SCHEDSWITCH_6_E)
{
query_os = false;
@ -641,7 +645,8 @@ bool sinsp_parser::reset(sinsp_evt *evt)
etype == PPME_SYSCALL_FORK_20_X ||
etype == PPME_SYSCALL_VFORK_X ||
etype == PPME_SYSCALL_VFORK_17_X ||
etype == PPME_SYSCALL_VFORK_20_X)
etype == PPME_SYSCALL_VFORK_20_X ||
etype == PPME_SYSCALL_CLONE3_X)
{
#ifdef GATHER_INTERNAL_STATS
m_inspector->m_thread_manager->m_failed_lookups->decrement();
@ -740,6 +745,19 @@ bool sinsp_parser::reset(sinsp_evt *evt)
//
if(eflags & EF_USES_FD)
{
//
// The copy_file_range syscall has the peculiarity of using two fds
// Set as m_lastevent_fd the output fd
//
if(etype == PPME_SYSCALL_COPY_FILE_RANGE_X)
{
sinsp_evt_param *parinfo;
parinfo = evt->get_param(1);
ASSERT(parinfo->m_len == sizeof(int64_t));
tinfo->m_lastevent_fd = *(int64_t *)parinfo->m_val;
}
evt->m_fdinfo = tinfo->get_fd(tinfo->m_lastevent_fd);
if(evt->m_fdinfo == NULL)
@ -954,6 +972,7 @@ void sinsp_parser::parse_clone_exit(sinsp_evt *evt)
case PPME_SYSCALL_CLONE_20_X:
case PPME_SYSCALL_FORK_20_X:
case PPME_SYSCALL_VFORK_20_X:
case PPME_SYSCALL_CLONE3_X:
parinfo = evt->get_param(15);
break;
default:
@ -986,6 +1005,7 @@ void sinsp_parser::parse_clone_exit(sinsp_evt *evt)
case PPME_SYSCALL_CLONE_20_X:
case PPME_SYSCALL_FORK_20_X:
case PPME_SYSCALL_VFORK_20_X:
case PPME_SYSCALL_CLONE3_X:
parinfo = evt->get_param(18);
ASSERT(parinfo->m_len == sizeof(int64_t));
vtid = *(int64_t *)parinfo->m_val;
@ -1259,6 +1279,7 @@ void sinsp_parser::parse_clone_exit(sinsp_evt *evt)
case PPME_SYSCALL_FORK_20_X:
case PPME_SYSCALL_VFORK_17_X:
case PPME_SYSCALL_VFORK_20_X:
case PPME_SYSCALL_CLONE3_X:
parinfo = evt->get_param(13);
tinfo->m_comm = parinfo->m_val;
break;
@ -1375,6 +1396,7 @@ void sinsp_parser::parse_clone_exit(sinsp_evt *evt)
case PPME_SYSCALL_FORK_20_X:
case PPME_SYSCALL_VFORK_17_X:
case PPME_SYSCALL_VFORK_20_X:
case PPME_SYSCALL_CLONE3_X:
parinfo = evt->get_param(13);
tinfo->m_comm = parinfo->m_val;
break;
@ -1404,6 +1426,7 @@ void sinsp_parser::parse_clone_exit(sinsp_evt *evt)
case PPME_SYSCALL_VFORK_X:
case PPME_SYSCALL_VFORK_17_X:
case PPME_SYSCALL_VFORK_20_X:
case PPME_SYSCALL_CLONE3_X:
// Get the pgflt_maj
parinfo = evt->get_param(8);
ASSERT(parinfo->m_len == sizeof(uint64_t));
@ -1452,6 +1475,7 @@ void sinsp_parser::parse_clone_exit(sinsp_evt *evt)
case PPME_SYSCALL_CLONE_20_X:
case PPME_SYSCALL_FORK_20_X:
case PPME_SYSCALL_VFORK_20_X:
case PPME_SYSCALL_CLONE3_X:
parinfo = evt->get_param(16);
break;
default:
@ -1479,6 +1503,7 @@ void sinsp_parser::parse_clone_exit(sinsp_evt *evt)
case PPME_SYSCALL_CLONE_20_X:
case PPME_SYSCALL_FORK_20_X:
case PPME_SYSCALL_VFORK_20_X:
case PPME_SYSCALL_CLONE3_X:
parinfo = evt->get_param(17);
break;
default:
@ -1515,6 +1540,7 @@ void sinsp_parser::parse_clone_exit(sinsp_evt *evt)
case PPME_SYSCALL_FORK_20_X:
case PPME_SYSCALL_VFORK_20_X:
case PPME_SYSCALL_CLONE_20_X:
case PPME_SYSCALL_CLONE3_X:
parinfo = evt->get_param(14);
tinfo->set_cgroups(parinfo->m_val, parinfo->m_len);
m_inspector->m_container_manager.resolve_container(tinfo, m_inspector->is_live());
@ -2094,13 +2120,17 @@ void sinsp_parser::parse_open_openat_creat_exit(sinsp_evt *evt)
sinsp_evt_param *parinfo;
int64_t fd;
char *name;
char *enter_evt_name;
uint32_t namelen;
uint32_t enter_evt_namelen;
uint32_t flags;
uint32_t enter_evt_flags;
sinsp_fdinfo_t fdi;
sinsp_evt *enter_evt = &m_tmp_evt;
string sdir;
uint16_t etype = evt->get_type();
uint32_t dev = 0;
bool lastevent_retrieved;
ASSERT(evt->m_tinfo);
if(evt->m_tinfo == nullptr)
@ -2108,17 +2138,10 @@ void sinsp_parser::parse_open_openat_creat_exit(sinsp_evt *evt)
return;
}
if(etype != PPME_SYSCALL_OPENAT_2_X && etype != PPME_SYSCALL_OPENAT2_X)
{
//
// Load the enter event so we can access its arguments
//
if(!retrieve_enter_event(enter_evt, evt))
{
return;
}
}
//
// Load the enter event so we can access its arguments
//
lastevent_retrieved = retrieve_enter_event(enter_evt, evt);
//
// Check the return value
@ -2147,6 +2170,27 @@ void sinsp_parser::parse_open_openat_creat_exit(sinsp_evt *evt)
dev = *(uint32_t *)parinfo->m_val;
}
//
// Compare with enter event parameters
//
if(lastevent_retrieved && enter_evt->get_num_params() >= 2)
{
parinfo = enter_evt->get_param(0);
enter_evt_name = parinfo->m_val;
enter_evt_namelen = parinfo->m_len;
parinfo = enter_evt->get_param(1);
ASSERT(parinfo->m_len == sizeof(uint32_t));
enter_evt_flags = *(uint32_t *)parinfo->m_val;
if(enter_evt_namelen != 0 && strcmp(enter_evt_name, "(NULL)") != 0)
{
name = enter_evt_name;
namelen = enter_evt_namelen;
flags = enter_evt_flags;
}
}
sdir = evt->m_tinfo->get_cwd();
}
else if(etype == PPME_SYSCALL_CREAT_X)
@ -2164,6 +2208,22 @@ void sinsp_parser::parse_open_openat_creat_exit(sinsp_evt *evt)
dev = *(uint32_t *)parinfo->m_val;
}
if(lastevent_retrieved && enter_evt->get_num_params() >= 1)
{
parinfo = enter_evt->get_param(0);
enter_evt_name = parinfo->m_val;
enter_evt_namelen = parinfo->m_len;
enter_evt_flags = 0;
if(enter_evt_namelen != 0 && strcmp(enter_evt_name, "(NULL)") != 0)
{
name = enter_evt_name;
namelen = enter_evt_namelen;
flags = enter_evt_flags;
}
}
sdir = evt->m_tinfo->get_cwd();
}
else if(etype == PPME_SYSCALL_OPENAT_X)
@ -2203,6 +2263,32 @@ void sinsp_parser::parse_open_openat_creat_exit(sinsp_evt *evt)
dev = *(uint32_t *)parinfo->m_val;
}
//
// Compare with enter event parameters
//
if(lastevent_retrieved && enter_evt->get_num_params() >= 3)
{
parinfo = enter_evt->get_param(1);
enter_evt_name = parinfo->m_val;
enter_evt_namelen = parinfo->m_len;
parinfo = enter_evt->get_param(2);
ASSERT(parinfo->m_len == sizeof(uint32_t));
enter_evt_flags = *(uint32_t *)parinfo->m_val;
parinfo = enter_evt->get_param(0);
ASSERT(parinfo->m_len == sizeof(int64_t));
int64_t enter_evt_dirfd = *(int64_t *)parinfo->m_val;
if(enter_evt_namelen != 0 && strcmp(enter_evt_name, "(NULL)") != 0)
{
name = enter_evt_name;
namelen = enter_evt_namelen;
flags = enter_evt_flags;
dirfd = enter_evt_dirfd;
}
}
parse_dirfd(evt, name, dirfd, &sdir);
}
else
@ -2606,11 +2692,8 @@ void sinsp_parser::parse_bind_exit(sinsp_evt *evt)
* Register a socket in pending state
*/
void sinsp_parser::parse_connect_enter(sinsp_evt *evt){
if(!m_track_connection_status){
return;
}
sinsp_evt_param *parinfo;
const char *parstr;
uint8_t *packed_data;
if(evt->m_fdinfo == NULL)
@ -2618,7 +2701,15 @@ void sinsp_parser::parse_connect_enter(sinsp_evt *evt){
return;
}
evt->m_fdinfo->set_socket_pending();
if (m_track_connection_status) {
evt->m_fdinfo->set_socket_pending();
}
if(evt->get_num_params() < 2)
{
return;
}
parinfo = evt->get_param(1);
if(parinfo->m_len == 0)
{
@ -2631,14 +2722,52 @@ void sinsp_parser::parse_connect_enter(sinsp_evt *evt){
return;
}
packed_data = (uint8_t*)parinfo->m_val;
packed_data = (uint8_t*)parinfo->m_val;
fill_client_socket_info(evt, packed_data);
uint8_t family = *packed_data;
if(family == PPM_AF_INET)
{
evt->m_fdinfo->m_type = SCAP_FD_IPV4_SOCK;
memcpy(&evt->m_fdinfo->m_sockinfo.m_ipv4info.m_fields.m_dip, packed_data + 1, sizeof(uint32_t));
memcpy(&evt->m_fdinfo->m_sockinfo.m_ipv4info.m_fields.m_dport, packed_data + 5, sizeof(uint16_t));
}
else if (family == PPM_AF_INET6)
{
uint16_t port;
memcpy(&port, packed_data + 17, sizeof(uint16_t));
uint8_t* ip = packed_data + 1;
if(sinsp_utils::is_ipv4_mapped_ipv6(ip))
{
evt->m_fdinfo->m_type = SCAP_FD_IPV4_SOCK;
memcpy(&evt->m_fdinfo->m_sockinfo.m_ipv4info.m_fields.m_dip, packed_data + 13, sizeof(uint32_t));
evt->m_fdinfo->m_sockinfo.m_ipv4info.m_fields.m_dport = port;
}
else
{
evt->m_fdinfo->m_type = SCAP_FD_IPV6_SOCK;
evt->m_fdinfo->m_sockinfo.m_ipv6info.m_fields.m_dport = port;
memcpy(evt->m_fdinfo->m_sockinfo.m_ipv6info.m_fields.m_dip.m_b, ip, sizeof(ipv6addr));
}
} else {
//
// Add the friendly name to the fd info
//
evt->m_fdinfo->m_name = evt->get_param_as_str(1, &parstr, sinsp_evt::PF_SIMPLE);
#ifndef HAS_ANALYZER
//
// Update the FD with this tuple
//
m_inspector->m_parser->set_unix_info(evt->m_fdinfo, packed_data);
#endif
}
//
// If there's a listener callback, invoke it
// If there's a listener callback and we're tracking connection status, invoke it
//
if(m_fd_listener)
if(m_track_connection_status && m_fd_listener)
{
m_fd_listener->on_connect(evt, packed_data);
}
@ -2698,19 +2827,12 @@ inline void sinsp_parser::fill_client_socket_info(sinsp_evt *evt, uint8_t *packe
//
// Add the friendly name to the fd info
//
if(evt->m_fdinfo->is_role_server() && evt->m_fdinfo->is_udp_socket())
{
sinsp_utils::sockinfo_to_str(&evt->m_fdinfo->m_sockinfo,
evt->m_fdinfo->m_type, &evt->m_paramstr_storage[0],
(uint32_t)evt->m_paramstr_storage.size(),
m_inspector->m_hostname_and_port_resolution_enabled);
sinsp_utils::sockinfo_to_str(&evt->m_fdinfo->m_sockinfo,
evt->m_fdinfo->m_type, &evt->m_paramstr_storage[0],
(uint32_t)evt->m_paramstr_storage.size(),
m_inspector->m_hostname_and_port_resolution_enabled);
evt->m_fdinfo->m_name = &evt->m_paramstr_storage[0];
}
else
{
evt->m_fdinfo->m_name = evt->get_param_as_str(1, &parstr, sinsp_evt::PF_SIMPLE);
}
evt->m_fdinfo->m_name = &evt->m_paramstr_storage[0];
}
else
{
@ -3189,16 +3311,9 @@ void sinsp_parser::parse_thread_exit(sinsp_evt *evt)
}
}
bool sinsp_parser::set_ipv4_addresses_and_ports(sinsp_fdinfo_t* fdinfo, uint8_t* packed_data)
inline bool sinsp_parser::update_ipv4_addresses_and_ports(sinsp_fdinfo_t* fdinfo,
uint32_t tsip, uint16_t tsport, uint32_t tdip, uint16_t tdport)
{
uint32_t tsip, tdip;
uint16_t tsport, tdport;
tsip = *(uint32_t *)(packed_data + 1);
tsport = *(uint16_t *)(packed_data + 5);
tdip = *(uint32_t *)(packed_data + 7);
tdport = *(uint16_t *)(packed_data + 11);
if(fdinfo->m_type == SCAP_FD_IPV4_SOCK)
{
if((tsip == fdinfo->m_sockinfo.m_ipv4info.m_fields.m_sip &&
@ -3215,12 +3330,42 @@ bool sinsp_parser::set_ipv4_addresses_and_ports(sinsp_fdinfo_t* fdinfo, uint8_t*
}
}
fdinfo->m_sockinfo.m_ipv4info.m_fields.m_sip = tsip;
fdinfo->m_sockinfo.m_ipv4info.m_fields.m_sport = tsport;
fdinfo->m_sockinfo.m_ipv4info.m_fields.m_dip = tdip;
fdinfo->m_sockinfo.m_ipv4info.m_fields.m_dport = tdport;
bool changed = false;
return true;
if(fdinfo->m_sockinfo.m_ipv4info.m_fields.m_sip != tsip) {
fdinfo->m_sockinfo.m_ipv4info.m_fields.m_sip = tsip;
changed = true;
}
if(fdinfo->m_sockinfo.m_ipv4info.m_fields.m_sport != tsport) {
fdinfo->m_sockinfo.m_ipv4info.m_fields.m_sport = tsport;
changed = true;
}
if(fdinfo->m_sockinfo.m_ipv4info.m_fields.m_dip == 0) {
fdinfo->m_sockinfo.m_ipv4info.m_fields.m_dip = tdip;
changed = true;
}
if(fdinfo->m_sockinfo.m_ipv4info.m_fields.m_dport == 0) {
fdinfo->m_sockinfo.m_ipv4info.m_fields.m_dport = tdport;
changed = true;
}
return changed;
}
bool sinsp_parser::set_ipv4_addresses_and_ports(sinsp_fdinfo_t* fdinfo, uint8_t* packed_data)
{
uint32_t tsip, tdip;
uint16_t tsport, tdport;
memcpy(&tsip, packed_data + 1, sizeof(uint32_t));
memcpy(&tsport, packed_data + 5, sizeof(uint16_t));
memcpy(&tdip, packed_data + 7, sizeof(uint32_t));
memcpy(&tdport, packed_data + 11, sizeof(uint16_t));
return update_ipv4_addresses_and_ports(fdinfo, tsip, tsport, tdip, tdport);
}
bool sinsp_parser::set_ipv4_mapped_ipv6_addresses_and_ports(sinsp_fdinfo_t* fdinfo, uint8_t* packed_data)
@ -3233,28 +3378,7 @@ bool sinsp_parser::set_ipv4_mapped_ipv6_addresses_and_ports(sinsp_fdinfo_t* fdin
tdip = *(uint32_t *)(packed_data + 31);
tdport = *(uint16_t *)(packed_data + 35);
if(fdinfo->m_type == SCAP_FD_IPV4_SOCK)
{
if((tsip == fdinfo->m_sockinfo.m_ipv4info.m_fields.m_sip &&
tsport == fdinfo->m_sockinfo.m_ipv4info.m_fields.m_sport &&
tdip == fdinfo->m_sockinfo.m_ipv4info.m_fields.m_dip &&
tdport == fdinfo->m_sockinfo.m_ipv4info.m_fields.m_dport) ||
(tdip == fdinfo->m_sockinfo.m_ipv4info.m_fields.m_sip &&
tdport == fdinfo->m_sockinfo.m_ipv4info.m_fields.m_sport &&
tsip == fdinfo->m_sockinfo.m_ipv4info.m_fields.m_dip &&
tsport == fdinfo->m_sockinfo.m_ipv4info.m_fields.m_dport)
)
{
return false;
}
}
fdinfo->m_sockinfo.m_ipv4info.m_fields.m_sip = tsip;
fdinfo->m_sockinfo.m_ipv4info.m_fields.m_sport = tsport;
fdinfo->m_sockinfo.m_ipv4info.m_fields.m_dip = tdip;
fdinfo->m_sockinfo.m_ipv4info.m_fields.m_dport = tdport;
return true;
return update_ipv4_addresses_and_ports(fdinfo, tsip, tsport, tdip, tdport);
}
bool sinsp_parser::set_ipv6_addresses_and_ports(sinsp_fdinfo_t* fdinfo, uint8_t* packed_data)
@ -3284,12 +3408,29 @@ bool sinsp_parser::set_ipv6_addresses_and_ports(sinsp_fdinfo_t* fdinfo, uint8_t*
}
}
fdinfo->m_sockinfo.m_ipv6info.m_fields.m_sip = tsip;
fdinfo->m_sockinfo.m_ipv6info.m_fields.m_sport = tsport;
fdinfo->m_sockinfo.m_ipv6info.m_fields.m_dip = tdip;
fdinfo->m_sockinfo.m_ipv6info.m_fields.m_dport = tdport;
bool changed = false;
return true;
if(fdinfo->m_sockinfo.m_ipv6info.m_fields.m_sip != tsip) {
fdinfo->m_sockinfo.m_ipv6info.m_fields.m_sip = tsip;
changed = true;
}
if(fdinfo->m_sockinfo.m_ipv6info.m_fields.m_sport != tsport) {
fdinfo->m_sockinfo.m_ipv6info.m_fields.m_sport = tsport;
changed = true;
}
if(fdinfo->m_sockinfo.m_ipv6info.m_fields.m_dip == ipv6addr::empty_address) {
fdinfo->m_sockinfo.m_ipv6info.m_fields.m_dip = tdip;
changed = true;
}
if(fdinfo->m_sockinfo.m_ipv6info.m_fields.m_dport == 0) {
fdinfo->m_sockinfo.m_ipv6info.m_fields.m_dport = tdport;
changed = true;
}
return changed;
}
bool sinsp_parser::set_unix_info(sinsp_fdinfo_t* fdinfo, uint8_t* packed_data)

View File

@ -145,6 +145,8 @@ private:
void parse_setsid_exit(sinsp_evt *evt);
void parse_getsockopt_exit(sinsp_evt *evt);
inline bool update_ipv4_addresses_and_ports(sinsp_fdinfo_t* fdinfo,
uint32_t tsip, uint16_t tsport, uint32_t tdip, uint16_t tdport);
inline void fill_client_socket_info(sinsp_evt* evt, uint8_t* packed_data);
inline void add_socket(sinsp_evt* evt, int64_t fd, uint32_t domain, uint32_t type, uint32_t protocol);
inline void infer_sendto_fdinfo(sinsp_evt *evt);

View File

@ -336,9 +336,9 @@ std::shared_ptr<sinsp_plugin> sinsp_plugin::create_plugin(string &filepath, cons
std::shared_ptr<sinsp_plugin> ret;
#ifdef _WIN32
HINSTANCE handle = LoadLibrary(filepath.c_str());
sinsp_plugin_handle handle = LoadLibrary(filepath.c_str());
#else
void* handle = dlopen(filepath.c_str(), RTLD_LAZY);
sinsp_plugin_handle handle = dlopen(filepath.c_str(), RTLD_LAZY);
#endif
if(handle == NULL)
{
@ -392,8 +392,8 @@ std::shared_ptr<sinsp_plugin> sinsp_plugin::create_plugin(string &filepath, cons
switch(plugin_type)
{
case TYPE_SOURCE_PLUGIN:
splugin = new sinsp_source_plugin();
if(!splugin->resolve_dylib_symbols(handle, errstr))
splugin = new sinsp_source_plugin(handle);
if(!splugin->resolve_dylib_symbols(errstr))
{
delete splugin;
return ret;
@ -401,14 +401,18 @@ std::shared_ptr<sinsp_plugin> sinsp_plugin::create_plugin(string &filepath, cons
ret.reset(splugin);
break;
case TYPE_EXTRACTOR_PLUGIN:
eplugin = new sinsp_extractor_plugin();
if(!eplugin->resolve_dylib_symbols(handle, errstr))
eplugin = new sinsp_extractor_plugin(handle);
if(!eplugin->resolve_dylib_symbols(errstr))
{
delete eplugin;
return ret;
}
ret.reset(eplugin);
break;
default:
errstr = string("Wrong plugin type.");
destroy_handle(handle);
return ret;
}
errstr = "";
@ -449,13 +453,39 @@ std::list<sinsp_plugin::info> sinsp_plugin::plugin_infos(sinsp* inspector)
return ret;
}
sinsp_plugin::sinsp_plugin()
: m_nfields(0)
bool sinsp_plugin::is_plugin_loaded(std::string &filepath)
{
#ifdef _WIN32
/*
* LoadLibrary maps the module into the address space of the calling process, if necessary,
* and increments the modules reference count, if it is already mapped.
* GetModuleHandle, however, returns the handle to a mapped module
* without incrementing its reference count.
*
* This returns an HMODULE indeed, but they are the same thing
*/
sinsp_plugin_handle handle = (HINSTANCE)GetModuleHandle(filepath.c_str());
#else
/*
* RTLD_NOLOAD (since glibc 2.2)
* Don't load the shared object. This can be used to test if
* the object is already resident (dlopen() returns NULL if
* it is not, or the object's handle if it is resident).
* This does not increment dlobject reference count.
*/
sinsp_plugin_handle handle = dlopen(filepath.c_str(), RTLD_LAZY | RTLD_NOLOAD);
#endif
return handle != NULL;
}
sinsp_plugin::sinsp_plugin(sinsp_plugin_handle handle)
: m_handle(handle), m_nfields(0)
{
}
sinsp_plugin::~sinsp_plugin()
{
destroy_handle(m_handle);
}
bool sinsp_plugin::init(const char *config)
@ -582,12 +612,12 @@ bool sinsp_plugin::extract_field(ss_plugin_event &evt, sinsp_plugin::ext_field &
return true;
}
void* sinsp_plugin::getsym(void* handle, const char* name, std::string &errstr)
void* sinsp_plugin::getsym(sinsp_plugin_handle handle, const char* name, std::string &errstr)
{
void *ret;
#ifdef _WIN32
ret = GetProcAddress((HINSTANCE)handle, name);
ret = GetProcAddress(handle, name);
#else
ret = dlsym(handle, name);
#endif
@ -615,25 +645,25 @@ std::string sinsp_plugin::str_from_alloc_charbuf(const char* charbuf)
return str;
}
bool sinsp_plugin::resolve_dylib_symbols(void *handle, std::string &errstr)
bool sinsp_plugin::resolve_dylib_symbols(std::string &errstr)
{
// Some functions are required and return false if not found.
if((*(void **) (&(m_plugin_info.get_required_api_version)) = getsym(handle, "plugin_get_required_api_version", errstr)) == NULL ||
(*(void **) (&(m_plugin_info.get_last_error)) = getsym(handle, "plugin_get_last_error", errstr)) == NULL ||
(*(void **) (&(m_plugin_info.get_name)) = getsym(handle, "plugin_get_name", errstr)) == NULL ||
(*(void **) (&(m_plugin_info.get_description)) = getsym(handle, "plugin_get_description", errstr)) == NULL ||
(*(void **) (&(m_plugin_info.get_contact)) = getsym(handle, "plugin_get_contact", errstr)) == NULL ||
(*(void **) (&(m_plugin_info.get_version)) = getsym(handle, "plugin_get_version", errstr)) == NULL)
if((*(void **) (&(m_plugin_info.get_required_api_version)) = getsym(m_handle, "plugin_get_required_api_version", errstr)) == NULL ||
(*(void **) (&(m_plugin_info.get_last_error)) = getsym(m_handle, "plugin_get_last_error", errstr)) == NULL ||
(*(void **) (&(m_plugin_info.get_name)) = getsym(m_handle, "plugin_get_name", errstr)) == NULL ||
(*(void **) (&(m_plugin_info.get_description)) = getsym(m_handle, "plugin_get_description", errstr)) == NULL ||
(*(void **) (&(m_plugin_info.get_contact)) = getsym(m_handle, "plugin_get_contact", errstr)) == NULL ||
(*(void **) (&(m_plugin_info.get_version)) = getsym(m_handle, "plugin_get_version", errstr)) == NULL)
{
return false;
}
// Others are not and the values will be checked when needed.
(*(void **) (&m_plugin_info.init)) = getsym(handle, "plugin_init", errstr);
(*(void **) (&m_plugin_info.destroy)) = getsym(handle, "plugin_destroy", errstr);
(*(void **) (&m_plugin_info.get_fields)) = getsym(handle, "plugin_get_fields", errstr);
(*(void **) (&m_plugin_info.extract_fields)) = getsym(handle, "plugin_extract_fields", errstr);
(*(void **) (&m_plugin_info.get_init_schema)) = getsym(handle, "plugin_get_init_schema", errstr);
(*(void **) (&m_plugin_info.init)) = getsym(m_handle, "plugin_init", errstr);
(*(void **) (&m_plugin_info.destroy)) = getsym(m_handle, "plugin_destroy", errstr);
(*(void **) (&m_plugin_info.get_fields)) = getsym(m_handle, "plugin_get_fields", errstr);
(*(void **) (&m_plugin_info.extract_fields)) = getsym(m_handle, "plugin_extract_fields", errstr);
(*(void **) (&m_plugin_info.get_init_schema)) = getsym(m_handle, "plugin_get_init_schema", errstr);
m_name = str_from_alloc_charbuf(m_plugin_info.get_name());
m_description = str_from_alloc_charbuf(m_plugin_info.get_description());
@ -697,6 +727,8 @@ bool sinsp_plugin::resolve_dylib_symbols(void *handle, std::string &errstr)
{
throw sinsp_exception(string("error in plugin ") + m_name + ": field JSON entry has no name");
}
const Json::Value &jvdisplay = root[j]["display"];
string fdisplay = jvdisplay.asString();
const Json::Value &jvdesc = root[j]["desc"];
string fdesc = jvdesc.asString();
if(fdesc == "")
@ -705,6 +737,7 @@ bool sinsp_plugin::resolve_dylib_symbols(void *handle, std::string &errstr)
}
strlcpy(tf.m_name, fname.c_str(), sizeof(tf.m_name));
strlcpy(tf.m_display, fdisplay.c_str(), sizeof(tf.m_display));
strlcpy(tf.m_description, fdesc.c_str(), sizeof(tf.m_description));
tf.m_print_format = PF_DEC;
if(ftype == "string")
@ -763,12 +796,19 @@ bool sinsp_plugin::resolve_dylib_symbols(void *handle, std::string &errstr)
const std::string &str = prop.asString();
// There might be other properties (e.g. "conversation" and "info", which are used by wireshark),
// but the only one that is relevant to libs is "hidden".
// "hidden" is used inside and outside libs. "info" and "conversation" are used outside libs.
if(str == "hidden")
{
tf.m_flags = (filtercheck_field_flags) ((int) tf.m_flags | (int) filtercheck_field_flags::EPF_TABLE_ONLY);
}
else if(str == "info")
{
tf.m_flags = (filtercheck_field_flags) ((int) tf.m_flags | (int) filtercheck_field_flags::EPF_INFO);
}
else if(str == "conversation")
{
tf.m_flags = (filtercheck_field_flags) ((int) tf.m_flags | (int) filtercheck_field_flags::EPF_CONVERSATION);
}
}
}
}
@ -866,7 +906,16 @@ void sinsp_plugin::validate_init_config_json_schema(std::string config, std::str
}
}
sinsp_source_plugin::sinsp_source_plugin()
void sinsp_plugin::destroy_handle(sinsp_plugin_handle handle) {
#ifdef _WIN32
FreeLibrary(handle);
#else
dlclose(handle);
#endif
}
sinsp_source_plugin::sinsp_source_plugin(sinsp_plugin_handle handle) :
sinsp_plugin(handle)
{
memset(&m_source_plugin_info, 0, sizeof(m_source_plugin_info));
}
@ -997,9 +1046,9 @@ ss_plugin_t *sinsp_source_plugin::plugin_state()
return m_source_plugin_info.state;
}
bool sinsp_source_plugin::resolve_dylib_symbols(void *handle, std::string &errstr)
bool sinsp_source_plugin::resolve_dylib_symbols(std::string &errstr)
{
if (!sinsp_plugin::resolve_dylib_symbols(handle, errstr))
if (!sinsp_plugin::resolve_dylib_symbols(errstr))
{
return false;
}
@ -1010,32 +1059,32 @@ bool sinsp_source_plugin::resolve_dylib_symbols(void *handle, std::string &errst
// down to libscap when reading/writing capture files).
//
// Some functions are required and return false if not found.
if((*(void **) (&(m_source_plugin_info.get_required_api_version)) = getsym(handle, "plugin_get_required_api_version", errstr)) == NULL ||
(*(void **) (&(m_source_plugin_info.init)) = getsym(handle, "plugin_init", errstr)) == NULL ||
(*(void **) (&(m_source_plugin_info.destroy)) = getsym(handle, "plugin_destroy", errstr)) == NULL ||
(*(void **) (&(m_source_plugin_info.get_last_error)) = getsym(handle, "plugin_get_last_error", errstr)) == NULL ||
(*(void **) (&(m_source_plugin_info.get_type)) = getsym(handle, "plugin_get_type", errstr)) == NULL ||
(*(void **) (&(m_source_plugin_info.get_id)) = getsym(handle, "plugin_get_id", errstr)) == NULL ||
(*(void **) (&(m_source_plugin_info.get_name)) = getsym(handle, "plugin_get_name", errstr)) == NULL ||
(*(void **) (&(m_source_plugin_info.get_description)) = getsym(handle, "plugin_get_description", errstr)) == NULL ||
(*(void **) (&(m_source_plugin_info.get_contact)) = getsym(handle, "plugin_get_contact", errstr)) == NULL ||
(*(void **) (&(m_source_plugin_info.get_version)) = getsym(handle, "plugin_get_version", errstr)) == NULL ||
(*(void **) (&(m_source_plugin_info.get_event_source)) = getsym(handle, "plugin_get_event_source", errstr)) == NULL ||
(*(void **) (&(m_source_plugin_info.open)) = getsym(handle, "plugin_open", errstr)) == NULL ||
(*(void **) (&(m_source_plugin_info.close)) = getsym(handle, "plugin_close", errstr)) == NULL ||
(*(void **) (&(m_source_plugin_info.next_batch)) = getsym(handle, "plugin_next_batch", errstr)) == NULL ||
(*(void **) (&(m_source_plugin_info.event_to_string)) = getsym(handle, "plugin_event_to_string", errstr)) == NULL)
if((*(void **) (&(m_source_plugin_info.get_required_api_version)) = getsym(m_handle, "plugin_get_required_api_version", errstr)) == NULL ||
(*(void **) (&(m_source_plugin_info.init)) = getsym(m_handle, "plugin_init", errstr)) == NULL ||
(*(void **) (&(m_source_plugin_info.destroy)) = getsym(m_handle, "plugin_destroy", errstr)) == NULL ||
(*(void **) (&(m_source_plugin_info.get_last_error)) = getsym(m_handle, "plugin_get_last_error", errstr)) == NULL ||
(*(void **) (&(m_source_plugin_info.get_type)) = getsym(m_handle, "plugin_get_type", errstr)) == NULL ||
(*(void **) (&(m_source_plugin_info.get_id)) = getsym(m_handle, "plugin_get_id", errstr)) == NULL ||
(*(void **) (&(m_source_plugin_info.get_name)) = getsym(m_handle, "plugin_get_name", errstr)) == NULL ||
(*(void **) (&(m_source_plugin_info.get_description)) = getsym(m_handle, "plugin_get_description", errstr)) == NULL ||
(*(void **) (&(m_source_plugin_info.get_contact)) = getsym(m_handle, "plugin_get_contact", errstr)) == NULL ||
(*(void **) (&(m_source_plugin_info.get_version)) = getsym(m_handle, "plugin_get_version", errstr)) == NULL ||
(*(void **) (&(m_source_plugin_info.get_event_source)) = getsym(m_handle, "plugin_get_event_source", errstr)) == NULL ||
(*(void **) (&(m_source_plugin_info.open)) = getsym(m_handle, "plugin_open", errstr)) == NULL ||
(*(void **) (&(m_source_plugin_info.close)) = getsym(m_handle, "plugin_close", errstr)) == NULL ||
(*(void **) (&(m_source_plugin_info.next_batch)) = getsym(m_handle, "plugin_next_batch", errstr)) == NULL ||
(*(void **) (&(m_source_plugin_info.event_to_string)) = getsym(m_handle, "plugin_event_to_string", errstr)) == NULL)
{
return false;
}
// Others are not.
(*(void **) (&m_source_plugin_info.get_fields)) = getsym(handle, "plugin_get_fields", errstr);
(*(void **) (&m_source_plugin_info.get_progress)) = getsym(handle, "plugin_get_progress", errstr);
(*(void **) (&m_source_plugin_info.event_to_string)) = getsym(handle, "plugin_event_to_string", errstr);
(*(void **) (&m_source_plugin_info.extract_fields)) = getsym(handle, "plugin_extract_fields", errstr);
(*(void **) (&m_source_plugin_info.list_open_params)) = getsym(handle, "plugin_list_open_params", errstr);
(*(void **) (&m_source_plugin_info.get_init_schema)) = getsym(handle, "plugin_get_init_schema", errstr);
(*(void **) (&m_source_plugin_info.get_fields)) = getsym(m_handle, "plugin_get_fields", errstr);
(*(void **) (&m_source_plugin_info.get_progress)) = getsym(m_handle, "plugin_get_progress", errstr);
(*(void **) (&m_source_plugin_info.event_to_string)) = getsym(m_handle, "plugin_event_to_string", errstr);
(*(void **) (&m_source_plugin_info.extract_fields)) = getsym(m_handle, "plugin_extract_fields", errstr);
(*(void **) (&m_source_plugin_info.list_open_params)) = getsym(m_handle, "plugin_list_open_params", errstr);
(*(void **) (&m_source_plugin_info.get_init_schema)) = getsym(m_handle, "plugin_get_init_schema", errstr);
m_id = m_source_plugin_info.get_id();
m_event_source = str_from_alloc_charbuf(m_source_plugin_info.get_event_source());
@ -1043,7 +1092,8 @@ bool sinsp_source_plugin::resolve_dylib_symbols(void *handle, std::string &errst
return true;
}
sinsp_extractor_plugin::sinsp_extractor_plugin()
sinsp_extractor_plugin::sinsp_extractor_plugin(sinsp_plugin_handle handle) :
sinsp_plugin(handle)
{
memset(&m_extractor_plugin_info, 0, sizeof(m_extractor_plugin_info));
}
@ -1074,9 +1124,9 @@ ss_plugin_t *sinsp_extractor_plugin::plugin_state()
return m_extractor_plugin_info.state;
}
bool sinsp_extractor_plugin::resolve_dylib_symbols(void *handle, std::string &errstr)
bool sinsp_extractor_plugin::resolve_dylib_symbols(std::string &errstr)
{
if (!sinsp_plugin::resolve_dylib_symbols(handle, errstr))
if (!sinsp_plugin::resolve_dylib_symbols(errstr))
{
return false;
}
@ -1087,24 +1137,24 @@ bool sinsp_extractor_plugin::resolve_dylib_symbols(void *handle, std::string &er
// down to libscap when reading/writing capture files).
//
// Some functions are required and return false if not found.
if((*(void **) (&(m_extractor_plugin_info.get_required_api_version)) = getsym(handle, "plugin_get_required_api_version", errstr)) == NULL ||
(*(void **) (&(m_extractor_plugin_info.init)) = getsym(handle, "plugin_init", errstr)) == NULL ||
(*(void **) (&(m_extractor_plugin_info.destroy)) = getsym(handle, "plugin_destroy", errstr)) == NULL ||
(*(void **) (&(m_extractor_plugin_info.get_last_error)) = getsym(handle, "plugin_get_last_error", errstr)) == NULL ||
(*(void **) (&(m_extractor_plugin_info.get_type)) = getsym(handle, "plugin_get_type", errstr)) == NULL ||
(*(void **) (&(m_extractor_plugin_info.get_name)) = getsym(handle, "plugin_get_name", errstr)) == NULL ||
(*(void **) (&(m_extractor_plugin_info.get_description)) = getsym(handle, "plugin_get_description", errstr)) == NULL ||
(*(void **) (&(m_extractor_plugin_info.get_contact)) = getsym(handle, "plugin_get_contact", errstr)) == NULL ||
(*(void **) (&(m_extractor_plugin_info.get_version)) = getsym(handle, "plugin_get_version", errstr)) == NULL ||
(*(void **) (&(m_extractor_plugin_info.get_fields)) = getsym(handle, "plugin_get_fields", errstr)) == NULL ||
(*(void **) (&(m_extractor_plugin_info.extract_fields)) = getsym(handle, "plugin_extract_fields", errstr)) == NULL)
if((*(void **) (&(m_extractor_plugin_info.get_required_api_version)) = getsym(m_handle, "plugin_get_required_api_version", errstr)) == NULL ||
(*(void **) (&(m_extractor_plugin_info.init)) = getsym(m_handle, "plugin_init", errstr)) == NULL ||
(*(void **) (&(m_extractor_plugin_info.destroy)) = getsym(m_handle, "plugin_destroy", errstr)) == NULL ||
(*(void **) (&(m_extractor_plugin_info.get_last_error)) = getsym(m_handle, "plugin_get_last_error", errstr)) == NULL ||
(*(void **) (&(m_extractor_plugin_info.get_type)) = getsym(m_handle, "plugin_get_type", errstr)) == NULL ||
(*(void **) (&(m_extractor_plugin_info.get_name)) = getsym(m_handle, "plugin_get_name", errstr)) == NULL ||
(*(void **) (&(m_extractor_plugin_info.get_description)) = getsym(m_handle, "plugin_get_description", errstr)) == NULL ||
(*(void **) (&(m_extractor_plugin_info.get_contact)) = getsym(m_handle, "plugin_get_contact", errstr)) == NULL ||
(*(void **) (&(m_extractor_plugin_info.get_version)) = getsym(m_handle, "plugin_get_version", errstr)) == NULL ||
(*(void **) (&(m_extractor_plugin_info.get_fields)) = getsym(m_handle, "plugin_get_fields", errstr)) == NULL ||
(*(void **) (&(m_extractor_plugin_info.extract_fields)) = getsym(m_handle, "plugin_extract_fields", errstr)) == NULL)
{
return false;
}
// Others are not.
(*(void **) (&m_extractor_plugin_info.get_extract_event_sources)) = getsym(handle, "plugin_get_extract_event_sources", errstr);
(*(void **) (&m_extractor_plugin_info.get_init_schema)) = getsym(handle, "plugin_get_init_schema", errstr);
(*(void **) (&m_extractor_plugin_info.get_extract_event_sources)) = getsym(m_handle, "plugin_get_extract_event_sources", errstr);
(*(void **) (&m_extractor_plugin_info.get_init_schema)) = getsym(m_handle, "plugin_get_init_schema", errstr);
if (m_extractor_plugin_info.get_extract_event_sources != NULL)

View File

@ -28,6 +28,13 @@ limitations under the License.
#include "filter_check_list.h"
#ifdef _WIN32
typedef HINSTANCE sinsp_plugin_handle;
#else
typedef void* sinsp_plugin_handle;
#endif
class sinsp_filter_check_plugin;
// Base class for source/extractor plugins. Can not be created directly.
@ -94,14 +101,17 @@ public:
// Return a string with names/descriptions/etc of all plugins used by this inspector
static std::list<sinsp_plugin::info> plugin_infos(sinsp *inspector);
sinsp_plugin();
// Return whether a filesystem object is loaded
static bool is_plugin_loaded(std::string &filepath);
sinsp_plugin(sinsp_plugin_handle handle);
virtual ~sinsp_plugin();
// Given a dynamic library handle, fill in common properties
// (name/desc/etc) and required functions
// (init/destroy/extract/etc).
// Returns true on success, false + sets errstr on error.
virtual bool resolve_dylib_symbols(void *handle, std::string &errstr);
virtual bool resolve_dylib_symbols(std::string &errstr);
bool init(const char* config);
void destroy();
@ -123,9 +133,11 @@ public:
std::string get_init_schema(ss_plugin_schema_type& schema_type);
void validate_init_config(const char* config);
sinsp_plugin_handle m_handle;
protected:
// Helper function to resolve symbols
static void* getsym(void* handle, const char* name, std::string &errstr);
static void* getsym(sinsp_plugin_handle handle, const char* name, std::string &errstr);
// Helper function to set a string from an allocated charbuf and free the charbuf.
std::string str_from_alloc_charbuf(const char* charbuf);
@ -165,6 +177,8 @@ private:
common_plugin_info m_plugin_info;
void validate_init_config_json_schema(std::string config, std::string &schema);
static void destroy_handle(sinsp_plugin_handle handle);
};
// Note that this doesn't have a next_batch() method, as event generation is
@ -178,10 +192,10 @@ public:
std::string desc;
};
sinsp_source_plugin();
sinsp_source_plugin(sinsp_plugin_handle handle);
virtual ~sinsp_source_plugin();
bool resolve_dylib_symbols(void *handle, std::string &errstr) override;
bool resolve_dylib_symbols(std::string &errstr) override;
ss_plugin_type type() override { return TYPE_SOURCE_PLUGIN; };
uint32_t id();
@ -214,10 +228,10 @@ private:
class sinsp_extractor_plugin : public sinsp_plugin
{
public:
sinsp_extractor_plugin();
sinsp_extractor_plugin(sinsp_plugin_handle handle);
virtual ~sinsp_extractor_plugin();
bool resolve_dylib_symbols(void *handle, std::string &errstr) override;
bool resolve_dylib_symbols(std::string &errstr) override;
ss_plugin_type type() override { return TYPE_EXTRACTOR_PLUGIN; };

View File

@ -0,0 +1,65 @@
/*
Copyright (C) 2021 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "procfs_utils.h"
#include <string>
#include "sinsp.h"
int libsinsp::procfs_utils::get_userns_root_uid(std::istream& uid_map)
{
std::string uid_map_line;
while(std::getline(uid_map, uid_map_line))
{
int src_uid, target_uid;
std::stringstream mapping(uid_map_line);
mapping >> src_uid;
// if the target uid we're looking for was anything other than 0,
// we'd have to check the length of the range as well, but since
// 0 is the lowest, we're good
if(src_uid != 0)
{
continue;
}
mapping >> target_uid;
return target_uid;
}
return libsinsp::procfs_utils::NO_MATCH;
}
std::string libsinsp::procfs_utils::get_systemd_cgroup(std::istream& cgroups)
{
std::string cgroups_line;
while(std::getline(cgroups, cgroups_line))
{
size_t cgpos = cgroups_line.find(":name=systemd:");
if(cgpos == std::string::npos)
{
continue;
}
std::string systemd_cgroup = cgroups_line.substr(cgpos + strlen(":name=systemd:"), std::string::npos);
return systemd_cgroup;
}
return "";
}

View File

@ -0,0 +1,31 @@
#pragma once
#include <istream>
#include <string>
namespace libsinsp {
namespace procfs_utils {
constexpr const int NO_MATCH = -1;
/**
* @brief Parse /proc/<pid>/uid_map to find the uid that root in the userns maps to
* @param uid_map a stream with the contents of /proc/<pid>/uid_map
* @return the uid of the userns owner
*
* For unprivileged Podman containers at least, all processes are created
* in a child user namespace which maps uids inside the container to uids
* outside. The root user in the container is mapped to the uid that created
* the container (in the parent user namespace)
*/
int get_userns_root_uid(std::istream& uid_map);
/**
* @brief Get the path of the `name=systemd` cgroup
* @param cgroups a stream with the contents of /proc/<pid>/cgroup
* @return the path of the `name=systemd` cgroup
*/
std::string get_systemd_cgroup(std::istream& cgroups);
}
}

View File

@ -30,6 +30,11 @@ const char* CONTAINER_ID_VALID_CHARACTERS = "0123456789abcdefABCDEF";
static_assert(REPORTED_CONTAINER_ID_LENGTH <= CONTAINER_ID_LENGTH, "Reported container ID length cannot be longer than actual length");
}
namespace libsinsp {
namespace runc {
// check if cgroup ends with <prefix><container_id><suffix>
// If true, set <container_id> to a truncated version of the id and return true.
// Otherwise return false and leave container_id unchanged
@ -76,17 +81,13 @@ bool match_container_id(const std::string &cgroup, const libsinsp::runc::cgroup_
return false;
}
}
namespace libsinsp {
namespace runc {
bool matches_runc_cgroups(const sinsp_threadinfo *tinfo, const cgroup_layout *layout, std::string &container_id)
bool matches_runc_cgroups(const sinsp_threadinfo *tinfo, const cgroup_layout *layout, std::string &container_id, std::string &matching_cgroup)
{
for(const auto &it : tinfo->m_cgroups)
{
if(match_container_id(it.second, layout, container_id))
{
matching_cgroup = it.second;
return true;
}
}

View File

@ -24,22 +24,61 @@ class sinsp_threadinfo;
namespace libsinsp {
namespace runc {
/// runc-based runtimes (Docker, containerd, CRI-O, probably others) use the same two cgroup layouts
/// with slight variations:
/// - non-systemd layout uses cgroups ending with .../<prefix><container id>
/// - systemd layout uses .../<prefix><container id>.scope
/// where <container id> is always 64 hex digits (we report the first 12 as the container id).
/// For non-systemd only CRI-O seems to use /crio-<container id>, while for systemd layout
/// while all known container engines use a prefix like "docker-", "crio-" or "containerd-cri-".
/// We can encode all these variants with a simple list of (prefix, suffix) pairs
/// (the last one must be a pair of null pointers to mark the end of the array)
/**
* @brief A pattern to match cgroup paths against
*
* runc-based runtimes (Docker, containerd, CRI-O, probably others) use the same two cgroup layouts
* with slight variations:
* - non-systemd layout uses cgroups ending with .../<prefix><container id>
* - systemd layout uses .../<prefix><container id>.scope
* where <container id> is always 64 hex digits (we report the first 12 as the container id).
* For non-systemd only CRI-O seems to use /crio-<container id>, while for systemd layout
* while all known container engines use a prefix like "docker-", "crio-" or "containerd-cri-".
* We can encode all these variants with a simple list of (prefix, suffix) pairs
* (the last one must be a pair of null pointers to mark the end of the array)
*/
struct cgroup_layout {
const char* prefix;
const char* suffix;
};
/// If any of the cgroups of the thread in `tinfo` matches the `layout`, set `container_id` to the found id
/// and return true. Otherwise, return false and leave `container_id` unchanged
bool matches_runc_cgroups(const sinsp_threadinfo *tinfo, const cgroup_layout *layout, std::string &container_id);
/**
* @brief Check if `cgroup` ends with <prefix><64_hex_digits><suffix>
* @param container_id output parameter
* @return true if `cgroup` matches the pattern
*
* If this function returns true, `container_id` will be set to
* the truncated hex string (first 12 digits). Otherwise, it will remain
* unchanged.
*/
bool match_one_container_id(const std::string &cgroup, const std::string &prefix, const std::string &suffix, std::string &container_id);
/**
* @brief Match `cgroup` against a list of layouts using `match_one_container_id()`
* @param layout an array of (prefix, suffix) pairs
* @param container_id output parameter
* @return true if `cgroup` matches any of the patterns
*
* `layout` is an array terminated by an empty entry (prefix, suffix both empty)
*
* If this function returns true, `container_id` will be set to
* the truncated hex string (first 12 digits). Otherwise, it will remain
* unchanged.
*/
bool match_container_id(const std::string &cgroup, const libsinsp::runc::cgroup_layout *layout,
std::string &container_id);
/**
* @brief Match all the cgroups of `tinfo` against a list of cgroup layouts
* @param layout an array of (prefix, suffix) pairs
* @param container_id output parameter
* @param matching_cgroup output parameter
* @return true if any of `tinfo`'s cgroups match any of the patterns
*
* If this function returns true, `container_id` will be set to
* the truncated hex string (first 12 digits). Otherwise, it will remain
* unchanged.
*/
bool matches_runc_cgroups(const sinsp_threadinfo *tinfo, const cgroup_layout *layout, std::string &container_id, std::string &matching_cgroup);
}
}

View File

@ -92,7 +92,6 @@ sinsp::sinsp(bool static_container, const std::string static_id, const std::stri
#ifdef HAS_FILTERING
m_filter = NULL;
m_evttype_filter = NULL;
#endif
m_fds_to_remove = new vector<int64_t>;
@ -798,11 +797,6 @@ void sinsp::close()
m_filter = NULL;
}
if(m_evttype_filter != NULL)
{
delete m_evttype_filter;
m_evttype_filter = NULL;
}
#endif
m_ppm_sc_of_interest.clear();
@ -1314,11 +1308,13 @@ int32_t sinsp::next(OUT sinsp_evt **puevt)
"n_evts:%" PRIu64
" n_drops:%" PRIu64
" n_drops_buffer:%" PRIu64
" n_drops_scratch_map:%" PRIu64
" n_drops_pf:%" PRIu64
" n_drops_bug:%" PRIu64,
stats.n_evts,
stats.n_drops,
stats.n_drops_buffer,
stats.n_drops_scratch_map,
stats.n_drops_pf,
stats.n_drops_bug);
}
@ -1582,6 +1578,11 @@ void sinsp::set_cri_socket_path(const std::string& path)
m_container_manager.set_cri_socket_path(path);
}
void sinsp::add_cri_socket_path(const std::string& path)
{
m_container_manager.add_cri_socket_path(path);
}
void sinsp::set_cri_timeout(int64_t timeout_ms)
{
m_container_manager.set_cri_timeout(timeout_ms);
@ -1834,21 +1835,6 @@ const string sinsp::get_filter()
return m_filterstring;
}
void sinsp::add_evttype_filter(string &name,
set<uint32_t> &evttypes,
set<uint32_t> &syscalls,
set<string> &tags,
sinsp_filter *filter)
{
// Create the evttype filter if it doesn't exist.
if(m_evttype_filter == NULL)
{
m_evttype_filter = new sinsp_evttype_filter();
}
m_evttype_filter->add(name, evttypes, syscalls, tags, filter);
}
bool sinsp::run_filters_on_evt(sinsp_evt *evt)
{
//
@ -1859,13 +1845,6 @@ bool sinsp::run_filters_on_evt(sinsp_evt *evt)
return true;
}
//
// Then run the evttype filter, if there is one.
if(m_evttype_filter && m_evttype_filter->run(evt) == true)
{
return true;
}
return false;
}
#endif
@ -2341,6 +2320,37 @@ void sinsp::init_k8s_client(string* api_server, string* ssl_cert, string* node_n
}
}
void sinsp::validate_k8s_node_name()
{
if(!m_k8s_node_name || m_k8s_node_name->size() == 0)
{
g_logger.log("No k8s node name passed as argument. "
"This may result in performance penalty on large clusters", sinsp_logger::SEV_WARNING);
}
else
{
bool found = false;
const auto& state = m_k8s_client->get_state();
for(const auto& node : state.get_nodes())
{
if(!node.get_node_name().compare(*m_k8s_node_name))
{
found = true;
break;
}
}
if(!found)
{
throw sinsp_exception("Failing to enrich events with Kubernetes metadata:"
"node name does not correspond to a node in the cluster");
}
}
m_k8s_node_name_validated = true;
}
void sinsp::collect_k8s()
{
if(m_parser)
@ -2372,6 +2382,11 @@ void sinsp::collect_k8s()
delta = sinsp_utils::get_current_time_ns() - delta;
g_logger.format(sinsp_logger::SEV_DEBUG, "Updating Kubernetes state took %" PRIu64 " ms", delta / 1000000LL);
}
if(!m_k8s_node_name_validated)
{
validate_k8s_node_name();
}
}
}
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2021 The Falco Authors.
Copyright (C) 2022 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -366,12 +366,6 @@ public:
*/
const string get_filter();
void add_evttype_filter(std::string &name,
std::set<uint32_t> &evttypes,
std::set<uint32_t> &syscalls,
std::set<std::string> &tags,
sinsp_filter* filter);
bool run_filters_on_evt(sinsp_evt *evt);
#endif
@ -655,6 +649,38 @@ public:
return PLUGIN_API_VERSION_STR;
}
/*!
\brief Returns the API version supported by the driver
*/
inline uint64_t get_driver_api_version() const
{
return scap_get_driver_api_version(m_h);
}
/*!
\brief Returns the minimum API version required by the userspace library
*/
inline uint64_t get_scap_api_version() const
{
return SCAP_MINIMUM_DRIVER_API_VERSION;
}
/*!
\brief Returns the schema version supported by the driver
*/
inline uint64_t get_driver_schema_version() const
{
return scap_get_driver_schema_version(m_h);
}
/*!
\brief Returns the minimum schema version required by the userspace library
*/
inline uint64_t get_scap_schema_version() const
{
return SCAP_MINIMUM_DRIVER_SCHEMA_VERSION;
}
/*!
\brief Returns true if truncated environments should be loaded from /proc
*/
@ -855,6 +881,7 @@ public:
void init_k8s_client(std::string* api_server, std::string* ssl_cert, std::string *node_name, bool verbose = false);
void make_k8s_client();
k8s* get_k8s_client() const { return m_k8s_client; }
void validate_k8s_node_name();
void init_mesos_client(std::string* api_server, bool verbose = false);
mesos* get_mesos_client() const { return m_mesos_client; }
@ -960,7 +987,14 @@ public:
void set_statsd_port(uint16_t port);
/*!
\brief Reset list of crio socket paths currently stored, and set path as the only path.
*/
void set_cri_socket_path(const std::string& path);
/*!
\brief Pushed a new path to the list of crio socket paths
*/
void add_cri_socket_path(const std::string &path);
void set_cri_timeout(int64_t timeout_ms);
void set_cri_async(bool async);
void set_cri_delay(uint64_t delay_ms);
@ -1109,6 +1143,7 @@ public:
std::string* m_k8s_api_server;
std::string* m_k8s_api_cert;
std::string* m_k8s_node_name;
bool m_k8s_node_name_validated = false;
#ifdef HAS_CAPTURE
std::shared_ptr<sinsp_ssl> m_k8s_ssl;
std::shared_ptr<sinsp_bearer_token> m_k8s_bt;
@ -1146,7 +1181,6 @@ public:
#ifdef HAS_FILTERING
uint64_t m_firstevent_ts;
sinsp_filter* m_filter;
sinsp_evttype_filter *m_evttype_filter;
std::string m_filterstring;
#endif
unordered_set<uint32_t> m_ppm_sc_of_interest;

View File

@ -22,15 +22,22 @@ if(NOT MINIMAL_BUILD)
endif() # MINIMAL_BUILD
include_directories("..")
include_directories(${LIBSCAP_INCLUDE_DIR})
include_directories(${LIBSCAP_INCLUDE_DIR} ${LIBSCAP_DIR}/driver)
add_executable(unit-test-libsinsp
set(LIBSINSP_UNIT_TESTS_SOURCES
cgroup_list_counter.ut.cpp
sinsp.ut.cpp
evttype_filter.ut.cpp
token_bucket.ut.cpp
ppm_api_version.ut.cpp
)
if(NOT MINIMAL_BUILD)
list(APPEND LIBSINSP_UNIT_TESTS_SOURCES procfs_utils.ut.cpp)
endif()
add_executable(unit-test-libsinsp ${LIBSINSP_UNIT_TESTS_SOURCES})
target_link_libraries(unit-test-libsinsp
"${GTEST_LIB}"
"${GTEST_MAIN_LIB}"

View File

@ -27,5 +27,6 @@ ExternalProject_Add(googletest
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
UPDATE_COMMAND ""
TEST_COMMAND ""
)

View File

@ -91,8 +91,8 @@ protected:
FAIL() << "Expected event type "
<< etype
<< " not found in actual set. "
<< "Expected: " << expected << " "
<< " Actual: " << actual;
<< "Expected: " << testing::PrintToString(expected) << " "
<< " Actual: " << testing::PrintToString(actual);
}
}
@ -104,8 +104,8 @@ protected:
FAIL() << "Actual evttypes had additional event type "
<< etype
<< " not found in expected set. "
<< "Expected: " << expected << " "
<< " Actual: " << actual;
<< "Expected: " << testing::PrintToString(expected) << " "
<< " Actual: " << testing::PrintToString(actual);
}
}
}

View File

@ -0,0 +1,33 @@
/*
Copyright (C) 2022 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include <gtest.h>
#include <ppm_api_version.h>
TEST(api_version, unpack)
{
uint64_t ver1_2_3 = (1ULL << 44) | (2ULL << 24) | 3;
ASSERT_EQ(ver1_2_3, PPM_API_VERSION(1, 2, 3));
}
TEST(api_version, pack)
{
uint64_t ver1_2_3 = (1ULL << 44) | (2ULL << 24) | 3;
EXPECT_EQ(1u, PPM_API_VERSION_MAJOR(ver1_2_3));
EXPECT_EQ(2u, PPM_API_VERSION_MINOR(ver1_2_3));
EXPECT_EQ(3u, PPM_API_VERSION_PATCH(ver1_2_3));
}

View File

@ -0,0 +1,59 @@
/*
Copyright (C) 2021 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include <gtest.h>
#include <procfs_utils.h>
#include <sstream>
using namespace libsinsp::procfs_utils;
TEST(procfs_utils_test, get_userns_uid)
{
std::string uidmap = " 0 1000 0\n 1 1000000 1000\n";
std::stringstream s(uidmap);
ASSERT_EQ(get_userns_root_uid(s), 1000);
}
TEST(procfs_utils_test, get_userns_uid_root)
{
std::string uidmap = " 0 0 0\n";
std::stringstream s(uidmap);
ASSERT_EQ(get_userns_root_uid(s), 0);
}
TEST(procfs_utils_test, get_systemd_cgroup)
{
std::string cgroups = "12:perf_event:/\n"
"11:memory:/user.slice/user-0.slice/session-10697.scope\n"
"10:cpuset:/\n"
"9:cpu,cpuacct:/user.slice/user-0.slice/session-10697.scope\n"
"8:hugetlb:/\n"
"7:freezer:/\n"
"6:rdma:/\n"
"5:devices:/user.slice/user-0.slice/session-10697.scope\n"
"4:pids:/user.slice/user-0.slice/session-10697.scope\n"
"3:blkio:/user.slice/user-0.slice/session-10697.scope\n"
"2:net_cls,net_prio:/\n"
"1:name=systemd:/user.slice/user-0.slice/session-10697.scope";
std::stringstream s(cgroups);
ASSERT_EQ(get_systemd_cgroup(s), "/user.slice/user-0.slice/session-10697.scope");
}

View File

@ -1,5 +1,6 @@
#include "token_bucket.h"
#include <gtest.h>
#include <memory>
// token bucket default ctor
TEST(token_bucket, constructor)

View File

@ -949,16 +949,14 @@ void sinsp_threadinfo::traverse_parent_state(visitor_func_t &visitor)
}
}
void sinsp_threadinfo::populate_cmdline(string &cmdline, sinsp_threadinfo *tinfo)
void sinsp_threadinfo::populate_cmdline(string &cmdline, const sinsp_threadinfo *tinfo)
{
cmdline = tinfo->get_comm();
uint32_t j;
uint32_t nargs = (uint32_t)tinfo->m_args.size();
for(j = 0; j < nargs; j++)
for (const auto& arg : tinfo->m_args)
{
cmdline += " " + tinfo->m_args[j];
cmdline += " ";
cmdline += arg;
}
}

View File

@ -229,7 +229,7 @@ public:
typedef std::function<bool (sinsp_threadinfo *)> visitor_func_t;
void traverse_parent_state(visitor_func_t &visitor);
static void populate_cmdline(std::string &cmdline, sinsp_threadinfo *tinfo);
static void populate_cmdline(std::string &cmdline, const sinsp_threadinfo *tinfo);
// Return true if this thread is a part of a healthcheck,
// readiness probe, or liveness probe.

View File

@ -898,7 +898,7 @@ void sinsp_utils::bt(void)
bool sinsp_utils::find_first_env(std::string &out, const vector<std::string> &env, const vector<std::string> &keys)
{
for (const string key : keys)
for (const auto& key : keys)
{
for(const auto& env_var : env)
{