Compare commits

...

54 Commits

Author SHA1 Message Date
Federico Di Pierro d8d6d2bb45 fix(userspace/libsinsp): manually cherry picked 7326e56429.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-10-24 15:17:29 +02:00
Andrea Terzolo 76fd297bea cleanup
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
Co-authored-by: Mauro Ezequiel Moltrasio <mmoltras@redhat.com>
2023-10-24 15:17:29 +02:00
Andrea Terzolo e6a5c8e3e2 cleanup
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
Co-authored-by: Mauro Ezequiel Moltrasio <mmoltras@redhat.com>
2023-10-24 15:17:29 +02:00
Andrea Terzolo 12733f576f fix(modern): perform an exact check on `BPF_TRACE_RAW_TP` attach type
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-10-24 15:17:29 +02:00
Federico Di Pierro 29ec9e2c46 chore(userspace/libsinsp): set puevt even when the event is fitlered out.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-10-24 15:17:29 +02:00
Federico Di Pierro 3b1dc02551 chore(userspace/libsinsp): always clear `m_fds_to_remove` even when no matching `ptinfo` is found.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>

Co-authored-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2023-10-24 15:17:29 +02:00
Federico Di Pierro bdc2e3456f fix(userspace/libsinsp): avoid a possible source of segfault in libsinsp next.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-10-24 15:17:29 +02:00
Andrea Terzolo 3977c2d638 revert: commit 58d974572
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-10-13 17:49:50 +02:00
Luca Guerra a99b7e36d5 fix(ci): pin semgrep to 1.41.0
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-10-13 14:40:50 +02:00
Andrea Terzolo 8d93fd8f78 fix(scap): map unsupported fd types to SCAP_FD_UNSUPPORTED
This lets us read captures written with newer versions that add new fd
types.

Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-10-13 14:40:50 +02:00
Jason Dellaluce 58d9745723 fix(userspace/libsinsp): make plugin_filtercheck arg parsing more resilient
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-10-13 14:40:50 +02:00
Luca Guerra daa25c41b3 update(build): upgrade libcurl to 8.4.0
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-10-13 14:40:50 +02:00
Gerald Combs 10b2c10fc2 fix(libsinsp): Add a couple of NULL checks
Signed-off-by: Gerald Combs <gerald@wireshark.org>
2023-10-13 14:40:50 +02:00
Gerald Combs 5087729187 fix(libsinsp): Add a NULL check
Signed-off-by: Gerald Combs <gerald@wireshark.org>
2023-10-13 14:40:50 +02:00
Andrea Terzolo 7376d90024 cleanup(libscap): add some comments and minor cleanups to the CPU logic
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-10-13 14:40:50 +02:00
Federico Di Pierro 6c4222665f fix(userspace/libscap): fixed ebpf init loop on online CPUs.
Moreover, made kmod loop more robust too.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>

Co-authored-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-10-13 14:40:50 +02:00
Mauro Ezequiel Moltrasio 807b57be99 test(scap): add unit tests for scap_cgroup_prefix_path
Signed-off-by: Mauro Ezequiel Moltrasio <mmoltras@redhat.com>
Co-authored-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-21 15:24:47 +02:00
Mauro Ezequiel Moltrasio f6a8499542 fix(scap): remove the trailing slash when traversing cgroups
Without this change, having multiple levels of cgroups nested result on
the path removing the /.. sections, but leaves the prefix locked at the
first slash that is found.

Signed-off-by: Mauro Ezequiel Moltrasio <mmoltras@redhat.com>
2023-09-21 15:24:47 +02:00
Andrea Terzolo 96cc888b6d update(scap): add a `memset` to clear `m_agent_info`
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
Co-authored-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2023-09-21 15:24:47 +02:00
Grzegorz Nosek d13e89961b fix(scap): do not access /proc in generic platform code
Signed-off-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2023-09-21 15:24:47 +02:00
Andrea Terzolo 6904e23a4f cleanup(userspace): provide an error message
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-21 15:24:47 +02:00
Andrea Terzolo c8dc49ff92 fix(userspace): report a clear message when the '/proc' directory is not
available

Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-21 15:24:47 +02:00
Andrea Terzolo 5efa6ca6eb fix(userspace): avoid a segmentation fault when `m_input_plugin` is not
initialized

Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-21 15:24:47 +02:00
Nathan Baker 8271dec87e fix(libsinsp): Don't loop forever on container api
Add an escape clause on the container lookup path to make sure we're not just constantly getting timeouts.

/kind bug
/area libsinsp

```release-note
NONE
```

Signed-off-by: Nathan Baker <nathan.baker@sysdig.com>
2023-09-19 10:18:42 +02:00
Federico Di Pierro d4060b2011 fix(ci): fixed release-body double quoted string usage.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-14 14:21:44 +02:00
Federico Di Pierro 72a25d501a fix(driver/modern_bpf): fixed modern bpf driver.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>

Co-authored-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-14 10:49:42 +02:00
Federico Di Pierro d230606fb0 chore(ci): improve latest-kernel workflow.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-14 10:49:42 +02:00
Federico Di Pierro 0122aead06 fix(driver): fixed build against 6.6 rc kernel.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-14 10:49:42 +02:00
Federico Di Pierro 5860a5f8d9 chore(ci): reworked to avoid using weird gh commands.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>

Co-authored-by: Luca Guerra <luca@guerra.sh>
2023-09-14 10:49:42 +02:00
Federico Di Pierro 191a78bc5f fix(ci): fixed release body step.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-14 10:49:42 +02:00
Federico Di Pierro 6b92800d59 fix(ci): properly skip release-body workflow in non-drivers tags.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-14 10:49:42 +02:00
Leonardo Grasso 2aa6057c93 docs: add LICENSE
This commit creates a copy of https://github.com/falcosecurity/libs/blob/master/COPYING (which is kept for historical reasons) to address the recommendation reported by https://github.com/falcosecurity/evolution/issues/317

Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-09-14 10:49:42 +02:00
Federico Di Pierro eecb760909 new(ci): append SCHEMA and API versions to drivers release body.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-14 10:49:42 +02:00
Angelo Puglisi 8958f00bfa fix(kmod): safer ppm_get_mm_exe_file
Leverage `get_file_rcu` being a define to use the safer version of
`get_mm_exe_file`.
This will allow kernel versions prior to 4.1, but with the fix being
backported don't suffer RCU violations.

Co-authored-by: Joseph Pittman <joseph.pittman@sysdig.com>
Signed-off-by: Angelo Puglisi <angelo.puglisi@sysdig.com>
2023-09-13 10:23:39 +02:00
Federico Di Pierro 8d147677ac chore(ci): enforce bundled deps generated binary (sinsp-example) to be as static as possible.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-13 10:23:39 +02:00
Gerald Combs 4644924b53 update(libsinsp): Make sinsp::fseek public
Give consumers random access to scap files.

Signed-off-by: Gerald Combs <gerald@wireshark.org>
2023-09-07 11:29:03 +02:00
Grzegorz Nosek f9127f9b17 fix(scap): don't use generic platform for nodriver full proc scan
Signed-off-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2023-09-07 11:29:03 +02:00
Grzegorz Nosek 196fd56ad6 fix(sinsp): disable get_cwd assert, it breaks tests with non-live platforms
This should technically be controlled by the platform, but we're
not quite there yet, so as long as we have test_input setups
where threads may not have a main thread, disable this assert.

Signed-off-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2023-09-07 11:29:03 +02:00
Grzegorz Nosek 29bba20a52 cleanup(tests): Log sinsp-example messages in e2e tests
They were logged as JSON parse errors before, but we can simply
print them without trying to parse them.

Signed-off-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2023-09-07 11:29:03 +02:00
Grzegorz Nosek c9d2723d51 new(sinsp): add raw output to sinsp-example
This is *really* raw (basic header info and a hexdump
of each parameter) but it may come in handy any time we need
to go deeper in analyzing individual events.

Note: to get an actual raw dump, we could use two extra features:
* show the sentinel if available
* verify the total event length vs the lengths of all parameters

Note 2: I really couldn't be bothered to fight with C++ iostreams
to get a usable hex dump so I went for classic C stdio.

To do this, we'd need the access to the raw `scap_evt`, which
would violate the abstraction layering even more.

Signed-off-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2023-09-07 11:29:03 +02:00
Grzegorz Nosek 68c4472981 cleanup(sinsp): remove all non-formatter fields from output
The formatter output should be good enough now

Note: we keep the old format in JSON mode for e2e tests compatibility

Signed-off-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2023-09-07 11:29:03 +02:00
Grzegorz Nosek 1a7864328e cleanup(sinsp): move "is main thread" logic to main()
Signed-off-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2023-09-07 11:29:03 +02:00
Grzegorz Nosek a76366fe72 cleanup(sinsp): inline json_dump_init
Signed-off-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2023-09-07 11:29:03 +02:00
Grzegorz Nosek 7e017af2f4 fix(sinsp): add missing event category names
Signed-off-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2023-09-07 11:29:03 +02:00
Grzegorz Nosek 6c9bb76fba new(sinsp): use sinsp formatters for plaintext output in sinsp-example
This makes sinsp-example actually useful for looking at events
in non-JSON mode.

--output-fields-json now also affects plaintext output and has been renamed
to --output-fields.

The default output format has been trimmed too, removing the items that
are present in the default output format. Effectively this leaves only
the container id (or `HOST`) and the event category.

Signed-off-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2023-09-07 11:29:03 +02:00
Grzegorz Nosek c07e7823f6 cleanup(sinsp): move getting the event out of the dump function
Signed-off-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2023-09-07 11:29:03 +02:00
Grzegorz Nosek 58c2e7acc3 chore(sinsp): use unique_ptr in sinsp-example
Signed-off-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2023-09-07 11:29:03 +02:00
Grzegorz Nosek 3cdca05e80 fix(sinsp): check the correct parameter for PT_PID type
Signed-off-by: Grzegorz Nosek <grzegorz.nosek@sysdig.com>
2023-09-07 11:29:03 +02:00
Roberto Scolaro 05f013aa24 fix(libscap,libsinsp): correctly manage pidfd in scapfiles
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-09-06 11:56:00 +02:00
Roberto Scolaro a3fb7149b6 fix(libscap): handle fname with memfd
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-09-06 11:56:00 +02:00
Roberto Scolaro b553485768 fix(libscap,libsinsp): correctly manage memfd in scapfiles
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-09-06 11:56:00 +02:00
Luca Guerra 11fdb6dcce update(build): update elfutils to 0.189
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-06 11:56:00 +02:00
Luca Guerra 9575c45400 update(build): update libtbb to 2021.9
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-06 11:56:00 +02:00
Luca Guerra b9a90fb643 chore(cmake): update OpenSSL to 3.1.2
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-06 11:56:00 +02:00
53 changed files with 946 additions and 703 deletions

View File

@ -298,6 +298,43 @@ jobs:
KERNELDIR=/lib/modules/$(ls /lib/modules)/build make scap-open driver bpf unit-test-libsinsp -j6
./libsinsp/test/unit-test-libsinsp
# This job checks that a bundled deps of libs is as static as possible
test-libs-static:
name: test-libs-static (bundled_deps)
runs-on: ubuntu-22.04
steps:
- name: Checkout Libs ⤵️
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install deps ⛓️
run: |
sudo apt update
sudo apt install -y --no-install-recommends ca-certificates cmake build-essential clang-14 llvm-14 git pkg-config autoconf automake libtool libelf-dev libcap-dev linux-headers-$(uname -r)
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-14 90
sudo update-alternatives --install /usr/bin/llvm-strip llvm-strip /usr/bin/llvm-strip-14 90
sudo update-alternatives --install /usr/bin/llc llc /usr/bin/llc-14 90
- name: Build sinsp-example
run: |
mkdir -p build
cd build && cmake -DUSE_BUNDLED_DEPS=On -DBUILD_DRIVER=ON -DBUILD_LIBSCAP_MODERN_BPF=ON -DBUILD_BPF=On -DBUILD_LIBSCAP_GVISOR=On -DCREATE_TEST_TARGETS=Off -DENABLE_LIBSCAP_TESTS=Off ../
make -j$(nproc) sinsp-example
- name: Ensure that sinsp-example with bundled deps is as static as possible
run: |
ldd "build/libsinsp/examples/sinsp-example" | cut --fields=2 | cut --delimiter=' ' --fields=1 | rev | cut --delimiter='/' --fields=1 | rev | sort --unique --version-sort > ldd_out.txt
cat > expected_ldd_out.txt <<EOF
ld-linux-x86-64.so.2
libc.so.6
libgcc_s.so.1
libm.so.6
libstdc++.so.6
linux-vdso.so.1
EOF
diff -u expected_ldd_out.txt ldd_out.txt
run-e2e-tests-amd64:
name: run-e2e-tests-amd64
strategy:

View File

@ -11,7 +11,7 @@ jobs:
name: check-insecure-api
runs-on: ubuntu-latest
container:
image: returntocorp/semgrep
image: returntocorp/semgrep:1.41.0
steps:
- name: Checkout Libs ⤵️
uses: actions/checkout@v3

View File

@ -4,8 +4,8 @@ on:
workflow_dispatch:
inputs:
linux-version:
description: 'Archlinux kernel version to build a driver against, eg: 6.2.arch1-1'
required: true
description: 'Archlinux kernel version to build a driver against, eg: 6.2.arch1-1 or empty to build latest mainline'
required: false
type: string
schedule:
- cron: '0 8 * * *' # every day at 8am
@ -59,7 +59,7 @@ jobs:
- name: Update README badge
uses: schneegans/dynamic-badges-action@v1.6.0
if: always() && inputs.linux-version == ''
if: always() && github.event_name == 'schedule'
with:
auth: ${{ secrets.FEDEDP_GIST_SECRET }}
gistID: 1cbc5d42edf8e3a02fb75e76625f1072

View File

@ -13,8 +13,11 @@ concurrency:
cancel-in-progress: true
jobs:
release-body:
check-driver-tag:
runs-on: ubuntu-latest
outputs:
driver_tag: ${{ steps.regex-match.outputs.match }}
steps:
# Note: there is no `tag` filter for `workflow_run`.
# We need to manually check whether we are running on a tag.
@ -25,9 +28,25 @@ jobs:
text: ${{ github.event.workflow_run.head_branch }}
regex: '[0-9]+.[0-9]+.[0-9]+\+driver$'
- name: Skip on non driver tag
if: steps.regex-match.outputs.match == ''
run: exit 0
release-body:
needs: check-driver-tag
runs-on: ubuntu-latest
if: needs.check-driver-tag.outputs.driver_tag != ''
steps:
- name: Clone libs repo
uses: actions/checkout@v4
with:
ref: ${{ github.event.workflow_run.head_branch }}
- name: Extract API and SCHEMA versions
run: |
touch release-body.md
API_VERS=$(cat driver/API_VERSION)
SCHEMA_VERS=$(cat driver/SCHEMA_VERSION)
echo '!'"[API](https://img.shields.io/badge/API-${API_VERS}-yellow)" >> release-body.md
echo '!'"[SCHEMA](https://img.shields.io/badge/SCHEMA-${SCHEMA_VERS}-yellow)" >> release-body.md
echo "" >> release-body.md
- name: Download matrixes
uses: dawidd6/action-download-artifact@v2
@ -52,7 +71,7 @@ jobs:
sed -i 's/\[\(.\)\]([^)]*)/\1/g' matrix_ARM64.md
sed -i '1s/^/# Driver Testing Matrix amd64\n\n/' matrix_X64.md
sed -i '1s/^/# Driver Testing Matrix arm64\n\n/' matrix_ARM64.md
cat matrix_X64.md matrix_ARM64.md > release-body.md
cat matrix_X64.md matrix_ARM64.md >> release-body.md
- name: Release
uses: softprops/action-gh-release@v1

202
LICENSE Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] 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.

View File

@ -43,8 +43,8 @@ else()
curl
PREFIX "${PROJECT_BINARY_DIR}/curl-prefix"
DEPENDS openssl zlib
URL "https://github.com/curl/curl/releases/download/curl-8_2_0/curl-8.2.0.tar.bz2"
URL_HASH "SHA256=080aaa5bef29ab3f592101e7a95f32ddbe88b92125cb28dde479d5a104928ea4"
URL "https://github.com/curl/curl/releases/download/curl-8_4_0/curl-8.4.0.tar.bz2"
URL_HASH "SHA256=e5250581a9c032b1b6ed3cf2f9c114c811fc41881069e9892d115cc73f9e88c6"
CONFIGURE_COMMAND
./configure
${CURL_SSL_OPTION}

View File

@ -34,9 +34,9 @@ else()
libelf
PREFIX "${PROJECT_BINARY_DIR}/libelf-prefix"
DEPENDS zlib
URL "https://sourceware.org/elfutils/ftp/0.187/elfutils-0.187.tar.bz2"
URL_HASH "SHA256=e70b0dfbe610f90c4d1fe0d71af142a4e25c3c4ef9ebab8d2d72b65159d454c8"
CONFIGURE_COMMAND ./configure LDFLAGS=-L${ZLIB_SRC} "CFLAGS=-I${ZLIB_INCLUDE}" --enable-deterministic-archives --disable-debuginfod --disable-libdebuginfod
URL "https://sourceware.org/elfutils/ftp/0.189/elfutils-0.189.tar.bz2"
URL_HASH "SHA256=39bd8f1a338e2b7cd4abc3ff11a0eddc6e690f69578a57478d8179b4148708c8"
CONFIGURE_COMMAND ./configure LDFLAGS=-L${ZLIB_SRC} "CFLAGS=-I${ZLIB_INCLUDE}" --enable-deterministic-archives --disable-debuginfod --disable-libdebuginfod --without-zstd
BUILD_IN_SOURCE 1
BUILD_COMMAND ${CMAKE_MAKE_PROGRAM} -C lib libeu.a
COMMAND ${CMAKE_MAKE_PROGRAM} -C libelf libelf${LIBELF_LIB_SUFFIX}

View File

@ -28,8 +28,8 @@ else()
ExternalProject_Add(openssl
PREFIX "${PROJECT_BINARY_DIR}/openssl-prefix"
URL "https://github.com/openssl/openssl/releases/download/openssl-3.1.1/openssl-3.1.1.tar.gz"
URL_HASH "SHA256=b3aa61334233b852b63ddb048df181177c2c659eb9d4376008118f9c08d07674"
URL "https://github.com/openssl/openssl/releases/download/openssl-3.1.2/openssl-3.1.2.tar.gz"
URL_HASH "SHA256=a0ce69b8b97ea6a35b96875235aa453b966ba3cba8af2de23657d8b6767d6539"
CONFIGURE_COMMAND ./config ${OPENSSL_SHARED_OPTION} --prefix=${OPENSSL_INSTALL_DIR} --libdir=lib
BUILD_COMMAND ${CMAKE_MAKE_PROGRAM}
BUILD_IN_SOURCE 1

View File

@ -46,8 +46,8 @@ else()
if(NOT TARGET tbb)
message(STATUS "Using bundled tbb in '${TBB_SRC}'")
set(TBB_SRC_URL "https://github.com/oneapi-src/oneTBB/archive/refs/tags/v2021.8.0.tar.gz")
set(TBB_SRC_URL_HASH "SHA256=eee380323bb7ce864355ed9431f85c43955faaae9e9bce35c62b372d7ffd9f8b")
set(TBB_SRC_URL "https://github.com/oneapi-src/oneTBB/archive/refs/tags/v2021.9.0.tar.gz")
set(TBB_SRC_URL_HASH "SHA256=1ce48f34dada7837f510735ff1172f6e2c261b09460e3bf773b49791d247d24e")
set(TBB_FLAGS "")
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# latest TBB has issues with GCC >= 12

View File

@ -2839,7 +2839,12 @@ FILLER(execve_extra_tail_1, true)
struct timespec64 time = {0};
/* Parameter 25: exe_file ctime (last status change time, epoch value in nanoseconds) (type: PT_ABSTIME) */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
time = _READ(inode->__i_ctime);
time.tv_nsec = time.tv_nsec & ~I_CTIME_QUERIED; // See https://elixir.bootlin.com/linux/v6.6-rc1/source/include/linux/fs.h#L1544
#else
time = _READ(inode->i_ctime);
#endif
res = bpf_push_u64_to_ring(data, bpf_epoch_ns_from_time(time));
CHECK_RES(res);
@ -6694,7 +6699,12 @@ FILLER(sched_prog_exec_4, false)
struct timespec64 time = {0};
/* Parameter 25: exe_file ctime (last status change time, epoch value in nanoseconds) (type: PT_ABSTIME) */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
time = _READ(inode->__i_ctime);
time.tv_nsec = time.tv_nsec & ~I_CTIME_QUERIED; // See https://elixir.bootlin.com/linux/v6.6-rc1/source/include/linux/fs.h#L1544
#else
time = _READ(inode->i_ctime);
#endif
res = bpf_push_u64_to_ring(data, bpf_epoch_ns_from_time(time));
CHECK_RES(res);

View File

@ -584,6 +584,13 @@
#define FMODE_CREATED (/*(__force fmode_t) */0x100000)
//////////////////////////
// ctime flags
//////////////////////////
/* `include/linux/fs.h` from kernel source tree. */
#define I_CTIME_QUERIED (1L<<30)
//////////////////////////
// flock flags
//////////////////////////

View File

@ -36,6 +36,10 @@ struct task_struct___cos {
struct audit_task_info *audit;
};
struct inode___v6_6 {
struct timespec64 __i_ctime;
};
#ifndef BPF_NO_PRESERVE_ACCESS_INDEX
#pragma clang attribute pop
#endif

View File

@ -213,7 +213,16 @@ int BPF_PROG(t1_sched_p_exec,
/* Parameter 25: exe_file ctime (last status change time, epoch value in nanoseconds) (type: PT_ABSTIME) */
struct timespec64 time = { 0, 0 };
BPF_CORE_READ_INTO(&time, exe_inode, i_ctime);
if(bpf_core_field_exists(exe_inode->i_ctime))
{
BPF_CORE_READ_INTO(&time, exe_inode, i_ctime);
}
else
{
struct inode___v6_6 *exe_inode_v6_6 = (void *)exe_inode;
BPF_CORE_READ_INTO(&time, exe_inode_v6_6, __i_ctime);
time.tv_nsec = time.tv_nsec & ~I_CTIME_QUERIED;
}
auxmap__store_u64_param(auxmap, extract__epoch_ns_from_time(time));
/* Parameter 26: exe_file mtime (last modification time, epoch value in nanoseconds) (type: PT_ABSTIME) */

View File

@ -277,7 +277,16 @@ int BPF_PROG(t1_execve_x,
/* Parameter 25: exe_file ctime (last status change time, epoch value in nanoseconds) (type: PT_ABSTIME) */
struct timespec64 time = { 0, 0 };
BPF_CORE_READ_INTO(&time, exe_inode, i_ctime);
if(bpf_core_field_exists(exe_inode->i_ctime))
{
BPF_CORE_READ_INTO(&time, exe_inode, i_ctime);
}
else
{
struct inode___v6_6 *exe_inode_v6_6 = (void *)exe_inode;
BPF_CORE_READ_INTO(&time, exe_inode_v6_6, __i_ctime);
time.tv_nsec = time.tv_nsec & ~I_CTIME_QUERIED;
}
auxmap__store_u64_param(auxmap, extract__epoch_ns_from_time(time));
/* Parameter 26: exe_file mtime (last modification time, epoch value in nanoseconds) (type: PT_ABSTIME) */

View File

@ -293,7 +293,16 @@ int BPF_PROG(t1_execveat_x,
/* Parameter 25: exe_file ctime (last status change time, epoch value in nanoseconds) (type: PT_ABSTIME) */
struct timespec64 time = { 0, 0 };
BPF_CORE_READ_INTO(&time, exe_inode, i_ctime);
if(bpf_core_field_exists(exe_inode->i_ctime))
{
BPF_CORE_READ_INTO(&time, exe_inode, i_ctime);
}
else
{
struct inode___v6_6 *exe_inode_v6_6 = (void *)exe_inode;
BPF_CORE_READ_INTO(&time, exe_inode_v6_6, __i_ctime);
time.tv_nsec = time.tv_nsec & ~I_CTIME_QUERIED;
}
auxmap__store_u64_param(auxmap, extract__epoch_ns_from_time(time));
/* Parameter 26: exe_file mtime (last modification time, epoch value in nanoseconds) (type: PT_ABSTIME) */

View File

@ -579,12 +579,18 @@ int f_sys_write_x(struct event_filler_arguments *args)
/*
* get_mm_exe_file is only exported in some kernel versions
*/
struct file *ppm_get_mm_exe_file(struct mm_struct *mm)
{
struct file *exe_file;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
/*
* The following if/else preprocessor directive is to cover for that change:
* https://github.com/torvalds/linux/commit/90f31d0ea88880f780574f3d0bb1a227c4c66ca3#diff-e37b5cb4c23f6ab27741c60ec48674eff0268624a228c9a1cddddb9e4ee2922dL709
* That was introduced in linux 4.1, but it's backported in some distro kernels.
* Luckily enough, `get_file_rcu` is a define, so we can check for it and use
* the safer version.
*/
#if defined(get_file_rcu)
rcu_read_lock();
exe_file = rcu_dereference(mm->exe_file);
if (exe_file && !get_file_rcu(exe_file))
@ -1506,8 +1512,15 @@ cgroups_error:
* During kernel versions `i_ctime` changed from `struct timespec` to `struct timespec64`
* but fields names should be always the same.
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
{
struct timespec64 inode_ctime;
inode_ctime = inode_get_ctime(file_inode(exe_file));
ctime = inode_ctime.tv_sec * (uint64_t) 1000000000 + inode_ctime.tv_nsec;
}
#else
ctime = file_inode(exe_file)->i_ctime.tv_sec * (uint64_t) 1000000000 + file_inode(exe_file)->i_ctime.tv_nsec;
#endif
/* Support exe_file mtime
* During kernel versions `i_mtime` changed from `struct timespec` to `struct timespec64`
* but fields names should be always the same.
@ -7769,7 +7782,15 @@ cgroups_error:
* During kernel versions `i_ctime` changed from `struct timespec` to `struct timespec64`
* but fields names should be always the same.
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
{
struct timespec64 inode_ctime;
inode_ctime = inode_get_ctime(file_inode(exe_file));
ctime = inode_ctime.tv_sec * (uint64_t) 1000000000 + inode_ctime.tv_nsec;
}
#else
ctime = file_inode(exe_file)->i_ctime.tv_sec * (uint64_t) 1000000000 + file_inode(exe_file)->i_ctime.tv_nsec;
#endif
/* Support exe_file mtime
* During kernel versions `i_mtime` changed from `struct timespec` to `struct timespec64`

View File

@ -197,6 +197,10 @@ def parse_log(log: str) -> dict:
Returns:
A dictionary holding all the captured values for the event.
"""
if log.startswith('--'):
# sinsp-example diagnostic messages
print(log)
return None
try:
return json.loads(log)
except json.JSONDecodeError as e:

View File

@ -4,6 +4,7 @@ from sinspqa.sinsp import assert_events
from sinspqa.docker import get_container_id
sinsp_args = [
"-j",
"-f", "evt.category=process and not container.id=host",
"-o", "%container.id %evt.args %evt.category %evt.type %proc.cmdline %proc.exe %user.uid %user.name %user.homedir %group.gid %group.name"
]

View File

@ -65,6 +65,12 @@ set(LIBSCAP_TESTS_SOURCES ${USERSPACE_TEST_SUITE})
file(GLOB_RECURSE LIBSCAP_TESTS_UTILS_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/helpers/*cpp")
list(APPEND LIBSCAP_TESTS_SOURCES ${LIBSCAP_TESTS_UTILS_SOURCES})
# Linux specific tests
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
file(GLOB_RECURSE LINUX_TEST_SUITE "${CMAKE_CURRENT_SOURCE_DIR}/test_suites/userspace/linux/*.cpp")
list(APPEND LIBSCAP_TEST_SOURCES ${LINUX_TEST_SUITE})
endif()
# Engine-specific tests
if(BUILD_DRIVER)
file(GLOB_RECURSE KMOD_TEST_SUITE "${CMAKE_CURRENT_SOURCE_DIR}/test_suites/engines/kmod/*.cpp")

View File

@ -0,0 +1,77 @@
/*
Copyright (C) 2023 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/gtest.h>
#include <linux/scap_cgroup.h>
#include <linux/scap_cgroup.c>
TEST(cgroups, path_relative)
{
char final_path[4096];
const char* prefix = "/1/2/3";
const char* path = "/../../../init.scope";
size_t prefix_len = 0;
size_t path_strip_len = 0;
ASSERT_EQ(scap_cgroup_prefix_path(prefix, path, &prefix_len, &path_strip_len), SCAP_SUCCESS);
snprintf(final_path, sizeof(final_path), "%.*s%s", (int)prefix_len, prefix, path + path_strip_len);
ASSERT_STREQ(final_path,"/init.scope");
}
TEST(cgroups, path_relative_with_final_slash)
{
char final_path[4096];
const char* prefix = "/1/2/3/";
const char* path = "/../../../init.scope";
size_t prefix_len = 0;
size_t path_strip_len = 0;
ASSERT_EQ(scap_cgroup_prefix_path(prefix, path, &prefix_len, &path_strip_len), SCAP_SUCCESS);
snprintf(final_path, sizeof(final_path), "%.*s%s", (int)prefix_len, prefix, path + path_strip_len);
ASSERT_STREQ(final_path,"/1/init.scope");
}
TEST(cgroups, path_absolute)
{
char final_path[4096];
const char* prefix = "/1/2/3";
const char* path = "/absolute";
size_t prefix_len = 0;
size_t path_strip_len = 0;
ASSERT_EQ(scap_cgroup_prefix_path(prefix, path, &prefix_len, &path_strip_len), SCAP_SUCCESS);
snprintf(final_path, sizeof(final_path), "%.*s%s", (int)prefix_len, prefix, path + path_strip_len);
ASSERT_STREQ(final_path,"/1/2/3/absolute");
}
TEST(cgroups, prefix_empty)
{
const char* prefix = "";
const char* path = "/../../absolute";
size_t prefix_len = 0;
size_t path_strip_len = 0;
ASSERT_EQ(scap_cgroup_prefix_path(prefix, path, &prefix_len, &path_strip_len), SCAP_FAILURE);
}
TEST(cgroups, path_empty)
{
char final_path[4096];
const char* prefix = "/1/2/3";
const char* path = "";
size_t prefix_len = 0;
size_t path_strip_len = 0;
ASSERT_EQ(scap_cgroup_prefix_path(prefix, path, &prefix_len, &path_strip_len), SCAP_SUCCESS);
snprintf(final_path, sizeof(final_path), "%.*s%s", (int)prefix_len, prefix, path + path_strip_len);
ASSERT_STREQ(final_path,"/1/2/3");
}

View File

@ -17,6 +17,10 @@ limitations under the License.
#include "state.h"
#include <sys/resource.h>
#include <linux/limits.h>
#include <sys/utsname.h>
#include <fcntl.h> /* Definition of AT_* constants */
#include <unistd.h>
static int setup_libbpf_print_verbose(enum libbpf_print_level level, const char* format, va_list args)
{
@ -164,16 +168,139 @@ int pman_get_required_buffers()
return g_state.n_required_buffers;
}
bool check_location(const char* path)
{
static const char bpf_trace_raw_byte_array[] = "BPF_TRACE_RAW_TP";
bool res = false;
// On success `faccessat` returns 0.
if(faccessat(0, path, R_OK, AT_EACCESS) != 0)
{
return false;
}
char *file_content = NULL;
FILE *f = fopen(path, "r");
if(!f)
{
return false;
}
// Seek to the end of file
if(fseek(f, 0, SEEK_END))
{
goto cleanup;
}
// Return the dimension of the file
long sz = ftell(f);
if (sz < 0)
{
goto cleanup;
}
// Seek again to the beginning of the file
if(fseek(f, 0, SEEK_SET))
{
goto cleanup;
}
// pre-alloc memory to read all of BTF data
file_content = malloc(sz);
if (!file_content)
{
goto cleanup;
}
// read all of BTF data
if(fread(file_content, 1, sz, f) < sz)
{
goto cleanup;
}
// Search 'BPF_TRACE_RAW_TP' byte array
int z = 0;
for(int j = 0; j< sz; j++)
{
if(file_content[j] == bpf_trace_raw_byte_array[z])
{
z++;
if(z == sizeof(bpf_trace_raw_byte_array) / sizeof(*bpf_trace_raw_byte_array))
{
res = true;
break;
}
}
else
{
z = 0;
}
}
cleanup:
if(f)
{
fclose(f);
}
if(file_content)
{
free(file_content);
}
return res;
}
bool probe_BPF_TRACE_RAW_TP_type(void)
{
// These locations are taken from libbpf library:
// https://elixir.bootlin.com/linux/latest/source/tools/lib/bpf/btf.c#L4767
const char *locations[] = {
"/sys/kernel/btf/vmlinux",
"/boot/vmlinux-%1$s",
"/lib/modules/%1$s/vmlinux-%1$s",
"/lib/modules/%1$s/build/vmlinux",
"/usr/lib/modules/%1$s/kernel/vmlinux",
"/usr/lib/debug/boot/vmlinux-%1$s",
"/usr/lib/debug/boot/vmlinux-%1$s.debug",
"/usr/lib/debug/lib/modules/%1$s/vmlinux",
};
// Try canonical `vmlinux` BTF through `sysfs` first.
if(check_location(locations[0]))
{
return true;
}
// Fall back to trying to find `vmlinux` on disk otherwise
struct utsname buf = {};
if(uname(&buf) == -1)
{
return false;
}
char path[PATH_MAX + 1];
// Skip vmlinux since we already tested it.
for (int i = 1; i < sizeof(locations) / sizeof(*locations); i++)
{
snprintf(path, PATH_MAX, locations[i], buf.release);
if(check_location(path))
{
return true;
}
}
return false;
}
/*
* Probe the kernel for required dependencies, ring buffer maps and tracing
* progs needs to be supported.
*/
bool pman_check_support()
{
bool res;
res = libbpf_probe_bpf_map_type(BPF_MAP_TYPE_RINGBUF, NULL) > 0;
if (!res)
bool res = libbpf_probe_bpf_map_type(BPF_MAP_TYPE_RINGBUF, NULL) > 0;
if(!res)
{
pman_print_error("ring buffer map type is not supported");
return res;
@ -182,8 +309,18 @@ bool pman_check_support()
res = libbpf_probe_bpf_prog_type(BPF_PROG_TYPE_TRACING, NULL) > 0;
if (!res)
{
pman_print_error("tracing program type is not supported");
return res;
// The above function checks for the `BPF_TRACE_FENTRY` attach type presence, while we need
// to check for the `BPF_TRACE_RAW_TP` one. If `BPF_TRACE_FENTRY` is defined we are
// sure `BPF_TRACE_RAW_TP` is defined as well, in all other cases, we need to search
// for it in the `vmlinux` file.
res = probe_BPF_TRACE_RAW_TP_type();
if(!res)
{
// Clear the errno for `pman_print_error`
errno = 0;
pman_print_error("prog 'BPF_TRACE_RAW_TP' is not supported");
return res;
}
}
/* Probe result depends on the success of map creation, no additional

View File

@ -201,6 +201,16 @@ int pman_finalize_ringbuf_array_after_loading()
continue;
}
if(ringbuf_id >= g_state.n_required_buffers)
{
/* If we arrive here it means that we have too many CPUs for our allocated ring buffers
* so probably we faced a CPU hotplug.
*/
snprintf(error_message, MAX_ERROR_MESSAGE_LEN, "the actual system configuration requires more than '%d' ring buffers", g_state.n_required_buffers);
pman_print_error((const char *)error_message);
goto clean_percpu_ring_buffers;
}
if(bpf_map_update_elem(ringubuf_array_fd, &i, &ringbufs_fds[ringbuf_id], BPF_ANY))
{
snprintf(error_message, MAX_ERROR_MESSAGE_LEN, "failed to add the ringbuf map for CPU '%d' to ringbuf '%d'", i, ringbuf_id);

View File

@ -73,16 +73,6 @@ add_library(scap
scap_userlist.c
scap_suppress.c)
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
target_sources(scap PRIVATE linux/scap_machine_info.c)
elseif(WIN32)
target_sources(scap PRIVATE win32/scap_machine_info.c)
elseif(APPLE)
target_sources(scap PRIVATE macos/scap_machine_info.c)
elseif(EMSCRIPTEN)
target_sources(scap PRIVATE emscripten/scap_machine_info.c)
endif()
set_scap_target_properties(scap)
add_library(scap_platform_util

View File

@ -1,102 +0,0 @@
/*
Copyright (C) 2023 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 "scap_machine_info.h"
#include "scap_os_machine_info.h"
#include "scap_limits.h"
#include "scap_assert.h"
#include "scap.h"
#include "gettimeofday.h"
#include <sys/utsname.h>
#include <stdio.h>
#include <unistd.h>
// note: in a webassembly module we have no notion of process or host from which
// retrieving the boot time. As such, we just take a timestamp at which the
// module is inited throgh a function noted as __attribute__((constructor)), which
// should be supported by clang (emscripten's backend). We make no distiction
// between the agent's boot time and the host boot time here.
static uint64_t s_emscripten_boot_time_ns = 0;
static void retrieve_boot_time_ns() __attribute__((constructor));
static void retrieve_boot_time_ns()
{
s_emscripten_boot_time_ns = get_timestamp_ns();
}
void scap_os_get_agent_info(scap_agent_info* agent_info)
{
agent_info->start_ts_epoch = 0;
agent_info->start_time = 0;
/* Info 1:
*
* unix time in nsec of our startup time
*/
{
// todo: this needs to be the process startup time
agent_info->start_ts_epoch = s_emscripten_boot_time_ns;
}
/* Info 2:
*
* our startup time in seconds since boot
*/
if(agent_info->start_ts_epoch != 0)
{
uint64_t boot_time_ns = s_emscripten_boot_time_ns;
agent_info->start_time = (agent_info->start_ts_epoch - boot_time_ns) / (1.0 * SECOND_TO_NS);
}
/* Info 3:
*
* Kernel release `uname -r` of the machine the agent is running on.
*/
struct utsname uts;
uname(&uts);
snprintf(agent_info->uname_r, sizeof(agent_info->uname_r), "%s", uts.release);
}
static void scap_gethostname(char* buf, size_t size)
{
char *env_hostname = getenv(SCAP_HOSTNAME_ENV_VAR);
if(env_hostname != NULL)
{
snprintf(buf, size, "%s", env_hostname);
}
else
{
gethostname(buf, size);
}
}
int32_t scap_os_get_machine_info(scap_machine_info* machine_info, char* lasterr)
{
machine_info->num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
machine_info->memory_size_bytes = (uint64_t)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE);
scap_gethostname(machine_info->hostname, sizeof(machine_info->hostname));
machine_info->boot_ts_epoch = s_emscripten_boot_time_ns;
if(machine_info->boot_ts_epoch == 0)
{
return SCAP_FAILURE;
}
return SCAP_SUCCESS;
}

View File

@ -1465,8 +1465,6 @@ int32_t scap_bpf_load(
const char *bpf_probe,
scap_open_args *oargs)
{
int online_cpu;
int j;
struct scap_bpf_engine_params* bpf_args = oargs->engine_params;
if(set_runtime_params(handle) != SCAP_SUCCESS)
@ -1521,26 +1519,28 @@ int32_t scap_bpf_load(
//
// Open and initialize all the devices
//
online_cpu = 0;
for(j = 0; j < handle->m_ncpus; ++j)
struct scap_device_set *devset = &handle->m_dev_set;
uint32_t online_idx = 0;
// devset->m_ndevs = online CPUs in the system.
// handle->m_ncpus = available CPUs in the system.
for(uint32_t cpu_idx = 0; online_idx < devset->m_ndevs && cpu_idx < handle->m_ncpus; ++cpu_idx)
{
struct perf_event_attr attr = {
.sample_type = PERF_SAMPLE_RAW,
.type = PERF_TYPE_SOFTWARE,
.config = PERF_COUNT_SW_BPF_OUTPUT,
};
int pmu_fd;
int ret;
struct scap_device *dev;
int pmu_fd = 0;
int ret = 0;
/* We suppose that CPU 0 is always online, so we only check for j > 0 */
if(j > 0)
/* We suppose that CPU 0 is always online, so we only check for cpu_idx > 0 */
if(cpu_idx > 0)
{
char filename[SCAP_MAX_PATH_SIZE];
int online;
FILE *fp;
int online = 0;
snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%d/online", j);
snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%d/online", cpu_idx);
fp = fopen(filename, "r");
if(fp == NULL)
@ -1549,15 +1549,15 @@ int32_t scap_bpf_load(
// Fallback at considering them online if we can at least reach their folder.
// This is useful for example for raspPi devices.
// See: https://github.com/kubernetes/kubernetes/issues/95039
snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%d/", j);
snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%d/", cpu_idx);
if (access(filename, F_OK) == 0)
{
online = 1;
}
else
{
return scap_errprintf(handle->m_lasterr, errno, "can't open %sonline", filename);
}
// If we can't access the cpu, count it as offline.
// Some VMs or hyperthreading systems export an high number of configured CPUs,
// even if they are not existing. See https://github.com/falcosecurity/falco/issues/2843 for example.
// Skip them.
}
else
{
@ -1577,29 +1577,23 @@ int32_t scap_bpf_load(
}
}
if(online_cpu >= handle->m_dev_set.m_ndevs)
{
return scap_errprintf(handle->m_lasterr, 0, "too many online processors: %d, expected: %d", online_cpu, handle->m_dev_set.m_ndevs);
}
dev = &handle->m_dev_set.m_devs[online_cpu];
pmu_fd = sys_perf_event_open(&attr, -1, j, -1, 0);
pmu_fd = sys_perf_event_open(&attr, -1, cpu_idx, -1, 0);
if(pmu_fd < 0)
{
return scap_errprintf(handle->m_lasterr, -pmu_fd, "unable to open the perf-buffer for cpu '%d'", j);
return scap_errprintf(handle->m_lasterr, -pmu_fd, "unable to open the perf-buffer for cpu '%d'", cpu_idx);
}
struct scap_device *dev = &devset->m_devs[online_idx];
dev->m_fd = pmu_fd;
if((ret = bpf_map_update_elem(handle->m_bpf_map_fds[SCAP_PERF_MAP], &j, &pmu_fd, BPF_ANY)) != 0)
if((ret = bpf_map_update_elem(handle->m_bpf_map_fds[SCAP_PERF_MAP], &cpu_idx, &pmu_fd, BPF_ANY)) != 0)
{
return scap_errprintf(handle->m_lasterr, -ret, "unable to update the SCAP_PERF_MAP map for cpu '%d'", j);
return scap_errprintf(handle->m_lasterr, -ret, "unable to update the SCAP_PERF_MAP map for cpu '%d'", cpu_idx);
}
if(ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0))
{
return scap_errprintf(handle->m_lasterr, errno, "unable to call PERF_EVENT_IOC_ENABLE on the fd for cpu '%d'", j);
return scap_errprintf(handle->m_lasterr, errno, "unable to call PERF_EVENT_IOC_ENABLE on the fd for cpu '%d'", cpu_idx);
}
//
@ -1609,16 +1603,28 @@ int32_t scap_bpf_load(
dev->m_buffer_size = bpf_args->buffer_bytes_dim;
if(dev->m_buffer == MAP_FAILED)
{
return scap_errprintf(handle->m_lasterr, errno, "unable to mmap the perf-buffer for cpu '%d'", j);
return scap_errprintf(handle->m_lasterr, errno, "unable to mmap the perf-buffer for cpu '%d'", cpu_idx);
}
++online_cpu;
online_idx++;
}
if(online_cpu != handle->m_dev_set.m_ndevs)
// Check that we parsed all online CPUs
if(online_idx != devset->m_ndevs)
{
return scap_errprintf(handle->m_lasterr, 0, "processors online: %d, expected: %d", online_cpu, handle->m_dev_set.m_ndevs);
return scap_errprintf(handle->m_lasterr, 0, "mismatch, processors online after the 'for' loop: %d, '_SC_NPROCESSORS_ONLN' before the 'for' loop: %d", online_idx, devset->m_ndevs);
}
// Check that no CPUs were hotplugged during the for loop
uint32_t final_ndevs = sysconf(_SC_NPROCESSORS_ONLN);
if(final_ndevs == -1)
{
return scap_errprintf(handle->m_lasterr, errno, "cannot obtain the number of online CPUs from '_SC_NPROCESSORS_ONLN' to check against the previous value");
}
if (online_idx != final_ndevs)
{
return scap_errprintf(handle->m_lasterr, 0, "mismatch, processors online after the 'for' loop: %d, '_SC_NPROCESSORS_ONLN' after the 'for' loop: %d", online_idx, final_ndevs);
}
if(set_default_settings(handle) != SCAP_SUCCESS)
{
@ -1945,7 +1951,7 @@ static int32_t init(scap_t* handle, scap_open_args *oargs)
ssize_t num_cpus = sysconf(_SC_NPROCESSORS_CONF);
if(num_cpus == -1)
{
return scap_errprintf(engine.m_handle->m_lasterr, errno, "_SC_NPROCESSORS_CONF");
return scap_errprintf(engine.m_handle->m_lasterr, errno, "cannot obtain the number of available CPUs from '_SC_NPROCESSORS_CONF'");
}
engine.m_handle->m_ncpus = num_cpus;
@ -1953,7 +1959,7 @@ static int32_t init(scap_t* handle, scap_open_args *oargs)
ssize_t num_devs = sysconf(_SC_NPROCESSORS_ONLN);
if(num_devs == -1)
{
return scap_errprintf(engine.m_handle->m_lasterr, errno, "_SC_NPROCESSORS_ONLN");
return scap_errprintf(engine.m_handle->m_lasterr, errno, "cannot obtain the number of online CPUs from '_SC_NPROCESSORS_ONLN'");
}
rc = devset_init(&engine.m_handle->m_dev_set, num_devs, engine.m_handle->m_lasterr);

View File

@ -336,7 +336,7 @@ int32_t scap_kmod_init(scap_t *handle, scap_open_args *oargs)
ncpus = sysconf(_SC_NPROCESSORS_CONF);
if(ncpus == -1)
{
return scap_errprintf(handle->m_lasterr, errno, "_SC_NPROCESSORS_CONF");
return scap_errprintf(handle->m_lasterr, errno, "cannot obtain the number of available CPUs from '_SC_NPROCESSORS_CONF'");
}
//
@ -345,7 +345,7 @@ int32_t scap_kmod_init(scap_t *handle, scap_open_args *oargs)
ndevs = sysconf(_SC_NPROCESSORS_ONLN);
if(ndevs == -1)
{
return scap_errprintf(handle->m_lasterr, errno, "_SC_NPROCESSORS_ONLN");
return scap_errprintf(handle->m_lasterr, errno, "cannot obtain the number of online CPUs from '_SC_NPROCESSORS_ONLN'");
}
rc = devset_init(&engine.m_handle->m_dev_set, ndevs, handle->m_lasterr);
@ -360,14 +360,17 @@ int32_t scap_kmod_init(scap_t *handle, scap_open_args *oargs)
mapped_len = single_buffer_dim * 2;
struct scap_device_set *devset = &engine.m_handle->m_dev_set;
for(uint32_t j = 0, all_scanned_devs = 0; j < devset->m_ndevs && all_scanned_devs < ncpus; ++all_scanned_devs)
uint32_t online_idx = 0;
// devset->m_ndevs = online CPUs in the system.
// ncpus = available CPUs in the system.
for(uint32_t cpu_idx = 0; online_idx < devset->m_ndevs && cpu_idx < ncpus; ++cpu_idx)
{
struct scap_device *dev = &devset->m_devs[j];
struct scap_device *dev = &devset->m_devs[online_idx];
//
// Open the device
//
snprintf(filename, sizeof(filename), "%s/dev/" DRIVER_DEVICE_NAME "%d", scap_get_host_root(), all_scanned_devs);
snprintf(filename, sizeof(filename), "%s/dev/" DRIVER_DEVICE_NAME "%d", scap_get_host_root(), cpu_idx);
if((dev->m_fd = open(filename, O_RDWR | O_SYNC)) < 0)
{
@ -489,7 +492,24 @@ int32_t scap_kmod_init(scap_t *handle, scap_open_args *oargs)
}
dev->m_bufinfo_size = sizeof(struct ppm_ring_buffer_info);
++j;
++online_idx;
}
// Check that we parsed all online CPUs
if(online_idx != devset->m_ndevs)
{
return scap_errprintf(handle->m_lasterr, 0, "mismatch, processors online after the 'for' loop: %d, '_SC_NPROCESSORS_ONLN' before the 'for' loop: %d", online_idx, devset->m_ndevs);
}
// Check that no CPUs were hotplugged during the for loop
uint32_t final_ndevs = sysconf(_SC_NPROCESSORS_ONLN);
if(final_ndevs == -1)
{
return scap_errprintf(handle->m_lasterr, errno, "cannot obtain the number of online CPUs from '_SC_NPROCESSORS_ONLN' to check against the previous value");
}
if (online_idx != final_ndevs)
{
return scap_errprintf(handle->m_lasterr, 0, "mismatch, processors online after the 'for' loop: %d, '_SC_NPROCESSORS_ONLN' after the 'for' loop: %d", online_idx, final_ndevs);
}
/* Here we are covering the case in which some syscalls don't have an associated ppm_sc

View File

@ -1580,14 +1580,18 @@ static uint32_t scap_fd_read_from_disk(scap_fdinfo *fdi, size_t *nbytes, uint32_
case SCAP_FD_BPF:
case SCAP_FD_USERFAULTFD:
case SCAP_FD_IOURING:
case SCAP_FD_MEMFD:
case SCAP_FD_PIDFD:
res = scap_fd_read_fname_from_disk(fdi->info.fname, nbytes, r, error);
break;
case SCAP_FD_UNKNOWN:
ASSERT(false);
break;
default:
snprintf(error, SCAP_LASTERR_SIZE, "error reading the fd info from file, wrong fd type %u", (uint32_t)fdi->type);
return SCAP_FAILURE;
// unknown fd type, possibly coming from a newer library version
fdi->type = SCAP_FD_UNSUPPORTED;
snprintf(fdi->info.fname, sizeof(fdi->info.fname), "unknown-type:[%d]", (int)type);
break;
}
if(sub_len && *nbytes != sub_len)

View File

@ -145,8 +145,12 @@ static int close_engine(struct scap_engine_handle engine)
{
struct source_plugin_engine *handle = engine.m_handle;
handle->m_input_plugin->close(handle->m_input_plugin->state, handle->m_input_plugin->handle);
handle->m_input_plugin->handle = NULL;
// We could arrive here without having initialized 'm_input_plugin'.
if(handle->m_input_plugin != NULL)
{
handle->m_input_plugin->close(handle->m_input_plugin->state, handle->m_input_plugin->handle);
handle->m_input_plugin->handle = NULL;
}
return SCAP_SUCCESS;
}

View File

@ -1,2 +1,2 @@
add_library(scap_platform STATIC scap_linux_platform.c scap_procs.c scap_fds.c scap_userlist.c scap_iflist.c scap_cgroup.c)
add_library(scap_platform STATIC scap_linux_platform.c scap_procs.c scap_fds.c scap_userlist.c scap_iflist.c scap_cgroup.c scap_machine_info.c)
target_link_libraries(scap_platform scap_error scap_platform_util)

View File

@ -259,11 +259,20 @@ static const char* scan_back(const char* start, const char* end)
// slash so that we don't end up with doubled slashes (one from the prefix, one from the path)
static int32_t scap_cgroup_prefix_path(const char* prefix, const char* path, size_t* prefix_len, size_t* path_strip_len)
{
ASSERT(prefix != NULL);
ASSERT(path != NULL);
const char* prefix_p = prefix + strlen(prefix);
const char* path_p = path;
while(strncmp(path_p, "/..", 3) == 0)
{
// If there's a trailing slash, remove it before scanning.
if (*prefix_p == '/' && prefix_p != prefix)
{
prefix_p--;
}
path_p += 3;
prefix_p = scan_back(prefix, prefix_p);
if(prefix_p == NULL)
@ -527,7 +536,7 @@ static int32_t get_cgroup_subsystems_v2(struct scap_cgroup_interface* cgi, struc
if(cgi->m_use_cache)
{
struct scap_cgroup_cache* cached = malloc(sizeof(*cached));
struct scap_cgroup_cache* cached = (struct scap_cgroup_cache*)malloc(sizeof(*cached));
if(cached)
{
int uth_status = SCAP_SUCCESS;

View File

@ -323,6 +323,10 @@ int32_t scap_fd_handle_regular_file(struct scap_proclist *proclist, char *fname,
{
fdi->type = SCAP_FD_BPF;
}
else if (0 == strcmp(link_name, "anon_inode:[pidfd]"))
{
fdi->type = SCAP_FD_PIDFD;
}
if(SCAP_FD_UNSUPPORTED == fdi->type)
{
@ -333,8 +337,16 @@ int32_t scap_fd_handle_regular_file(struct scap_proclist *proclist, char *fname,
}
else if(fdi->type == SCAP_FD_FILE_V2)
{
scap_fd_flags_file(fdi, procdir);
strlcpy(fdi->info.regularinfo.fname, link_name, sizeof(fdi->info.regularinfo.fname));
if (0 == strncmp(link_name, "/memfd:", strlen("/memfd:")))
{
fdi->type = SCAP_FD_MEMFD;
strlcpy(fdi->info.fname, link_name, sizeof(fdi->info.fname));
}
else
{
scap_fd_flags_file(fdi, procdir);
strlcpy(fdi->info.regularinfo.fname, link_name, sizeof(fdi->info.regularinfo.fname));
}
}
else
{

View File

@ -37,6 +37,11 @@ struct scap_linux_platform;
struct scap_proclist;
typedef struct scap_threadinfo scap_threadinfo;
typedef struct _scap_agent_info scap_agent_info;
typedef struct _scap_machine_info scap_machine_info;
void scap_os_get_agent_info(scap_agent_info* agent_info);
int32_t scap_os_get_machine_info(scap_machine_info* machine_info, char* lasterr);
int32_t scap_linux_create_iflist(struct scap_platform* platform);
int32_t scap_linux_create_userlist(struct scap_platform* platform);

View File

@ -62,6 +62,13 @@ int32_t scap_linux_init_platform(struct scap_platform* platform, char* lasterr,
linux_platform->m_proc_scan_log_interval_ms = oargs->proc_scan_log_interval_ms;
linux_platform->m_debug_log_fn = oargs->debug_log_fn;
if(scap_os_get_machine_info(&platform->m_machine_info, lasterr) != SCAP_SUCCESS)
{
return SCAP_FAILURE;
}
scap_os_get_agent_info(&platform->m_agent_info);
rc = scap_linux_create_iflist(platform);
if(rc != SCAP_SUCCESS)
{

View File

@ -16,7 +16,7 @@ limitations under the License.
*/
#include "scap_machine_info.h"
#include "scap_os_machine_info.h"
#include "scap_linux_int.h"
#include "scap_limits.h"
#include "scap_assert.h"
#include "scap.h"
@ -106,7 +106,6 @@ static uint64_t scap_linux_get_host_boot_time_ns(char* last_err)
FILE* f = fopen(proc_stat, "r");
if (f == NULL)
{
ASSERT(false);
return 0;
}
@ -119,7 +118,6 @@ static uint64_t scap_linux_get_host_boot_time_ns(char* last_err)
}
}
fclose(f);
ASSERT(false);
return 0;
}
@ -156,6 +154,28 @@ static void scap_gethostname(char* buf, size_t size)
int32_t scap_os_get_machine_info(scap_machine_info* machine_info, char* lasterr)
{
// Check that we can read under '/proc'.
// A wrong usage of the env variable 'HOST_ROOT' can be detected here.
char filename[SCAP_MAX_PATH_SIZE] = {0};
if(snprintf(filename, sizeof(filename), "%s/proc/", scap_get_host_root()) < 0)
{
if(lasterr != NULL)
{
snprintf(lasterr, SCAP_LASTERR_SIZE, "unable to build the `/proc` path with 'snprintf'\n");
}
return SCAP_FAILURE;
}
struct stat targetstat = {0};
if(stat(filename, &targetstat) != 0)
{
if(lasterr != NULL)
{
snprintf(lasterr, SCAP_LASTERR_SIZE, "the directory '%s' doesn't exist on the system. Check the usage of the 'HOST_ROOT' env variable.", filename);
}
return SCAP_FAILURE;
}
machine_info->num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
machine_info->memory_size_bytes = (uint64_t)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE);
scap_gethostname(machine_info->hostname, sizeof(machine_info->hostname));
@ -168,4 +188,3 @@ int32_t scap_os_get_machine_info(scap_machine_info* machine_info, char* lasterr)
return SCAP_SUCCESS;
}

View File

@ -1,123 +0,0 @@
/*
Copyright (C) 2023 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 "scap_machine_info.h"
#include "scap_os_machine_info.h"
#include "scap_limits.h"
#include "scap_assert.h"
#include "scap.h"
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/utsname.h>
#include <time.h>
#include <unistd.h>
#define US_TO_NS 1000ULL
// https://stackoverflow.com/questions/3269321/osx-programmatically-get-uptime
static uint64_t scap_macos_get_host_boot_time_ns()
{
struct timeval boottime;
size_t len = sizeof(boottime);
int mib[2] = { CTL_KERN, KERN_BOOTTIME };
if(sysctl(mib, 2, &boottime, &len, NULL, 0) < 0)
{
return 0;
}
return (boottime.tv_sec * SECOND_TO_NS) +
(boottime.tv_usec * US_TO_NS);
}
void scap_os_get_agent_info(scap_agent_info* agent_info)
{
agent_info->start_ts_epoch = 0;
agent_info->start_time = 0;
/* Info 1:
*
* unix time in nsec of our startup time
*/
{
// https://stackoverflow.com/questions/31603885/get-process-creation-date-time-in-osx-with-c-c/31605649
struct kinfo_proc info;
int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, (int)getpid() };
size_t len = sizeof info;
memset(&info, 0, len);
int rc = sysctl(mib, 4, &info, &len, NULL, 0);
if(rc == 0)
{
struct timeval tv = info.kp_proc.p_starttime;
if(tv.tv_sec != 0)
{
agent_info->start_ts_epoch = (tv.tv_sec * SECOND_TO_NS) +
(tv.tv_usec * US_TO_NS);
}
}
}
/* Info 2:
*
* our startup time in seconds since boot
*/
if(agent_info->start_ts_epoch != 0)
{
uint64_t boot_time_ns = scap_macos_get_host_boot_time_ns();
agent_info->start_time = (agent_info->start_ts_epoch - boot_time_ns) / (1.0 * SECOND_TO_NS);
}
/* Info 3:
*
* Kernel release `uname -r` of the machine the agent is running on.
*/
struct utsname uts;
uname(&uts);
snprintf(agent_info->uname_r, sizeof(agent_info->uname_r), "%s", uts.release);
}
static void scap_gethostname(char* buf, size_t size)
{
char *env_hostname = getenv(SCAP_HOSTNAME_ENV_VAR);
if(env_hostname != NULL)
{
snprintf(buf, size, "%s", env_hostname);
}
else
{
gethostname(buf, size);
}
}
int32_t scap_os_get_machine_info(scap_machine_info* machine_info, char* lasterr)
{
machine_info->num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
machine_info->memory_size_bytes = (uint64_t)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE);
scap_gethostname(machine_info->hostname, sizeof(machine_info->hostname));
machine_info->boot_ts_epoch = scap_macos_get_host_boot_time_ns();
if(machine_info->boot_ts_epoch == 0)
{
return SCAP_FAILURE;
}
return SCAP_SUCCESS;
}

View File

@ -175,10 +175,13 @@ int32_t scap_init(scap_t* handle, scap_open_args* oargs)
platform = scap_linux_alloc_platform();
struct scap_nodriver_engine_params* engine_params = oargs->engine_params;
if(platform && (!engine_params || !engine_params->full_proc_scan))
if(platform)
{
((struct scap_linux_platform*)platform)->m_fd_lookup_limit = SCAP_NODRIVER_MAX_FD_LOOKUP;
((struct scap_linux_platform*)platform)->m_minimal_scan = true;
if(!engine_params || !engine_params->full_proc_scan)
{
((struct scap_linux_platform*)platform)->m_fd_lookup_limit = SCAP_NODRIVER_MAX_FD_LOOKUP;
((struct scap_linux_platform*)platform)->m_minimal_scan = true;
}
}
else
{

View File

@ -1,32 +0,0 @@
/*
Copyright (C) 2023 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.
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
typedef struct _scap_agent_info scap_agent_info;
typedef struct _scap_machine_info scap_machine_info;
void scap_os_get_agent_info(scap_agent_info* agent_info);
int32_t scap_os_get_machine_info(scap_machine_info* machine_info, char* lasterr);
#ifdef __cplusplus
}
#endif

View File

@ -21,18 +21,11 @@ limitations under the License.
#include "scap.h"
#include "scap-int.h"
#include "scap_os_machine_info.h"
int32_t scap_generic_init_platform(struct scap_platform* platform, char* lasterr, struct scap_open_args* oargs)
{
memset(&platform->m_machine_info, 0, sizeof(platform->m_machine_info));
if(scap_os_get_machine_info(&platform->m_machine_info, lasterr) != SCAP_SUCCESS)
{
return SCAP_FAILURE;
}
scap_os_get_agent_info(&platform->m_agent_info);
memset(&platform->m_agent_info, 0, sizeof(platform->m_agent_info));
platform->m_proclist.m_proc_callback = oargs->proc_callback;
platform->m_proclist.m_proc_callback_context = oargs->proc_callback_context;
platform->m_proclist.m_proclist = NULL;

View File

@ -198,6 +198,8 @@ static uint32_t scap_fd_info_len(scap_fdinfo *fdi)
case SCAP_FD_BPF:
case SCAP_FD_USERFAULTFD:
case SCAP_FD_IOURING:
case SCAP_FD_MEMFD:
case SCAP_FD_PIDFD:
res += (uint32_t)strnlen(fdi->info.fname, SCAP_MAX_PATH_SIZE) + 2; // 2 is the length field before the string
break;
default:
@ -312,6 +314,8 @@ static int32_t scap_fd_write_to_disk(scap_dumper_t *d, scap_fdinfo *fdi, uint32_
case SCAP_FD_BPF:
case SCAP_FD_USERFAULTFD:
case SCAP_FD_IOURING:
case SCAP_FD_MEMFD:
case SCAP_FD_PIDFD:
stlen = (uint16_t)strnlen(fdi->info.fname, SCAP_MAX_PATH_SIZE);
if(scap_dump_write(d, &stlen, sizeof(uint16_t)) != sizeof(uint16_t) ||
(stlen > 0 && scap_dump_write(d, fdi->info.fname, stlen) != stlen))

View File

@ -1,152 +0,0 @@
/*
Copyright (C) 2023 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.
*/
#ifndef _UNICODE
#define _UNICODE
#endif
#include "scap_machine_info.h"
#include "scap_os_machine_info.h"
#include "scap_limits.h"
#include "scap_assert.h"
#include "scap.h"
#include "gettimeofday.h"
#include <stdbool.h>
#include <stdio.h>
#include <windows.h>
#include <tchar.h>
#define MSEC_TO_NS 1000000
typedef LONG (WINAPI * RtlGetVersionProc) (OSVERSIONINFOEX *);
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS 0
#endif
// https://stackoverflow.com/questions/10853985/programmatically-getting-system-boot-up-time-in-c-windows
static uint64_t scap_windows_get_host_boot_time_ns()
{
return GetTickCount64() * MSEC_TO_NS;
}
void scap_os_get_agent_info(scap_agent_info* agent_info)
{
agent_info->start_ts_epoch = 0;
agent_info->start_time = 0;
/* Info 1:
*
* unix time in nsec of our startup time
*/
{
FILETIME creation_time, exit_time, kernel_time, user_time;
if(GetProcessTimes(GetCurrentProcess(), &creation_time, &exit_time, &kernel_time, &user_time))
{
agent_info->start_ts_epoch = ft_to_epoch_nsec(&creation_time);
}
}
/* Info 2:
*
* our startup time in seconds since boot
*/
if(agent_info->start_ts_epoch != 0)
{
uint64_t boot_time_ns = scap_windows_get_host_boot_time_ns();
agent_info->start_time = (agent_info->start_ts_epoch - boot_time_ns) / (1.0 * SECOND_TO_NS);
}
/* Info 3:
*
* Kernel release `uname -r` of the machine the agent is running on.
*/
{
OSVERSIONINFOEX win_version_info = {0};
RtlGetVersionProc RtlGetVersionP = 0;
LONG version_status = -1; // Any nonzero value should work.
/*
* We want the major and minor Windows version along with other
* information. GetVersionEx provides this, but is deprecated.
* We use RtlGetVersion instead, which requires a bit of extra
* effort.
*/
HMODULE ntdll_module = LoadLibrary(_T("ntdll.dll"));
if(ntdll_module)
{
RtlGetVersionP = (RtlGetVersionProc) GetProcAddress(ntdll_module, "RtlGetVersion");
win_version_info.dwOSVersionInfoSize = sizeof(win_version_info);
version_status = RtlGetVersionP(&win_version_info);
FreeLibrary(ntdll_module);
}
if (version_status != STATUS_SUCCESS)
{
snprintf(agent_info->uname_r, sizeof(agent_info->uname_r), "Windows (unknown version)");
}
else
{
// more space than the absolute worst case of UTF16->UTF8 conversion
char utf8_servicepack[sizeof(win_version_info.szCSDVersion) * 2] = {0};
// ... but if it still gets truncated, be sad for a while and move on
// (our output buffer is finite, anyway)
WideCharToMultiByte(CP_UTF8, 0, win_version_info.szCSDVersion, -1, utf8_servicepack, sizeof(utf8_servicepack), NULL, NULL);
snprintf(agent_info->uname_r, sizeof(agent_info->uname_r), "Windows %lu.%lu%s%s, build %lu",
win_version_info.dwMajorVersion, win_version_info.dwMinorVersion,
utf8_servicepack[0] != '\0' ? " " : "",
utf8_servicepack,
win_version_info.dwBuildNumber);
}
}
}
static void scap_gethostname(char* buf, size_t size)
{
char *env_hostname = getenv(SCAP_HOSTNAME_ENV_VAR);
if(env_hostname != NULL)
{
snprintf(buf, size, "%s", env_hostname);
}
else
{
gethostname(buf, size);
}
}
int32_t scap_os_get_machine_info(scap_machine_info* machine_info, char* lasterr)
{
SYSTEM_INFO si;
GetSystemInfo(&si);
machine_info->num_cpus = si.dwNumberOfProcessors;
ULONGLONG mem_kb;
GetPhysicallyInstalledSystemMemory(&mem_kb);
machine_info->memory_size_bytes = mem_kb * 1024;
scap_gethostname(machine_info->hostname, sizeof(machine_info->hostname));
machine_info->boot_ts_epoch = scap_windows_get_host_boot_time_ns();
if(machine_info->boot_ts_epoch == 0)
{
return SCAP_FAILURE;
}
return SCAP_SUCCESS;
}

View File

@ -672,6 +672,7 @@ bool docker_async_source::parse(const docker_lookup_request& request, sinsp_cont
}
/* FALLTHRU */
case docker_connection::docker_response::RESP_ERROR:
case docker_connection::docker_response::RESP_TIMEOUT:
g_logger.format(sinsp_logger::SEV_DEBUG,
"docker_async (%s): Url fetch failed, returning false",
request.container_id.c_str());

View File

@ -18,7 +18,8 @@ public:
enum docker_response {
RESP_OK = 0,
RESP_BAD_REQUEST = 1,
RESP_ERROR = 2
RESP_ERROR = 2,
RESP_TIMEOUT = 3
};
docker_connection();

View File

@ -20,6 +20,7 @@ limitations under the License.
#include "sinsp_int.h"
namespace {
const uint32_t max_allowed_timeouts = 5;
size_t docker_curl_write_callback(const char *ptr, size_t size, size_t nmemb, std::string *json)
{
@ -107,6 +108,7 @@ docker_connection::docker_response docker_connection::get_docker(const docker_lo
return docker_response::RESP_ERROR;
}
uint32_t num_timeouts = 0;
while(true)
{
int still_running;
@ -141,6 +143,21 @@ docker_connection::docker_response docker_connection::get_docker(const docker_lo
ASSERT(false);
return docker_response::RESP_ERROR;
}
if(numfds == 0)
{
// Operation timed out
if(++num_timeouts >= max_allowed_timeouts)
{
g_logger.format(sinsp_logger::SEV_WARNING,
"docker_async (%s): Max timeouts exceeded",
url.c_str());
return docker_response::RESP_TIMEOUT;
}
g_logger.format(sinsp_logger::SEV_DEBUG,
"docker_async (%s): Operation timed out %d times",
url.c_str(),
num_timeouts);
}
}
if(curl_multi_remove_handle(m_curlm, curl) != CURLM_OK)

View File

@ -2656,6 +2656,8 @@ void sinsp_evt::get_category(OUT sinsp_evt::category* cat)
case SCAP_FD_BPF:
case SCAP_FD_IOURING:
case SCAP_FD_NETLINK:
case SCAP_FD_MEMFD:
case SCAP_FD_PIDFD:
cat->m_subcategory = SC_OTHER;
break;
case SCAP_FD_UNKNOWN:

View File

@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <chrono>
#ifndef _WIN32
@ -22,6 +23,7 @@ limitations under the License.
#include <csignal>
#include <sinsp.h>
#include <functional>
#include <memory>
#include "util.h"
#include "filter/ppm_codes.h"
#include <unordered_set>
@ -40,13 +42,11 @@ using namespace std;
// Functions used for dumping to stdout
void plaintext_dump(sinsp& inspector);
void json_dump(sinsp& inspector);
void json_dump_init(sinsp& inspector);
void json_dump_reinit_evt_formatter(sinsp& inspector);
void raw_dump(sinsp&, sinsp_evt* ev);
void formatted_dump(sinsp&, sinsp_evt* ev);
libsinsp::events::set<ppm_sc_code> extract_filter_sc_codes(sinsp& inspector);
std::function<void(sinsp& inspector)> dump;
std::function<void(sinsp&, sinsp_evt*)> dump = formatted_dump;
static bool g_interrupted = false;
static const uint8_t g_backoff_timeout_secs = 2;
static bool g_all_threads = false;
@ -54,20 +54,27 @@ static bool ppm_sc_modifies_state = false;
static bool ppm_sc_repair_state = false;
static bool ppm_sc_state_remove_io_sc = false;
static bool enable_glogger = false;
static bool json_dump_init_success = false;
string engine_string = KMOD_ENGINE; /* Default for backward compatibility. */
string filter_string = "";
string file_path = "";
string bpf_path = "";
string output_fields_json = "";
unsigned long buffer_bytes_dim = DEFAULT_DRIVER_BUFFER_BYTES_DIM;
static uint64_t max_events = UINT64_MAX;
sinsp_evt* get_event(sinsp& inspector);
sinsp_evt* get_event(sinsp& inspector, std::function<void(const std::string&)> handle_error);
#define PROCESS_DEFAULTS "*%evt.num %evt.time %evt.category %container.id %proc.ppid %proc.pid %evt.type %proc.exe %proc.cmdline %evt.args"
#define EVENT_HEADER "%evt.num %evt.time cat=%evt.category container=%container.id proc=%proc.name(%proc.pid.%thread.tid) "
#define EVENT_TRAILER "%evt.dir %evt.type %evt.args"
#define EVENT_DEFAULTS EVENT_HEADER EVENT_TRAILER
#define PROCESS_DEFAULTS EVENT_HEADER "ppid=%proc.ppid exe=%proc.exe args=[%proc.cmdline] " EVENT_TRAILER
#define JSON_PROCESS_DEFAULTS "*%evt.num %evt.time %evt.category %container.id %proc.ppid %proc.pid %evt.type %proc.exe %proc.cmdline %evt.args"
std::string default_output = EVENT_DEFAULTS;
std::string process_output = PROCESS_DEFAULTS;
std::string net_output = PROCESS_DEFAULTS " %fd.name";
// Formatters used with JSON output
static std::unique_ptr<sinsp_evt_formatter> default_formatter = nullptr;
static std::unique_ptr<sinsp_evt_formatter> process_formatter = nullptr;
static std::unique_ptr<sinsp_evt_formatter> net_formatter = nullptr;
@ -93,13 +100,14 @@ Options:
-k, --kmod Kernel module
-s <path>, --scap_file <path> Scap file
-d <dim>, --buffer_dim <dim> Dimension in bytes that every per-CPU buffer will have.
-o <fields>, --output-fields-json <fields> [JSON support only, can also use without -j] Output fields string (see <filter> for supported display fields) that overwrites JSON default output fields for all events. * at the beginning prints JSON keys with null values, else no null fields are printed.
-o <fields>, --output-fields <fields> Output fields string (see <filter> for supported display fields) that overwrites default output fields for all events. * at the beginning prints JSON keys with null values, else no null fields are printed.
-E, --exclude-users Don't create the user/group tables
-n, --num-events Number of events to be retrieved (no limit by default)
-z, --ppm-sc-modifies-state Select ppm sc codes from filter AST plus enforce sinsp state ppm sc codes via `sinsp_state_sc_set`, requires valid filter expression.
-x, --ppm-sc-repair-state Select ppm sc codes from filter AST plus enforce sinsp state ppm sc codes via `sinsp_repair_state_sc_set`, requires valid filter expression.
-q, --remove-io-sc-state Remove ppm sc codes belonging to `io_sc_set` from `sinsp_state_sc_set` sinsp state enforcement, defaults to false and only applies when choosing `-z` option, used for e2e testing of sinsp state.
-g, --enable-glogger Enable libs g_logger, set to SEV_DEBUG. For a different severity adjust the test binary source and re-compile.
-r, --raw raw event ouput
)";
cout << usage << endl;
}
@ -118,19 +126,21 @@ void parse_CLI_options(sinsp& inspector, int argc, char** argv)
{"kmod", no_argument, 0, 'k'},
{"scap_file", required_argument, 0, 's'},
{"buffer_dim", required_argument, 0, 'd'},
{"output-fields-json", required_argument, 0, 'o'},
{"output-fields", required_argument, 0, 'o'},
{"exclude-users", no_argument, 0, 'E'},
{"num-events", required_argument, 0, 'n'},
{"ppm-sc-modifies-state", no_argument, 0, 'z'},
{"ppm-sc-repair-state", no_argument, 0, 'x'},
{"remove-io-sc-state", no_argument, 0, 'q'},
{"enable-glogger", no_argument, 0, 'g'},
{"raw", no_argument, 0, 'r'},
{0, 0, 0, 0}};
bool format_set = false;
int op;
int long_index = 0;
while((op = getopt_long(argc, argv,
"hf:jab:mks:d:o:En:zxqg",
"hf:jab:mks:d:o:En:zxqgr",
long_options, &long_index)) != -1)
{
switch(op)
@ -142,7 +152,14 @@ void parse_CLI_options(sinsp& inspector, int argc, char** argv)
filter_string = optarg;
break;
case 'j':
json_dump_init(inspector);
dump = formatted_dump;
if(!format_set)
{
default_output = DEFAULT_OUTPUT_STR;
process_output = JSON_PROCESS_DEFAULTS;
net_output = JSON_PROCESS_DEFAULTS " %fd.name";
}
inspector.set_buffer_format(sinsp_evt::PF_JSON);
break;
case 'a':
g_all_threads = true;
@ -165,9 +182,10 @@ void parse_CLI_options(sinsp& inspector, int argc, char** argv)
buffer_bytes_dim = strtoul(optarg, NULL, 10);
break;
case 'o':
output_fields_json = optarg;
json_dump_init(inspector);
json_dump_reinit_evt_formatter(inspector);
default_output = optarg;
process_output = optarg;
net_output = optarg;
format_set = true;
break;
case 'E':
inspector.set_import_users(false);
@ -187,6 +205,8 @@ void parse_CLI_options(sinsp& inspector, int argc, char** argv)
case 'g':
enable_glogger = true;
break;
case 'r':
dump = raw_dump;
default:
break;
}
@ -341,7 +361,6 @@ error:
int main(int argc, char** argv)
{
sinsp inspector;
dump = plaintext_dump;
#ifndef _WIN32
parse_CLI_options(inspector, argc, argv);
@ -393,12 +412,25 @@ int main(int argc, char** argv)
inspector.start_capture();
default_formatter = std::make_unique<sinsp_evt_formatter>(&inspector, default_output);
process_formatter = std::make_unique<sinsp_evt_formatter>(&inspector, process_output);
net_formatter = std::make_unique<sinsp_evt_formatter>(&inspector, net_output);
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
uint64_t num_events = 0;
while(!g_interrupted && num_events < max_events)
{
dump(inspector);
num_events++;
sinsp_evt* ev = get_event(inspector, [](const std::string& error_msg)
{ cout << "[ERROR] " << error_msg << endl; });
if(ev != nullptr)
{
sinsp_threadinfo* thread = ev->get_thread_info();
if(!thread || g_all_threads || thread->is_main_thread())
{
dump(inspector, ev);
num_events++;
}
}
}
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
const auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count();
@ -442,146 +474,16 @@ sinsp_evt* get_event(sinsp& inspector, std::function<void(const std::string&)> h
return nullptr;
}
void plaintext_dump(sinsp& inspector)
void formatted_dump(sinsp&, sinsp_evt* ev)
{
sinsp_evt* ev = get_event(inspector, [](const std::string& error_msg)
{ cout << "[ERROR] " << error_msg << endl; });
if(ev == nullptr)
{
return;
}
sinsp_threadinfo* thread = ev->get_thread_info();
if(thread)
{
string cmdline;
sinsp_threadinfo::populate_cmdline(cmdline, thread);
if(g_all_threads || thread->is_main_thread())
{
string date_time;
sinsp_utils::ts_to_iso_8601(ev->get_ts(), &date_time);
bool is_host_proc = thread->m_container_id.empty();
cout << "[" << date_time << "]:["
<< (is_host_proc ? "HOST" : thread->m_container_id) << "]:";
cout << "[CAT=";
if(ev->get_category() == EC_PROCESS)
{
cout << "PROCESS]:";
}
else if(ev->get_category() == EC_NET)
{
cout << get_event_category_name(ev->get_category()) << "]:";
sinsp_fdinfo_t* fd_info = ev->get_fd_info();
// event subcategory should contain SC_NET if ipv4/ipv6
if(nullptr != fd_info && (fd_info->get_l4proto() != SCAP_L4_UNKNOWN && fd_info->get_l4proto() != SCAP_L4_NA))
{
cout << "[" << fd_info->tostring() << "]:";
}
}
else if(ev->get_category() == EC_IO_READ || ev->get_category() == EC_IO_WRITE)
{
cout << get_event_category_name(ev->get_category()) << "]:";
sinsp_fdinfo_t* fd_info = ev->get_fd_info();
if(nullptr != fd_info && (fd_info->get_l4proto() != SCAP_L4_UNKNOWN && fd_info->get_l4proto() != SCAP_L4_NA))
{
cout << "[" << fd_info->tostring() << "]:";
}
}
else
{
cout << get_event_category_name(ev->get_category()) << "]:";
}
sinsp_threadinfo* p_thr = thread->get_parent_thread();
int64_t parent_pid = -1;
if(nullptr != p_thr)
{
parent_pid = p_thr->m_pid;
}
cout << "[PPID=" << parent_pid << "]:"
<< "[PID=" << thread->m_pid << "]:"
<< "[TYPE=" << get_event_type_name(inspector, ev) << "]:"
<< "[EXE=" << thread->get_exepath() << "]:"
<< "[CMD=" << cmdline << "]"
<< endl;
}
}
else
{
cout << "[EVENT]:[" << get_event_category_name(ev->get_category()) << "]:"
<< ev->get_name() << endl;
}
}
void json_dump_init(sinsp& inspector)
{
if (!json_dump_init_success)
{
dump = json_dump;
inspector.set_buffer_format(sinsp_evt::PF_JSON);
// Initialize JSON formatters
default_formatter.reset(new sinsp_evt_formatter(&inspector, DEFAULT_OUTPUT_STR));
process_formatter.reset(new sinsp_evt_formatter(&inspector, PROCESS_DEFAULTS));
net_formatter.reset(new sinsp_evt_formatter(&inspector, PROCESS_DEFAULTS " %fd.name"));
json_dump_init_success = true;
}
}
void json_dump_reinit_evt_formatter(sinsp& inspector)
{
if (!output_fields_json.empty() && json_dump_init_success)
{
default_formatter.reset(new sinsp_evt_formatter(&inspector, output_fields_json));
process_formatter.reset(new sinsp_evt_formatter(&inspector, output_fields_json));
net_formatter.reset(new sinsp_evt_formatter(&inspector, output_fields_json));
}
}
void json_dump(sinsp& inspector)
{
sinsp_evt* ev = get_event(inspector, [](const std::string& error_msg)
{ cout << R"({"error": ")" << error_msg << R"("})" << endl; });
if(ev == nullptr)
{
return;
}
std::string output;
sinsp_threadinfo* thread = ev->get_thread_info();
if(thread)
if(ev->get_category() == EC_PROCESS)
{
if(g_all_threads || thread->is_main_thread())
{
if(ev->get_category() == EC_PROCESS)
{
process_formatter->tostring(ev, output);
}
else if(ev->get_category() == EC_NET || ev->get_category() == EC_IO_READ || ev->get_category() == EC_IO_WRITE)
{
net_formatter->tostring(ev, output);
}
else
{
default_formatter->tostring(ev, output);
}
}
else
{
// Prevent empty lines from being printed
return;
}
process_formatter->tostring(ev, output);
}
else if(ev->get_category() == EC_NET || ev->get_category() == EC_IO_READ || ev->get_category() == EC_IO_WRITE)
{
net_formatter->tostring(ev, output);
}
else
{
@ -590,3 +492,67 @@ void json_dump(sinsp& inspector)
cout << output << std::endl;
}
static void hexdump(const unsigned char* buf, size_t len)
{
bool in_ascii = false;
putc('[', stdout);
for(size_t i = 0; i < len; ++i)
{
if(isprint(buf[i]))
{
if(!in_ascii)
{
in_ascii = true;
if(i > 0)
{
putc(' ', stdout);
}
putc('"', stdout);
}
putc(buf[i], stdout);
}
else
{
if(in_ascii)
{
in_ascii = false;
fputs("\" ", stdout);
}
else if(i > 0)
{
putc(' ', stdout);
}
printf("%02x", buf[i]);
}
}
if(in_ascii)
{
putc('"', stdout);
}
putc(']', stdout);
}
void raw_dump(sinsp& inspector, sinsp_evt* ev)
{
string date_time;
sinsp_utils::ts_to_iso_8601(ev->get_ts(), &date_time);
cout << "ts=" << date_time;
cout << " tid=" << ev->get_tid();
cout << " type=" << (ev->get_direction() == SCAP_ED_IN ? '>' : '<') << get_event_type_name(ev);
cout << " category=" << get_event_category_name(ev->get_category());
cout << " nparams=" << ev->get_num_params();
for(size_t i = 0; i < ev->get_num_params(); ++i)
{
const sinsp_evt_param *p = ev->get_param(i);
const struct ppm_param_info *pi = ev->get_param_info(i);
cout << ' ' << i << ':' << pi->name << '=';
hexdump((const unsigned char*)p->m_val, p->m_len);
}
cout << endl;
}

View File

@ -50,7 +50,7 @@ std::string get_event_category_name(ppm_event_category category)
//
// Get the string representation of a ppm_event_type
//
std::string get_event_type_name(sinsp& inspector, sinsp_evt* ev)
std::string get_event_type_name(sinsp_evt *ev)
{
uint16_t type = ev->get_type();
if (type >= PPM_EVENT_MAX)

View File

@ -25,4 +25,4 @@ std::string get_event_category_name(ppm_event_category category);
//
// Get the string representation of a ppm_event_type
//
std::string get_event_type_name(sinsp& inspector, sinsp_evt* ev);
std::string get_event_type_name(sinsp_evt *ev);

View File

@ -428,6 +428,11 @@ uint8_t* sinsp_filter_check_fspath::extract(sinsp_evt* evt, OUT uint32_t* len, b
{
sinsp_threadinfo* tinfo = evt->get_thread_info();
if(tinfo == NULL)
{
return NULL;
}
std::filesystem::path tstr = tinfo->get_cwd() + m_tstr;
m_tstr = std::filesystem::absolute(tstr).lexically_normal().string();
}
@ -4489,6 +4494,7 @@ int32_t sinsp_filter_check_event::parse_field_name(const char* str, bool alloc_s
res = extract_arg("evt.rawarg", val, &m_arginfo);
m_customfield.m_type = m_arginfo->type;
m_customfield.m_print_format = m_arginfo->fmt;
}
else if(STR_MATCH("evt.around"))
{
@ -5287,6 +5293,21 @@ uint8_t* sinsp_filter_check_event::extract(sinsp_evt *evt, OUT uint32_t* len, bo
case EC_SCHEDULER:
m_strstorage = "scheduler";
break;
case EC_INTERNAL:
m_strstorage = "internal";
break;
case EC_SYSCALL:
m_strstorage = "syscall";
break;
case EC_TRACEPOINT:
m_strstorage = "tracepoint";
break;
case EC_PLUGIN:
m_strstorage = "plugin";
break;
case EC_METAEVENT:
m_strstorage = "meta";
break;
default:
m_strstorage = "unknown";
break;
@ -8563,7 +8584,7 @@ uint8_t* sinsp_filter_check_fdlist::extract(sinsp_evt *evt, OUT uint32_t* len, b
bool add_comma = true;
int64_t fd = *(int64_t *)(payload + pos);
sinsp_fdinfo_t *fdinfo = tinfo->get_fd(fd);
sinsp_fdinfo_t *fdinfo = tinfo ? tinfo->get_fd(fd) : NULL;
switch(m_field_id)
{

View File

@ -2806,7 +2806,15 @@ void sinsp_parser::parse_dirfd(sinsp_evt *evt, char* name, int64_t dirfd, OUT st
}
else if(dirfd == PPM_AT_FDCWD)
{
*sdir = evt->m_tinfo->get_cwd();
if(evt->m_tinfo != NULL)
{
*sdir = evt->m_tinfo->get_cwd();
}
else
{
ASSERT(false);
*sdir = "<UNKNOWN>";
}
}
else
{
@ -6658,7 +6666,7 @@ void sinsp_parser::parse_pidfd_open_exit(sinsp_evt *evt)
/* pid (fd) */
parinfo = evt->get_param(1);
ASSERT(parinfo->m_len == sizeof(int64_t));
ASSERT(evt->get_param_info(0)->type == PT_PID);
ASSERT(evt->get_param_info(1)->type == PT_PID);
pid = *(int64_t *)parinfo->m_val;
/* flags */

View File

@ -494,6 +494,10 @@ void sinsp::open_common(scap_open_args* oargs)
std::string error = scap_getlasterr(m_h);
scap_close(m_h);
m_h = NULL;
if(error.empty())
{
error = "Initialization issues during scap_init";
}
throw scap_open_exception(error, scap_rc);
}
@ -1216,6 +1220,8 @@ int32_t sinsp::next(OUT sinsp_evt **puevt)
sinsp_evt* evt;
int32_t res;
*puevt = NULL;
//
// Check if there are fake cpu events to events
//
@ -1289,8 +1295,6 @@ int32_t sinsp::next(OUT sinsp_evt **puevt)
{
m_external_event_processor->process_event(NULL, libsinsp::EVENT_RETURN_TIMEOUT);
}
*puevt = NULL;
return res;
}
else if(res == SCAP_EOF)
{
@ -1306,8 +1310,7 @@ int32_t sinsp::next(OUT sinsp_evt **puevt)
// In this case, we restart the capture so that the internal states gets reset
// and the blocks coming from the next appended file get consumed.
restart_capture();
return SCAP_TIMEOUT;
res = SCAP_TIMEOUT;
}
else if(res == SCAP_FILTERED_EVENT)
{
@ -1319,8 +1322,6 @@ int32_t sinsp::next(OUT sinsp_evt **puevt)
if(m_external_event_processor)
{
m_external_event_processor->process_event(NULL, libsinsp::EVENT_RETURN_FILTERED);
*puevt = NULL;
return res;
}
}
else
@ -1418,24 +1419,19 @@ int32_t sinsp::next(OUT sinsp_evt **puevt)
// things like exit() or close() can be parsed.
//
uint32_t nfdr = (uint32_t)m_fds_to_remove->size();
if(nfdr != 0)
{
/* This is a removal logic we shouldn't scan /proc. If we don't have the thread
* to remove we are fine.
*/
sinsp_threadinfo* ptinfo = get_thread_ref(m_tid_of_fd_to_remove, false).get();
if(!ptinfo)
if(ptinfo)
{
ASSERT(false);
return res;
for(uint32_t j = 0; j < nfdr; j++)
{
ptinfo->remove_fd(m_fds_to_remove->at(j));
}
}
for(uint32_t j = 0; j < nfdr; j++)
{
ptinfo->remove_fd(m_fds_to_remove->at(j));
}
m_fds_to_remove->clear();
}
@ -1508,6 +1504,9 @@ int32_t sinsp::next(OUT sinsp_evt **puevt)
m_dumper->dump(evt);
}
// Finally set output evt;
// From now on, any return must have the correct output being set.
*puevt = evt;
if(evt->m_filtered_out)
{
ppm_event_category cat = evt->get_category();
@ -1516,7 +1515,6 @@ int32_t sinsp::next(OUT sinsp_evt **puevt)
// mode and the category of this event is internal.
if(!(m_isinternal_events_enabled && (cat & EC_INTERNAL)))
{
*puevt = evt;
return SCAP_FILTERED_EVENT;
}
}
@ -1546,7 +1544,6 @@ int32_t sinsp::next(OUT sinsp_evt **puevt)
//
// Done
//
*puevt = evt;
return res;
}

View File

@ -234,6 +234,11 @@ public:
virtual void open_modern_bpf(unsigned long driver_buffer_bytes_dim = DEFAULT_DRIVER_BUFFER_BYTES_DIM, uint16_t cpus_for_each_buffer = DEFAULT_CPU_FOR_EACH_BUFFER, bool online_only = true, const libsinsp::events::set<ppm_sc_code> &ppm_sc_of_interest = {});
virtual void open_test_input(scap_test_input_data* data, scap_mode_t mode = SCAP_MODE_TEST);
void fseek(uint64_t filepos)
{
scap_fseek(m_h, filepos);
}
scap_open_args factory_open_args(const char* engine_name, scap_mode_t scap_mode);
std::string generate_gvisor_config(std::string socket_path);
@ -1080,11 +1085,6 @@ private:
void restart_capture();
void fseek(uint64_t filepos)
{
scap_fseek(m_h, filepos);
}
void add_suppressed_comms(scap_open_args *oargs);
bool increased_snaplen_port_range_set() const

View File

@ -69,7 +69,7 @@ TEST_F(sinsp_with_test_input, event_hostname)
add_default_init_thread();
open_inspector();
open_inspector(SCAP_MODE_LIVE);
sinsp_evt *evt = NULL;
/* Toy event example from a previous test. */

View File

@ -389,6 +389,8 @@ void sinsp_threadinfo::add_fd_from_scap(scap_fdinfo *fdi, OUT sinsp_fdinfo_t *re
case SCAP_FD_BPF:
case SCAP_FD_USERFAULTFD:
case SCAP_FD_IOURING:
case SCAP_FD_MEMFD:
case SCAP_FD_PIDFD:
newfdi->m_name = fdi->info.fname;
if(newfdi->m_name == USER_EVT_DEVICE_NAME)
@ -953,9 +955,6 @@ std::string sinsp_threadinfo::get_cwd()
else
{
///todo(@Andreagit97) not sure we want to return "./" it seems like a valid path
#if defined(__linux__)
ASSERT(false);
#endif //__linux__
return "./";
}
}
@ -1416,6 +1415,8 @@ void sinsp_threadinfo::fd_to_scap(scap_fdinfo *dst, sinsp_fdinfo_t* src)
case SCAP_FD_BPF:
case SCAP_FD_USERFAULTFD:
case SCAP_FD_IOURING:
case SCAP_FD_MEMFD:
case SCAP_FD_PIDFD:
strlcpy(dst->info.fname, src->m_name.c_str(), sizeof(dst->info.fname));
break;
default: