mirror of
https://github.com/falcosecurity/falco.git
synced 2026-03-22 04:32:21 +00:00
Compare commits
75 Commits
add-contex
...
0.17.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2439873a96 | ||
|
|
204f5f219d | ||
|
|
9b7c7ff5e4 | ||
|
|
1f0065e4b1 | ||
|
|
bcf83057fa | ||
|
|
46b1a3c841 | ||
|
|
a42ec9d7c7 | ||
|
|
3fedd00cfc | ||
|
|
4a4701b4fd | ||
|
|
40111a5d6e | ||
|
|
323a9ef51d | ||
|
|
49752fc81a | ||
|
|
4224329905 | ||
|
|
b7c35d3b54 | ||
|
|
d1c642cbd2 | ||
|
|
b369de3801 | ||
|
|
95a7cf3ea8 | ||
|
|
dc03dbee18 | ||
|
|
8156c9214c | ||
|
|
d11ad9a005 | ||
|
|
c71703b566 | ||
|
|
8400066ac8 | ||
|
|
f18fc46a1c | ||
|
|
e598606505 | ||
|
|
7b2b0b14a5 | ||
|
|
e422337ed7 | ||
|
|
c4cd9e326a | ||
|
|
533e8247fd | ||
|
|
736aa92b5e | ||
|
|
3e1ab78536 | ||
|
|
38cf3c6f29 | ||
|
|
50f04897e5 | ||
|
|
62be14dde6 | ||
|
|
c5e296576d | ||
|
|
a5b063f5fa | ||
|
|
c61c0e7020 | ||
|
|
ebcb133f00 | ||
|
|
88503a1ea9 | ||
|
|
e1c2cac9c9 | ||
|
|
44f0633f47 | ||
|
|
9d4ed8e33e | ||
|
|
0d4fc4bdad | ||
|
|
85a94d67d3 | ||
|
|
f3c3cda879 | ||
|
|
e02318db7c | ||
|
|
9f7e3bdfcd | ||
|
|
2cda10caeb | ||
|
|
7efec602e8 | ||
|
|
8fb4c7f2f6 | ||
|
|
6e313742e7 | ||
|
|
e92a721521 | ||
|
|
d5aae4aff5 | ||
|
|
2aff2d00a3 | ||
|
|
d7956a2a09 | ||
|
|
9308c1ee55 | ||
|
|
40e3e21391 | ||
|
|
d6c089c917 | ||
|
|
9ab718c100 | ||
|
|
4b2ea32eac | ||
|
|
5acdb16e89 | ||
|
|
a084f8c4ed | ||
|
|
01f65e3bae | ||
|
|
1711ed0a2e | ||
|
|
839d76a760 | ||
|
|
dc7bff127f | ||
|
|
e80ff6296a | ||
|
|
231f881c5a | ||
|
|
cb5a3a14e6 | ||
|
|
4c68da0dcc | ||
|
|
a32870ae1d | ||
|
|
fdbd520cce | ||
|
|
f20a5a04bf | ||
|
|
affb1086a3 | ||
|
|
8155d467ab | ||
|
|
bf19d8c881 |
119
.cmake-format
Normal file
119
.cmake-format
Normal file
@@ -0,0 +1,119 @@
|
||||
# --------------------------
|
||||
# General Formatting Options
|
||||
# --------------------------
|
||||
# How wide to allow formatted cmake files
|
||||
line_width = 80
|
||||
|
||||
# How many spaces to tab for indent
|
||||
tab_size = 2
|
||||
|
||||
# If arglists are longer than this, break them always
|
||||
max_subargs_per_line = 3
|
||||
|
||||
# If true, separate flow control names from their parentheses with a space
|
||||
separate_ctrl_name_with_space = False
|
||||
|
||||
# If true, separate function names from parentheses with a space
|
||||
separate_fn_name_with_space = False
|
||||
|
||||
# If a statement is wrapped to more than one line, than dangle the closing
|
||||
# parenthesis on it's own line
|
||||
dangle_parens = False
|
||||
|
||||
# If the statement spelling length (including space and parenthesis is larger
|
||||
# than the tab width by more than this amoung, then force reject un-nested
|
||||
# layouts.
|
||||
max_prefix_chars = 2
|
||||
|
||||
# If a candidate layout is wrapped horizontally but it exceeds this many lines,
|
||||
# then reject the layout.
|
||||
max_lines_hwrap = 2
|
||||
|
||||
# What style line endings to use in the output.
|
||||
line_ending = 'unix'
|
||||
|
||||
# Format command names consistently as 'lower' or 'upper' case
|
||||
command_case = 'canonical'
|
||||
|
||||
# Format keywords consistently as 'lower' or 'upper' case
|
||||
keyword_case = 'unchanged'
|
||||
|
||||
# Specify structure for custom cmake functions
|
||||
additional_commands = {
|
||||
"pkg_find": {
|
||||
"kwargs": {
|
||||
"PKG": "*"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# A list of command names which should always be wrapped
|
||||
always_wrap = []
|
||||
|
||||
# Specify the order of wrapping algorithms during successive reflow attempts
|
||||
algorithm_order = [0, 1, 2, 3, 4]
|
||||
|
||||
# If true, the argument lists which are known to be sortable will be sorted
|
||||
# lexicographicall
|
||||
enable_sort = True
|
||||
|
||||
# If true, the parsers may infer whether or not an argument list is sortable
|
||||
# (without annotation).
|
||||
autosort = False
|
||||
|
||||
# If a comment line starts with at least this many consecutive hash characters,
|
||||
# then don't lstrip() them off. This allows for lazy hash rulers where the first
|
||||
# hash char is not separated by space
|
||||
hashruler_min_length = 10
|
||||
|
||||
# A dictionary containing any per-command configuration overrides. Currently
|
||||
# only `command_case` is supported.
|
||||
per_command = {}
|
||||
|
||||
|
||||
# --------------------------
|
||||
# Comment Formatting Options
|
||||
# --------------------------
|
||||
# What character to use for bulleted lists
|
||||
bullet_char = '*'
|
||||
|
||||
# What character to use as punctuation after numerals in an enumerated list
|
||||
enum_char = '.'
|
||||
|
||||
# enable comment markup parsing and reflow
|
||||
enable_markup = True
|
||||
|
||||
# If comment markup is enabled, don't reflow the first comment block in each
|
||||
# listfile. Use this to preserve formatting of your copyright/license
|
||||
# statements.
|
||||
first_comment_is_literal = False
|
||||
|
||||
# If comment markup is enabled, don't reflow any comment block which matches
|
||||
# this (regex) pattern. Default is `None` (disabled).
|
||||
literal_comment_pattern = None
|
||||
|
||||
# Regular expression to match preformat fences in comments
|
||||
# default=r'^\s*([`~]{3}[`~]*)(.*)$'
|
||||
fence_pattern = '^\\s*([`~]{3}[`~]*)(.*)$'
|
||||
|
||||
# Regular expression to match rulers in comments
|
||||
# default=r'^\s*[^\w\s]{3}.*[^\w\s]{3}$'
|
||||
ruler_pattern = '^\\s*[^\\w\\s]{3}.*[^\\w\\s]{3}$'
|
||||
|
||||
# If true, then insert a space between the first hash char and remaining hash
|
||||
# chars in a hash ruler, and normalize it's length to fill the column
|
||||
canonicalize_hashrulers = True
|
||||
|
||||
|
||||
# ---------------------------------
|
||||
# Miscellaneous Options
|
||||
# ---------------------------------
|
||||
# If true, emit the unicode byte-order mark (BOM) at the start of the file
|
||||
emit_byteorder_mark = False
|
||||
|
||||
# Specify the encoding of the input file. Defaults to utf-8.
|
||||
input_encoding = 'utf-8'
|
||||
|
||||
# Specify the encoding of the output file. Defaults to utf-8. Note that cmake
|
||||
# only claims to support utf-8 so be careful when using anything else
|
||||
output_encoding = 'utf-8'
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -20,4 +20,7 @@ docker/event-generator/mysqld
|
||||
docker/event-generator/httpd
|
||||
docker/event-generator/sha1sum
|
||||
docker/event-generator/vipw
|
||||
.vscode/*
|
||||
|
||||
.vscode/*
|
||||
|
||||
.luacheckcache
|
||||
9
.luacheckrc
Normal file
9
.luacheckrc
Normal file
@@ -0,0 +1,9 @@
|
||||
std = "min"
|
||||
cache = true
|
||||
include_files = {
|
||||
"userspace/falco/lua/*.lua",
|
||||
"userspace/engine/lua/*.lua",
|
||||
"userspace/engine/lua/lyaml/*.lua",
|
||||
"*.luacheckrc"
|
||||
}
|
||||
exclude_files = {"build"}
|
||||
17
.travis.yml
17
.travis.yml
@@ -18,8 +18,8 @@
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
env:
|
||||
- BUILD_TYPE=Debug
|
||||
- BUILD_TYPE=Release
|
||||
- BUILD_TYPE=debug
|
||||
- BUILD_TYPE=release
|
||||
sudo: required
|
||||
services:
|
||||
- docker
|
||||
@@ -33,15 +33,4 @@ install:
|
||||
- pushd ../sysdig && (git checkout "${BRANCH}" || exit 0) && echo "Using sysdig branch:" $(git rev-parse --abbrev-ref HEAD) && popd
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- docker run --user $(id -u):$(id -g) -v /etc/passwd:/etc/passwd:ro -e MAKE_JOBS=4 -v $TRAVIS_BUILD_DIR/..:/source -v $TRAVIS_BUILD_DIR/build:/build falcosecurity/falco-builder cmake
|
||||
- docker run --user $(id -u):$(id -g) -v /etc/passwd:/etc/passwd:ro -e MAKE_JOBS=4 -v $TRAVIS_BUILD_DIR/..:/source -v $TRAVIS_BUILD_DIR/build:/build falcosecurity/falco-builder package
|
||||
- docker run --user $(id -u):$(id -g) -v /etc/passwd:/etc/passwd:ro -e MAKE_JOBS=1 -v $TRAVIS_BUILD_DIR/..:/source -v $TRAVIS_BUILD_DIR/build:/build falcosecurity/falco-builder tests
|
||||
- docker run -v /boot:/boot:ro -v /var/run/docker.sock:/var/run/docker.sock -v /etc/passwd:/etc/passwd:ro -e MAKE_JOBS=4 -v $TRAVIS_BUILD_DIR/..:/source -v $TRAVIS_BUILD_DIR/build:/build falcosecurity/falco-tester
|
||||
notifications:
|
||||
webhooks:
|
||||
urls:
|
||||
# - https://webhooks.gitter.im/e/fdbc2356fb0ea2f15033
|
||||
on_success: change
|
||||
on_failure: always
|
||||
on_start: never
|
||||
- ./scripts/build "${TRAVIS_BUILD_DIR}/.." "${TRAVIS_BUILD_DIR}/build"
|
||||
|
||||
8
.yamllint.conf
Normal file
8
.yamllint.conf
Normal file
@@ -0,0 +1,8 @@
|
||||
extends: default
|
||||
|
||||
rules:
|
||||
indentation: disable
|
||||
document-start: disable
|
||||
comments: disable
|
||||
line-length: disable
|
||||
new-line-at-end-of-file: disable
|
||||
98
CHANGELOG.md
98
CHANGELOG.md
@@ -2,6 +2,104 @@
|
||||
|
||||
This file documents all notable changes to Falco. The release numbering uses [semantic versioning](http://semver.org).
|
||||
|
||||
## v0.17.0
|
||||
|
||||
Released 2019-07-31
|
||||
|
||||
## Major Changes
|
||||
|
||||
* **The set of supported platforms has changed**. Switch to a reorganized builder image that uses Centos 7 as a base. As a result, falco is no longer supported on Centos 6. The other supported platforms should remain the same [[#719](https://github.com/falcosecurity/falco/pull/719)]
|
||||
|
||||
## Minor Changes
|
||||
|
||||
* When enabling rules within the falco engine, use rule substrings instead of regexes. [[#743](https://github.com/falcosecurity/falco/pull/743)]
|
||||
|
||||
* Additional improvements to the handling and display of rules validation errors [[#744](https://github.com/falcosecurity/falco/pull/744)] [[#747](https://github.com/falcosecurity/falco/pull/747)]
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
* Fix a problem that would cause prevent container metadata lookups when falco was daemonized [[#731](https://github.com/falcosecurity/falco/pull/731)]
|
||||
|
||||
* Allow rule priorites to be expressed as lowercase and a mix of lower/uppercase [[#737](https://github.com/falcosecurity/falco/pull/737)]
|
||||
|
||||
## Rule Changes
|
||||
|
||||
* Fix a parentheses bug with the `shell_procs` macro [[#728](https://github.com/falcosecurity/falco/pull/728)]
|
||||
|
||||
* Allow additional containers to mount sensitive host paths [[#733](https://github.com/falcosecurity/falco/pull/733)] [[#736](https://github.com/falcosecurity/falco/pull/736)]
|
||||
|
||||
* Allow additional containers to truncate log files [[#733](https://github.com/falcosecurity/falco/pull/733)]
|
||||
|
||||
* Fix false positives with the `Write below root` rule on GKE [[#739](https://github.com/falcosecurity/falco/pull/739)]
|
||||
|
||||
## v0.16.0
|
||||
|
||||
Released 2019-07-12
|
||||
|
||||
## Major Changes
|
||||
|
||||
* Clean up error reporting to provide more meaningful error messages along with context when loading rules files. When run with -V, the results of the validation ("OK" or error message) are sent to standard output. [[#708](https://github.com/falcosecurity/falco/pull/708)]
|
||||
|
||||
* Improve rule loading performance by optimizing lua parsing paths to avoid expensive pattern matches. [[#694](https://github.com/falcosecurity/falco/pull/694)]
|
||||
|
||||
* Bump falco engine version to 4 to reflect new fields `ka.useragent`, others. [[#710](https://github.com/falcosecurity/falco/pull/710)] [[#681](https://github.com/falcosecurity/falco/pull/681)]
|
||||
|
||||
* Add Catch2 as a unit testing framework. This will add additional coverage on top of the regression tests using Avocado. [[#687](https://github.com/falcosecurity/falco/pull/687)]
|
||||
|
||||
## Minor Changes
|
||||
|
||||
* Add SYSDIG_DIR Cmake option to specify location for sysdig source code when building falco. [[#677](https://github.com/falcosecurity/falco/pull/677)] [[#679](https://github.com/falcosecurity/falco/pull/679)] [[#702](https://github.com/falcosecurity/falco/pull/702)]
|
||||
|
||||
* New field `ka.useragent` reports the useragent from k8s audit events. [[#709](https://github.com/falcosecurity/falco/pull/709)]
|
||||
|
||||
* Add clang formatter for C++ syntax formatting. [[#701](https://github.com/falcosecurity/falco/pull/701)] [[#689](https://github.com/falcosecurity/falco/pull/689)]
|
||||
|
||||
* Partial changes towards lua syntax formatting. No particular formatting enforced yet, though. [[#718](https://github.com/falcosecurity/falco/pull/718)]
|
||||
|
||||
* Partial changes towards yaml syntax formatting. No particular formatting enforced yet, though. [[#714](https://github.com/falcosecurity/falco/pull/714)]
|
||||
|
||||
* Add cmake syntax formatting. [[#703](https://github.com/falcosecurity/falco/pull/703)]
|
||||
|
||||
* Token bucket unit tests and redesign. [[#692](https://github.com/falcosecurity/falco/pull/692)]
|
||||
|
||||
* Update github PR template. [[#699](https://github.com/falcosecurity/falco/pull/699)]
|
||||
|
||||
* Fix PR template for kind/rule-*. [[#697](https://github.com/falcosecurity/falco/pull/697)]
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
* Remove an unused cmake file. [[#700](https://github.com/falcosecurity/falco/pull/700)]
|
||||
|
||||
* Misc Cmake cleanups. [[#673](https://github.com/falcosecurity/falco/pull/673)]
|
||||
|
||||
* Misc k8s install docs improvements. [[#671](https://github.com/falcosecurity/falco/pull/671)]
|
||||
|
||||
## Rule Changes
|
||||
|
||||
* Allow k8s.gcr.io/kube-proxy image to run privileged. [[#717](https://github.com/falcosecurity/falco/pull/717)]
|
||||
|
||||
* Add runc to the list of possible container entrypoint parents. [[#712](https://github.com/falcosecurity/falco/pull/712)]
|
||||
|
||||
* Skip Source RFC 1918 addresses when considering outbound connections. [[#685](https://github.com/falcosecurity/falco/pull/685)]
|
||||
|
||||
* Add additional `user_XXX` placeholder macros to allow for easy customization of rule exceptions. [[#685](https://github.com/falcosecurity/falco/pull/685)]
|
||||
|
||||
* Let weaveworks programs change namespaces. [[#685](https://github.com/falcosecurity/falco/pull/685)]
|
||||
|
||||
* Add additional openshift images. [[#685](https://github.com/falcosecurity/falco/pull/685)]
|
||||
|
||||
* Add openshift as a k8s binary. [[#678](https://github.com/falcosecurity/falco/pull/678)]
|
||||
|
||||
* Add dzdo as a binary that can change users. [[#678](https://github.com/falcosecurity/falco/pull/678)]
|
||||
|
||||
* Allow azure/calico binaries to change namespaces. [[#678](https://github.com/falcosecurity/falco/pull/678)]
|
||||
|
||||
* Add back trusted_containers list for backport compatibility [[#675](https://github.com/falcosecurity/falco/pull/675)]
|
||||
|
||||
* Add mkdirat as a syscall for mkdir operations. [[#667](https://github.com/falcosecurity/falco/pull/667)]
|
||||
|
||||
* Add container id/repository to rules that can work with containers. [[#667](https://github.com/falcosecurity/falco/pull/667)]
|
||||
|
||||
## v0.15.3
|
||||
|
||||
Released 2019-06-12
|
||||
|
||||
@@ -15,32 +15,40 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
cmake_minimum_required(VERSION 2.8.2)
|
||||
cmake_minimum_required(VERSION 3.3.2)
|
||||
|
||||
project(falco)
|
||||
|
||||
option(BUILD_WARNINGS_AS_ERRORS "Enable building with -Wextra -Werror flags")
|
||||
|
||||
if(NOT DEFINED FALCO_VERSION)
|
||||
set(FALCO_VERSION "0.1.1dev")
|
||||
if(NOT SYSDIG_DIR)
|
||||
get_filename_component(SYSDIG_DIR "${PROJECT_SOURCE_DIR}/../sysdig" REALPATH)
|
||||
endif()
|
||||
|
||||
# Custom CMake modules
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
|
||||
list(APPEND CMAKE_MODULE_PATH "${SYSDIG_DIR}/cmake/modules")
|
||||
|
||||
option(BUILD_WARNINGS_AS_ERRORS "Enable building with -Wextra -Werror flags")
|
||||
|
||||
if(NOT DEFINED FALCO_ETC_DIR)
|
||||
set(FALCO_ETC_DIR "/etc/falco")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
SET(CMAKE_BUILD_TYPE Release)
|
||||
endif()
|
||||
|
||||
if(NOT DRAIOS_DEBUG_FLAGS)
|
||||
set(DRAIOS_DEBUG_FLAGS "-D_DEBUG")
|
||||
endif()
|
||||
|
||||
string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE)
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "debug")
|
||||
set(KBUILD_FLAGS "${DRAIOS_DEBUG_FLAGS} ${DRAIOS_FEATURE_FLAGS}")
|
||||
else()
|
||||
set(CMAKE_BUILD_TYPE "release")
|
||||
set(KBUILD_FLAGS "${DRAIOS_FEATURE_FLAGS}")
|
||||
endif()
|
||||
|
||||
set(CMAKE_COMMON_FLAGS "-Wall -ggdb ${DRAIOS_FEATURE_FLAGS}")
|
||||
|
||||
if(BUILD_WARNINGS_AS_ERRORS)
|
||||
set(CMAKE_SUPPRESSED_WARNINGS "-Wno-unused-parameter -Wno-missing-field-initializers -Wno-sign-compare -Wno-type-limits -Wno-implicit-fallthrough -Wno-format-truncation")
|
||||
set(CMAKE_SUPPRESSED_WARNINGS "-Wno-unused-parameter -Wno-unused-variable -Wno-unused-but-set-variable -Wno-missing-field-initializers -Wno-sign-compare -Wno-type-limits -Wno-implicit-fallthrough -Wno-format-truncation")
|
||||
set(CMAKE_COMMON_FLAGS "${CMAKE_COMMON_FLAGS} -Wextra -Werror ${CMAKE_SUPPRESSED_WARNINGS}")
|
||||
endif()
|
||||
|
||||
@@ -59,11 +67,28 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
add_definitions(-DHAS_CAPTURE)
|
||||
endif()
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(KBUILD_FLAGS "${DRAIOS_DEBUG_FLAGS} ${DRAIOS_FEATURE_FLAGS}")
|
||||
else()
|
||||
set(KBUILD_FLAGS "${DRAIOS_FEATURE_FLAGS}")
|
||||
# Create the falco version variable according to git index
|
||||
if(NOT FALCO_VERSION)
|
||||
include(GetGitRevisionDescription)
|
||||
git_get_exact_tag(FALCO_TAG)
|
||||
if(NOT FALCO_TAG)
|
||||
git_describe(FALCO_VERSION "--always")
|
||||
git_local_changes(FALCO_CHANGES)
|
||||
if(FALCO_CHANGES STREQUAL "DIRTY")
|
||||
string(TOLOWER "${FALCO_CHANGES}" FALCO_CHANGES)
|
||||
set(FALCO_VERSION "${FALCO_VERSION}.${FALCO_CHANGES}")
|
||||
endif()
|
||||
set(FALCO_VERSION "0.${FALCO_VERSION}")
|
||||
else()
|
||||
set(FALCO_VERSION "${FALCO_TAG}")
|
||||
string(REGEX
|
||||
REPLACE "^v([0-9]+)(\\.[0-9]+)(\\.[0-9]+)?"
|
||||
"\\1\\2\\3"
|
||||
FALCO_VERSION
|
||||
${FALCO_VERSION})
|
||||
endif()
|
||||
endif()
|
||||
message(STATUS "Falco version: ${FALCO_VERSION}")
|
||||
|
||||
set(PACKAGE_NAME "falco")
|
||||
set(PROBE_VERSION "${FALCO_VERSION}")
|
||||
@@ -75,10 +100,6 @@ endif()
|
||||
|
||||
set(CMD_MAKE make)
|
||||
|
||||
if(NOT SYSDIG_DIR)
|
||||
set(SYSDIG_DIR "${PROJECT_SOURCE_DIR}/../sysdig")
|
||||
endif()
|
||||
|
||||
# make luaJIT work on OS X
|
||||
if(APPLE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-pagezero_size 10000 -image_base 100000000")
|
||||
@@ -140,7 +161,7 @@ else()
|
||||
CONFIGURE_COMMAND ./configure --disable-maintainer-mode --enable-all-static --disable-dependency-tracking
|
||||
BUILD_COMMAND ${CMD_MAKE} LDFLAGS=-all-static
|
||||
BUILD_IN_SOURCE 1
|
||||
PATCH_COMMAND wget -O jq-1.5-fix-tokenadd.patch https://github.com/stedolan/jq/commit/8eb1367ca44e772963e704a700ef72ae2e12babd.patch && patch -i jq-1.5-fix-tokenadd.patch
|
||||
PATCH_COMMAND curl -L https://github.com/stedolan/jq/commit/8eb1367ca44e772963e704a700ef72ae2e12babd.patch | patch
|
||||
INSTALL_COMMAND "")
|
||||
endif()
|
||||
|
||||
@@ -594,7 +615,7 @@ else()
|
||||
BUILD_BYPRODUCTS ${GRPC_LIB} ${GRPCPP_LIB}
|
||||
# TODO s390x support
|
||||
# TODO what if using system zlib
|
||||
PATCH_COMMAND rm -rf third_party/zlib && ln -s ${ZLIB_SRC} third_party/zlib && wget https://download.sysdig.com/dependencies/grpc-1.1.4-Makefile.patch && patch < grpc-1.1.4-Makefile.patch
|
||||
PATCH_COMMAND rm -rf third_party/zlib && ln -s ${ZLIB_SRC} third_party/zlib && curl -L https://download.sysdig.com/dependencies/grpc-1.1.4-Makefile.patch | patch
|
||||
INSTALL_COMMAND "")
|
||||
endif()
|
||||
|
||||
@@ -606,14 +627,6 @@ add_subdirectory(test)
|
||||
add_subdirectory(rules)
|
||||
add_subdirectory(docker)
|
||||
|
||||
# Add path for custom CMake modules used to build dependencies from Sysdig (libscap, libsinsp)
|
||||
list(APPEND CMAKE_MODULE_PATH
|
||||
"${SYSDIG_DIR}/cmake/modules")
|
||||
|
||||
# Add path for custom CMake modules
|
||||
list(APPEND CMAKE_MODULE_PATH
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
|
||||
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
add_subdirectory("${SYSDIG_DIR}/driver" "${PROJECT_BINARY_DIR}/driver")
|
||||
include(FindMakedev)
|
||||
@@ -630,10 +643,10 @@ add_subdirectory(userspace/engine)
|
||||
add_subdirectory(userspace/falco)
|
||||
add_subdirectory(tests)
|
||||
|
||||
|
||||
set(CPACK_PACKAGE_NAME "${PACKAGE_NAME}")
|
||||
set(CPACK_PACKAGE_VENDOR "Sysdig Inc.")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "falco, a system-level activity monitoring tool")
|
||||
set(CPACK_PACKAGE_CONTACT "opensource@sysdig.com")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Falco - Container Native Runtime Security")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/scripts/description.txt")
|
||||
set(CPACK_PACKAGE_VERSION "${FALCO_VERSION}")
|
||||
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_SYSTEM_PROCESSOR}")
|
||||
@@ -643,19 +656,19 @@ set(CPACK_PACKAGE_RELOCATABLE "OFF")
|
||||
|
||||
set(CPACK_GENERATOR DEB RPM TGZ)
|
||||
|
||||
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Sysdig <support@sysdig.com>")
|
||||
set(CPACK_DEBIAN_PACKAGE_SECTION "utils")
|
||||
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "http://www.sysdig.org")
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64")
|
||||
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://www.falco.org")
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "dkms (>= 2.1.0.0)")
|
||||
set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_BINARY_DIR}/scripts/debian/postinst;${CMAKE_BINARY_DIR}/scripts/debian/prerm;${PROJECT_SOURCE_DIR}/scripts/debian/postrm;${PROJECT_SOURCE_DIR}/cpack/debian/conffiles")
|
||||
|
||||
set(CPACK_RPM_PACKAGE_LICENSE "Apache v2.0")
|
||||
set(CPACK_RPM_PACKAGE_URL "http://www.sysdig.org")
|
||||
set(CPACK_RPM_PACKAGE_URL "https://www.falco.org")
|
||||
set(CPACK_RPM_PACKAGE_REQUIRES "dkms, gcc, make, kernel-devel, perl")
|
||||
set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE "${PROJECT_SOURCE_DIR}/scripts/rpm/postinstall")
|
||||
set(CPACK_RPM_PRE_UNINSTALL_SCRIPT_FILE "${PROJECT_SOURCE_DIR}/scripts/rpm/preuninstall")
|
||||
set(CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE "${PROJECT_SOURCE_DIR}/scripts/rpm/postuninstall")
|
||||
set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION /usr/src /usr/share/man /usr/share/man/man8 /etc /usr /usr/bin /usr/share /etc/rc.d /etc/rc.d/init.d )
|
||||
set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION /usr/src /usr/share/man /usr/share/man/man8 /etc /usr /usr/bin /usr/share /etc/rc.d /etc/rc.d/init.d)
|
||||
set(CPACK_RPM_PACKAGE_RELOCATABLE "OFF")
|
||||
|
||||
include(CPack)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#### Latest release
|
||||
|
||||
**v0.15.3**
|
||||
**v0.17.0**
|
||||
Read the [change log](https://github.com/falcosecurity/falco/blob/dev/CHANGELOG.md)
|
||||
|
||||
Dev Branch: [](https://travis-ci.com/falcosecurity/falco)<br />
|
||||
|
||||
168
cmake/modules/GetGitRevisionDescription.cmake
Normal file
168
cmake/modules/GetGitRevisionDescription.cmake
Normal file
@@ -0,0 +1,168 @@
|
||||
# - Returns a version string from Git
|
||||
#
|
||||
# These functions force a re-configure on each git commit so that you can
|
||||
# trust the values of the variables in your build system.
|
||||
#
|
||||
# get_git_head_revision(<refspecvar> <hashvar> [<additional arguments to git describe> ...])
|
||||
#
|
||||
# Returns the refspec and sha hash of the current head revision
|
||||
#
|
||||
# git_describe(<var> [<additional arguments to git describe> ...])
|
||||
#
|
||||
# Returns the results of git describe on the source tree, and adjusting
|
||||
# the output so that it tests false if an error occurs.
|
||||
#
|
||||
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
|
||||
#
|
||||
# Returns the results of git describe --exact-match on the source tree,
|
||||
# and adjusting the output so that it tests false if there was no exact
|
||||
# matching tag.
|
||||
#
|
||||
# git_local_changes(<var>)
|
||||
#
|
||||
# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes.
|
||||
# Uses the return code of "git diff-index --quiet HEAD --".
|
||||
# Does not regard untracked files.
|
||||
#
|
||||
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||
#
|
||||
# Original Author:
|
||||
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
||||
# http://academic.cleardefinition.com
|
||||
# Iowa State University HCI Graduate Program/VRAC
|
||||
#
|
||||
# Copyright Iowa State University 2009-2010.
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
if(__get_git_revision_description)
|
||||
return()
|
||||
endif()
|
||||
set(__get_git_revision_description YES)
|
||||
|
||||
# We must run the following at "include" time, not at function call time,
|
||||
# to find the path to this module rather than the path to a calling list file
|
||||
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
|
||||
|
||||
function(get_git_head_revision _refspecvar _hashvar)
|
||||
set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
|
||||
while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories
|
||||
set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}")
|
||||
get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH)
|
||||
if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT)
|
||||
# We have reached the root directory, we are not in git
|
||||
set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
|
||||
set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
|
||||
endwhile()
|
||||
# check if this is a submodule
|
||||
if(NOT IS_DIRECTORY ${GIT_DIR})
|
||||
file(READ ${GIT_DIR} submodule)
|
||||
string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule})
|
||||
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
|
||||
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE)
|
||||
endif()
|
||||
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
|
||||
if(NOT EXISTS "${GIT_DATA}")
|
||||
file(MAKE_DIRECTORY "${GIT_DATA}")
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${GIT_DIR}/HEAD")
|
||||
return()
|
||||
endif()
|
||||
set(HEAD_FILE "${GIT_DATA}/HEAD")
|
||||
configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY)
|
||||
|
||||
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
|
||||
"${GIT_DATA}/grabRef.cmake"
|
||||
@ONLY)
|
||||
include("${GIT_DATA}/grabRef.cmake")
|
||||
|
||||
set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE)
|
||||
set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(git_describe _var)
|
||||
if(NOT GIT_FOUND)
|
||||
find_package(Git QUIET)
|
||||
endif()
|
||||
get_git_head_revision(refspec hash)
|
||||
if(NOT GIT_FOUND)
|
||||
set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
if(NOT hash)
|
||||
set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# TODO sanitize
|
||||
#if((${ARGN}" MATCHES "&&") OR
|
||||
# (ARGN MATCHES "||") OR
|
||||
# (ARGN MATCHES "\\;"))
|
||||
# message("Please report the following error to the project!")
|
||||
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
|
||||
#endif()
|
||||
|
||||
# message(STATUS "Arguments to execute_process: ${ARGN}")
|
||||
|
||||
execute_process(COMMAND
|
||||
"${GIT_EXECUTABLE}"
|
||||
describe
|
||||
${hash}
|
||||
${ARGN}
|
||||
WORKING_DIRECTORY
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
RESULT_VARIABLE
|
||||
res
|
||||
OUTPUT_VARIABLE
|
||||
out
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(NOT res EQUAL 0)
|
||||
set(out "${out}-${res}-NOTFOUND")
|
||||
endif()
|
||||
|
||||
set(${_var} "${out}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(git_get_exact_tag _var)
|
||||
git_describe(out --exact-match ${ARGN})
|
||||
set(${_var} "${out}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(git_local_changes _var)
|
||||
if(NOT GIT_FOUND)
|
||||
find_package(Git QUIET)
|
||||
endif()
|
||||
get_git_head_revision(refspec hash)
|
||||
if(NOT GIT_FOUND)
|
||||
set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
if(NOT hash)
|
||||
set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND
|
||||
"${GIT_EXECUTABLE}"
|
||||
diff-index --quiet HEAD --
|
||||
WORKING_DIRECTORY
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
RESULT_VARIABLE
|
||||
res
|
||||
OUTPUT_VARIABLE
|
||||
out
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(res EQUAL 0)
|
||||
set(${_var} "CLEAN" PARENT_SCOPE)
|
||||
else()
|
||||
set(${_var} "DIRTY" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
41
cmake/modules/GetGitRevisionDescription.cmake.in
Normal file
41
cmake/modules/GetGitRevisionDescription.cmake.in
Normal file
@@ -0,0 +1,41 @@
|
||||
#
|
||||
# Internal file for GetGitRevisionDescription.cmake
|
||||
#
|
||||
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||
#
|
||||
# Original Author:
|
||||
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
||||
# http://academic.cleardefinition.com
|
||||
# Iowa State University HCI Graduate Program/VRAC
|
||||
#
|
||||
# Copyright Iowa State University 2009-2010.
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
set(HEAD_HASH)
|
||||
|
||||
file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
|
||||
|
||||
string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
|
||||
if(HEAD_CONTENTS MATCHES "ref")
|
||||
# named branch
|
||||
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
|
||||
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
|
||||
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
|
||||
else()
|
||||
configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY)
|
||||
file(READ "@GIT_DATA@/packed-refs" PACKED_REFS)
|
||||
if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}")
|
||||
set(HEAD_HASH "${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
# detached HEAD
|
||||
configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
|
||||
endif()
|
||||
|
||||
if(NOT HEAD_HASH)
|
||||
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
|
||||
string(STRIP "${HEAD_HASH}" HEAD_HASH)
|
||||
endif()
|
||||
@@ -1,52 +1,49 @@
|
||||
FROM centos:6
|
||||
FROM centos:7
|
||||
|
||||
ENV FALCO_VERSION 0.1.1dev
|
||||
ENV BUILD_TYPE Release
|
||||
ENV BUILD_DRIVER OFF
|
||||
ENV BUILD_BPF OFF
|
||||
ENV BUILD_WARNINGS_AS_ERRORS ON
|
||||
ENV MAKE_JOBS 4
|
||||
LABEL name="falcosecurity/falco-builder"
|
||||
LABEL usage="docker run -v $PWD/..:/source -v $PWD/build:/build falcosecurity/falco-builder cmake"
|
||||
LABEL maintainer="opensource@sysdig.com"
|
||||
|
||||
# copied from builder script
|
||||
RUN curl -o /etc/yum.repos.d/devtools-2.repo https://people.centos.org/tru/devtools-2/devtools-2.repo && \
|
||||
rpm -i http://mirror.pnl.gov/epel/6/i386/epel-release-6-8.noarch.rpm && \
|
||||
sed -e 's,$basearch,i386,' -e 's,$releasever\],$releasever-i686\],' /etc/yum.repos.d/devtools-2.repo > /etc/yum.repos.d/devtools-2-i686.repo && \
|
||||
yum -y install \
|
||||
createrepo \
|
||||
devtoolset-2-toolchain \
|
||||
dpkg \
|
||||
dpkg-devel \
|
||||
expect \
|
||||
gcc \
|
||||
gcc-c++ \
|
||||
git \
|
||||
glibc-static \
|
||||
libcurl-devel \
|
||||
make \
|
||||
curl \
|
||||
libcurl-devel \
|
||||
zlib-devel \
|
||||
pkg-config \
|
||||
rpm-build \
|
||||
unzip \
|
||||
wget \
|
||||
tar \
|
||||
autoconf \
|
||||
automake \
|
||||
libtool && \
|
||||
yum -y install \
|
||||
glibc-devel.i686 \
|
||||
devtoolset-2-libstdc++-devel.i686 \
|
||||
devtoolset-2-elfutils-libelf-devel && \
|
||||
yum clean all
|
||||
RUN curl -o docker.tgz https://get.docker.com/builds/Linux/x86_64/docker-1.11.0.tgz && \
|
||||
tar xfz docker.tgz docker/docker && \
|
||||
mv docker/docker /usr/local/bin/docker && \
|
||||
chmod +x /usr/local/bin/docker && \
|
||||
rm -fr docker.tgz docker/
|
||||
ARG BUILD_TYPE=release
|
||||
ARG BUILD_DRIVER=OFF
|
||||
ARG BUILD_BPF=OFF
|
||||
ARG BUILD_WARNINGS_AS_ERRORS=ON
|
||||
ARG MAKE_JOBS=4
|
||||
ARG FALCO_VERSION
|
||||
|
||||
# TEMPORARY until dependencies in CMakeLists.txt are fixed
|
||||
RUN yum -y install libyaml-devel
|
||||
COPY entrypoint.sh /
|
||||
ENV BUILD_TYPE=${BUILD_TYPE}
|
||||
ENV BUILD_DRIVER=${BUILD_DRIVER}
|
||||
ENV BUILD_BPF=${BUILD_BPF}
|
||||
ENV BUILD_WARNINGS_AS_ERRORS=${BUILD_WARNINGS_AS_ERRORS}
|
||||
ENV MAKE_JOBS=${MAKE_JOBS}
|
||||
ENV FALCO_VERSION=${FALCO_VERSION}
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
ARG DOCKER_VERSION=1.11.0
|
||||
ARG CMAKE_VERSION=3.5.0
|
||||
|
||||
RUN yum -y install centos-release-scl && \
|
||||
INSTALL_PKGS="devtoolset-7-gcc devtoolset-7-gcc-c++ devtoolset-7-toolchain devtoolset-7-libstdc++-devel devtoolset-7-elfutils-libelf-devel glibc-static autoconf automake libtool createrepo expect git which libcurl-devel zlib-devel rpm-build" && \
|
||||
yum -y install --setopt=tsflags=nodocs $INSTALL_PKGS && \
|
||||
rpm -V $INSTALL_PKGS
|
||||
|
||||
RUN source scl_source enable devtoolset-7 && \
|
||||
cd /tmp && \
|
||||
curl -L https://github.com/kitware/cmake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}.tar.gz | tar xz; \
|
||||
cd cmake-${CMAKE_VERSION} && \
|
||||
./bootstrap --system-curl && \
|
||||
make -j${MAKE_JOBS} && \
|
||||
make install && \
|
||||
rm -rf /tmp/cmake-${CMAKE_VERSION}
|
||||
|
||||
# fixme: deps needs a fix into CMakeLists.txt
|
||||
RUN yum -y install libyaml-devel && yum clean all -y
|
||||
|
||||
COPY ./root /
|
||||
|
||||
# DTS
|
||||
ENV BASH_ENV=/usr/bin/scl_enable \
|
||||
ENV=/usr/bin/scl_enable \
|
||||
PROMPT_COMMAND=". /usr/bin/scl_enable"
|
||||
|
||||
ENTRYPOINT ["entrypoint"]
|
||||
CMD ["usage"]
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
SOURCE_DIR=/source
|
||||
BUILD_DIR=/build
|
||||
TASK=${1:-all}
|
||||
|
||||
MANPATH=
|
||||
|
||||
. /opt/rh/devtoolset-2/enable
|
||||
|
||||
# Download and install cmake if not downloaded
|
||||
CMAKE_DIR=$BUILD_DIR/cmake
|
||||
if [ ! -e $CMAKE_DIR ]; then
|
||||
cd $BUILD_DIR
|
||||
mkdir -p $BUILD_DIR/cmake
|
||||
wget -nv https://s3.amazonaws.com/download.draios.com/dependencies/cmake-3.3.2.tar.gz
|
||||
tar -C $CMAKE_DIR --strip-components 1 -xzf cmake-3.3.2.tar.gz
|
||||
cd $CMAKE_DIR
|
||||
./bootstrap --system-curl
|
||||
make -j$MAKE_JOBS
|
||||
fi
|
||||
|
||||
if [ $TASK == "cmake" ]; then
|
||||
mkdir -p $BUILD_DIR/$BUILD_TYPE
|
||||
cd $BUILD_DIR/$BUILD_TYPE
|
||||
$CMAKE_DIR/bin/cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DFALCO_VERSION=$FALCO_VERSION -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_DRIVER=${BUILD_DRIVER} -DBUILD_BPF=${BUILD_BPF} -DBUILD_WARNINGS_AS_ERRORS=${BUILD_WARNINGS_AS_ERRORS} $SOURCE_DIR/falco
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ $TASK == "bash" ]; then
|
||||
exec /bin/bash
|
||||
fi
|
||||
|
||||
cd $BUILD_DIR/$BUILD_TYPE
|
||||
make -j$MAKE_JOBS $TASK
|
||||
|
||||
|
||||
|
||||
62
docker/builder/root/usr/bin/entrypoint
Executable file
62
docker/builder/root/usr/bin/entrypoint
Executable file
@@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
SOURCE_DIR=/source
|
||||
BUILD_DIR=/build
|
||||
CMD=${1:-usage}
|
||||
shift
|
||||
|
||||
# Build type can be "debug" or "release", fallbacks to "release" by default
|
||||
BUILD_TYPE=$(echo "$BUILD_TYPE" | tr "[:upper:]" "[:lower:]")
|
||||
DRAIOS_DEBUG_FLAGS=
|
||||
case "$BUILD_TYPE" in
|
||||
"debug")
|
||||
DRAIOS_DEBUG_FLAGS="-D_DEBUG -DNDEBUG"
|
||||
;;
|
||||
*)
|
||||
BUILD_TYPE="release"
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$CMD" in
|
||||
"cmake")
|
||||
# Check that source directory contains Falco and Sysdig
|
||||
if [ ! -d "$SOURCE_DIR/sysdig" ]; then
|
||||
echo "Missing sysdig source." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -d "$SOURCE_DIR/falco" ]; then
|
||||
echo "Missing falco source." >&2
|
||||
exit 1
|
||||
fi
|
||||
# Prepare build directory
|
||||
mkdir -p "$BUILD_DIR/$BUILD_TYPE"
|
||||
cd "$BUILD_DIR/$BUILD_TYPE"
|
||||
|
||||
cmake \
|
||||
-DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr \
|
||||
-DBUILD_DRIVER="$BUILD_DRIVER" \
|
||||
-DBUILD_BPF="$BUILD_BPF" \
|
||||
-DBUILD_WARNINGS_AS_ERRORS="$BUILD_WARNINGS_AS_ERRORS" \
|
||||
-DFALCO_VERSION="$FALCO_VERSION" \
|
||||
-DDRAIOS_DEBUG_FLAGS="$DRAIOS_DEBUG_FLAGS" \
|
||||
"$SOURCE_DIR/falco"
|
||||
exit "$(printf '%d\n' $?)"
|
||||
;;
|
||||
"bash")
|
||||
CMD=/bin/bash
|
||||
;& # fallthrough
|
||||
"usage")
|
||||
exec "$CMD" "$@"
|
||||
;;
|
||||
*)
|
||||
if [ ! -d "$BUILD_DIR/$BUILD_TYPE" ]; then
|
||||
echo "Missing $BUILD_DIR/$BUILD_TYPE directory: run cmake."
|
||||
exit 1
|
||||
fi
|
||||
cd "$BUILD_DIR/$BUILD_TYPE"
|
||||
make -j"$MAKE_JOBS" "$CMD"
|
||||
;;
|
||||
esac
|
||||
6
docker/builder/root/usr/bin/scl_enable
Executable file
6
docker/builder/root/usr/bin/scl_enable
Executable file
@@ -0,0 +1,6 @@
|
||||
# IMPORTANT: Do not add more content to this file unless you know what you are doing.
|
||||
# This file is sourced everytime the shell session is opened.
|
||||
#
|
||||
# This will make scl collection binaries work out of box.
|
||||
unset BASH_ENV PROMPT_COMMAND ENV
|
||||
source scl_source enable devtoolset-7
|
||||
51
docker/builder/root/usr/bin/usage
Executable file
51
docker/builder/root/usr/bin/usage
Executable file
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
gccversion=$(gcc --version | head -n1)
|
||||
cppversion=$(g++ -dM -E -x c++ /dev/null | grep -F __cplusplus | cut -d' ' -f3)
|
||||
cmakeversion=$(cmake --version | head -n1)
|
||||
|
||||
cat <<EOF
|
||||
Hello, this is the Falco builder container.
|
||||
|
||||
How to use.
|
||||
|
||||
The default commands for the Falco builder image reports usage and environment info.
|
||||
* docker run falcosecurity/falco-builder
|
||||
* docker run falcosecurity/falco-builder usage
|
||||
|
||||
It supports bash.
|
||||
* docker run -ti falcosecurity/falco-builder bash
|
||||
|
||||
To build Falco it needs:
|
||||
- a bind-mount on the source directory (ie., the directory containing falco and sysdig source as siblings)
|
||||
|
||||
Optionally, you can also bind-mount the build directory.
|
||||
So, you can execute it from the Falco root directory as follows.
|
||||
|
||||
* docker run -v $PWD/..:/source -v $PWD/build:/build falcosecurity/falco-builder cmake
|
||||
* docker run -v $PWD/..:/source -v $PWD/build:/build falcosecurity/falco-builder [<cmake-target-x>, ..., <cmake-target-y>]
|
||||
|
||||
Eg.,
|
||||
* docker run -v $PWD/..:/source -v $PWD/build:/build falcosecurity/falco-builder tests
|
||||
* docker run -v $PWD/..:/source -v $PWD/build:/build falcosecurity/falco-builder install
|
||||
|
||||
How to build.
|
||||
|
||||
* cd docker/builder && DOCKER_BUILDKIT=1 docker build -t falcosecurity/falco-builder .
|
||||
|
||||
In case you want to customise the builder at build time the following build arguments are provided:
|
||||
- BUILD_TYPE whether you want a "release" or "debug" build (defaults to "release").
|
||||
- BUILD_DRIVER whether to build the driver or not (defaults to "OFF")
|
||||
- BUILD_BPF whether to build the BPF driver or not (defaults to "OFF")
|
||||
- BUILD_WARNINGS_AS_ERRORS whether to intend warnings as errors or not (defaults to "ON")
|
||||
- MAKE_JOBS the number of jobs to use during make (defaults to "4")
|
||||
- FALCO_VERSION the version to label the build (built from git index in case it is missing)
|
||||
|
||||
It is possible to change these at runtime (in the container) since environment variables with the same names are provided, too.
|
||||
|
||||
Environment.
|
||||
|
||||
* ${gccversion}
|
||||
* cplusplus ${cppversion}
|
||||
* ${cmakeversion}
|
||||
EOF
|
||||
@@ -1,12 +1,12 @@
|
||||
FROM debian:unstable
|
||||
|
||||
LABEL maintainer="Sysdig <support@sysdig.com>"
|
||||
LABEL usage="docker run -i -t -v /var/run/docker.sock:/host/var/run/docker.sock -v /dev:/host/dev -v /proc:/host/proc:ro -v /boot:/host/boot:ro -v /lib/modules:/host/lib/modules:ro -v /usr:/host/usr:ro --name NAME IMAGE"
|
||||
LABEL maintainer="opensource@sysdig.com"
|
||||
|
||||
ARG FALCO_VERSION=0.1.1dev
|
||||
ARG FALCO_VERSION=
|
||||
RUN test -n FALCO_VERSION
|
||||
ENV FALCO_VERSION ${FALCO_VERSION}
|
||||
|
||||
LABEL RUN="docker run -i -t -v /var/run/docker.sock:/host/var/run/docker.sock -v /dev:/host/dev -v /proc:/host/proc:ro -v /boot:/host/boot:ro -v /lib/modules:/host/lib/modules:ro -v /usr:/host/usr:ro --name NAME IMAGE"
|
||||
|
||||
ENV SYSDIG_HOST_ROOT /host
|
||||
|
||||
ENV HOME /root
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
FROM centos:7
|
||||
FROM fedora:28
|
||||
|
||||
ENV FALCO_VERSION 0.1.1dev
|
||||
ENV BUILD_TYPE Release
|
||||
LABEL name="falcosecurity/falco-tester"
|
||||
LABEL usage="docker run -v /boot:/boot:ro -v /var/run/docker.sock:/var/run/docker.sock -v $PWD/..:/source -v $PWD/build:/build -e FALCO_VERSION=<current_falco_version> --name <name> falcosecurity/falco-tester test"
|
||||
LABEL maintainer="opensource@sysdig.com"
|
||||
|
||||
RUN yum -y install epel-release && \
|
||||
yum -y install \
|
||||
python-pip \
|
||||
docker \
|
||||
jq \
|
||||
unzip
|
||||
ENV FALCO_VERSION=
|
||||
ENV BUILD_TYPE=release
|
||||
|
||||
RUN pip install avocado-framework avocado-framework-plugin-varianter-yaml-to-mux
|
||||
RUN curl https://avocado-project.org/data/repos/avocado-fedora.repo -o /etc/yum.repos.d/avocado.repo && \
|
||||
dnf install -y docker findutils jq unzip python2-avocado python2-avocado-plugins-varianter-yaml-to-mux && dnf clean all
|
||||
|
||||
COPY entrypoint.sh /
|
||||
COPY ./root /
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
ENTRYPOINT ["entrypoint"]
|
||||
CMD ["usage"]
|
||||
@@ -1,24 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
SOURCE_DIR=/source
|
||||
BUILD_DIR=/build
|
||||
TASK=${1:-test}
|
||||
|
||||
if [ $TASK == "test" ]; then
|
||||
echo "Building local docker image falcosecurity/falco:test from latest debian package..."
|
||||
cp $BUILD_DIR/$BUILD_TYPE/falco*.deb $BUILD_DIR/$BUILD_TYPE/docker/local
|
||||
cd $BUILD_DIR/$BUILD_TYPE/docker/local && docker build --build-arg FALCO_VERSION=${FALCO_VERSION} -t falcosecurity/falco:test .
|
||||
|
||||
echo "Running regression tests"
|
||||
cd $SOURCE_DIR/falco/test
|
||||
bash run_regression_tests.sh $BUILD_DIR/$BUILD_TYPE
|
||||
|
||||
docker rmi falcosecurity/falco:test || true
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ $TASK == "bash" ]; then
|
||||
exec /bin/bash
|
||||
fi
|
||||
57
docker/tester/root/usr/bin/entrypoint
Executable file
57
docker/tester/root/usr/bin/entrypoint
Executable file
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
SOURCE_DIR=/source
|
||||
BUILD_DIR=/build
|
||||
CMD=${1:-test}
|
||||
shift
|
||||
|
||||
# Build type can be "debug" or "release", fallbacks to "release" by default
|
||||
BUILD_TYPE=$(echo "$BUILD_TYPE" | tr "[:upper:]" "[:lower:]")
|
||||
case "$BUILD_TYPE" in
|
||||
"debug")
|
||||
;;
|
||||
*)
|
||||
BUILD_TYPE="release"
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$CMD" in
|
||||
"test")
|
||||
if [ ! -d "$BUILD_DIR/$BUILD_TYPE/docker/local" ]; then
|
||||
echo "Missing $BUILD_DIR/$BUILD_TYPE/docker/local directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$FALCO_VERSION" ]; then
|
||||
echo "Missing Falco version." >&2
|
||||
exit 1
|
||||
fi
|
||||
PACKAGE="$BUILD_DIR/$BUILD_TYPE/falco-$FALCO_VERSION-x86_64.deb"
|
||||
if [ ! -f "$PACKAGE" ]; then
|
||||
echo "Package(s) not found." >&2
|
||||
exit 1
|
||||
fi
|
||||
DOCKER_IMAGE_NAME="falcosecurity/falco:test"
|
||||
echo "Building local docker image $DOCKER_IMAGE_NAME from latest debian package..."
|
||||
cp "$PACKAGE" $BUILD_DIR/$BUILD_TYPE/docker/local
|
||||
cd $BUILD_DIR/$BUILD_TYPE/docker/local
|
||||
docker build --build-arg FALCO_VERSION="$FALCO_VERSION" -t "$DOCKER_IMAGE_NAME" .
|
||||
|
||||
# Check that source directory contains Falco and Sysdig
|
||||
if [ ! -d "$SOURCE_DIR/falco/test" ]; then
|
||||
echo "Missing $SOURCE_DIR/falco/test directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Running regression tests ..."
|
||||
cd $SOURCE_DIR/falco/test
|
||||
bash run_regression_tests.sh $BUILD_DIR/$BUILD_TYPE
|
||||
docker rmi "$DOCKER_IMAGE_NAME" || true
|
||||
;;
|
||||
"bash")
|
||||
CMD=/bin/bash
|
||||
;& # fallthrough
|
||||
"usage")
|
||||
exec "$CMD" "$@"
|
||||
;;
|
||||
esac
|
||||
41
docker/tester/root/usr/bin/usage
Executable file
41
docker/tester/root/usr/bin/usage
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
pythonversion=$(python -c 'import sys; version=sys.version_info[:3]; print("{0}.{1}.{2}".format(*version))')
|
||||
pipversion=$(pip --version | cut -d' ' -f 1,2,5,6)
|
||||
dockerversion=$(docker --version)
|
||||
avocadoversion=$(pip show avocado-framework | grep Version)
|
||||
avocadoversion=${avocadoversion#"Version: "}
|
||||
|
||||
cat <<EOF
|
||||
Hello, this is the Falco tester container.
|
||||
|
||||
How to use.
|
||||
|
||||
The default commands for the Falco tester image reports usage and environment info.
|
||||
* docker run falcosecurity/falco-tester
|
||||
* docker run falcosecurity/falco-tester usage
|
||||
|
||||
It supports bash.
|
||||
* docker run -ti falcosecurity/falco-tester bash
|
||||
|
||||
To run Falco regression tests you need to provide:
|
||||
- the docker socket
|
||||
- the boot directory
|
||||
- the source directory
|
||||
- the directory where Falco has been built
|
||||
- the environment variable FALCO_VARIABLE set to the value obtained during the Falco's build
|
||||
|
||||
Assuming you are running it from the Falco root directory, you can run it as follows.
|
||||
* docker run -v /boot:/boot:ro -v /var/run/docker.sock:/var/run/docker.sock -v $PWD/..:/source -v $PWD/build:/build -e FALCO_VERSION=<current_falco_version> falcosecurity/falco-tester test
|
||||
|
||||
How to build.
|
||||
|
||||
* cd docker/builder && DOCKER_BUILDKIT=1 docker build -t falcosecurity/falco-tester .
|
||||
|
||||
Environment.
|
||||
|
||||
* python ${pythonversion}
|
||||
* ${pipversion}
|
||||
* avocado ${avocadoversion}
|
||||
* ${dockerversion}
|
||||
EOF
|
||||
@@ -111,7 +111,7 @@
|
||||
items: [add-shell, remove-shell]
|
||||
|
||||
- macro: shell_procs
|
||||
condition: (proc.name in (shell_binaries))
|
||||
condition: proc.name in (shell_binaries)
|
||||
|
||||
- list: coreutils_binaries
|
||||
items: [
|
||||
@@ -1265,7 +1265,7 @@
|
||||
- list: known_root_files
|
||||
items: [/root/.monit.state, /root/.auth_tokens, /root/.bash_history, /root/.ash_history, /root/.aws/credentials,
|
||||
/root/.viminfo.tmp, /root/.lesshst, /root/.bzr.log, /root/.gitconfig.lock, /root/.babel.json, /root/.localstack,
|
||||
/root/.node_repl_history, /root/.mongorc.js, /root/.dbshell, /root/.augeas/history, /root/.rnd, /root/.wget-hsts, /health]
|
||||
/root/.node_repl_history, /root/.mongorc.js, /root/.dbshell, /root/.augeas/history, /root/.rnd, /root/.wget-hsts, /health, /exec.fifo]
|
||||
|
||||
- list: known_root_directories
|
||||
items: [/root/.oracle_jre_usage, /root/.ssh, /root/.subversion, /root/.nami]
|
||||
@@ -1740,7 +1740,7 @@
|
||||
docker.io/sysdig/agent, docker.io/sysdig/falco, docker.io/sysdig/sysdig,
|
||||
gcr.io/google_containers/kube-proxy, docker.io/calico/node,
|
||||
docker.io/rook/toolbox, docker.io/cloudnativelabs/kube-router, docker.io/mesosphere/mesos-slave,
|
||||
docker.io/docker/ucp-agent, sematext_images
|
||||
docker.io/docker/ucp-agent, sematext_images, k8s.gcr.io/kube-proxy
|
||||
]
|
||||
|
||||
- macro: falco_privileged_containers
|
||||
@@ -1774,7 +1774,8 @@
|
||||
gcr.io/google_containers/hyperkube,
|
||||
gcr.io/google_containers/kube-proxy, docker.io/calico/node,
|
||||
docker.io/rook/toolbox, docker.io/cloudnativelabs/kube-router, docker.io/consul,
|
||||
docker.io/datadog/docker-dd-agent, docker.io/datadog/agent, docker.io/docker/ucp-agent, docker.io/gliderlabs/logspout
|
||||
docker.io/datadog/docker-dd-agent, docker.io/datadog/agent, docker.io/docker/ucp-agent, docker.io/gliderlabs/logspout,
|
||||
docker.io/netdata/netdata, docker.io/google/cadvisor, docker.io/prom/node-exporter
|
||||
]
|
||||
|
||||
- macro: falco_sensitive_mount_containers
|
||||
@@ -1832,7 +1833,7 @@
|
||||
# when we lose events and lose track of state.
|
||||
|
||||
- macro: container_entrypoint
|
||||
condition: (not proc.pname exists or proc.pname in (runc:[0:PARENT], runc:[1:CHILD], docker-runc, exe))
|
||||
condition: (not proc.pname exists or proc.pname in (runc:[0:PARENT], runc:[1:CHILD], runc, docker-runc, exe))
|
||||
|
||||
- rule: Launch Sensitive Mount Container
|
||||
desc: >
|
||||
@@ -2253,7 +2254,7 @@
|
||||
condition: >
|
||||
spawned_process and container and
|
||||
((proc.name = "nc" and (proc.args contains "-e" or proc.args contains "-c")) or
|
||||
(proc.name = "ncat" and (proc.args contains "--sh-exec" or proc.args contains "--exec" or proc.args contains "-e "
|
||||
(proc.name = "ncat" and (proc.args contains "--sh-exec" or proc.args contains "--exec" or proc.args contains "-e "
|
||||
or proc.args contains "-c " or proc.args contains "--lua-exec"))
|
||||
)
|
||||
output: >
|
||||
@@ -2341,12 +2342,16 @@
|
||||
- macro: allowed_clear_log_files
|
||||
condition: (never_true)
|
||||
|
||||
- macro: trusted_logging_images
|
||||
condition: (container.image.repository endswith "splunk/fluentd-hec")
|
||||
|
||||
- rule: Clear Log Activities
|
||||
desc: Detect clearing of critical log files
|
||||
condition: >
|
||||
open_write and
|
||||
access_log_files and
|
||||
evt.arg.flags contains "O_TRUNC" and
|
||||
not trusted_logging_images and
|
||||
not allowed_clear_log_files
|
||||
output: >
|
||||
Log files were tampered (user=%user.name command=%proc.cmdline file=%fd.name container_id=%container.id image=%container.image.repository)
|
||||
|
||||
26
scripts/build
Executable file
26
scripts/build
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -xeuo pipefail
|
||||
|
||||
SOURCE_DIR=$1
|
||||
BUILD_DIR=$2
|
||||
FALCOBUILDER_IMAGE="falcosecurity/falco-builder"
|
||||
FALCOTESTER_IMAGE="falcosecurity/falco-tester"
|
||||
|
||||
docker run --user "$(id -u)":"$(id -g)" -v /etc/passwd:/etc/passwd:ro -e BUILD_TYPE="$BUILD_TYPE" -v "$SOURCE_DIR":/source -v "$BUILD_DIR":/build "$FALCOBUILDER_IMAGE" cmake
|
||||
docker run --user "$(id -u)":"$(id -g)" -v /etc/passwd:/etc/passwd:ro -e BUILD_TYPE="$BUILD_TYPE" -v "$SOURCE_DIR":/source -v "$BUILD_DIR":/build "$FALCOBUILDER_IMAGE" package
|
||||
docker run --user "$(id -u)":"$(id -g)" -v /etc/passwd:/etc/passwd:ro -e BUILD_TYPE="$BUILD_TYPE" -v "$SOURCE_DIR":/source -v "$BUILD_DIR":/build "$FALCOBUILDER_IMAGE" tests
|
||||
|
||||
# Deduct currently built version
|
||||
CURRENT_FALCO_VERSION=$(docker run -v "$BUILD_DIR":/build "$FALCOBUILDER_IMAGE" bash -c "./build/$BUILD_TYPE/userspace/falco/falco --version" | cut -d' ' -f3 | tr -d '\r')
|
||||
|
||||
# Execute regression tests
|
||||
docker run \
|
||||
-v /boot:/boot:ro \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v /etc/passwd:/etc/passwd:ro \
|
||||
-v "$SOURCE_DIR":/source \
|
||||
-v "$BUILD_DIR":/build \
|
||||
-e BUILD_TYPE="$BUILD_TYPE" \
|
||||
-e FALCO_VERSION="$CURRENT_FALCO_VERSION" \
|
||||
"$FALCOTESTER_IMAGE" test
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (C) 2016-2018 Draios Inc dba Sysdig.
|
||||
#
|
||||
@@ -21,17 +21,17 @@ set -ex
|
||||
|
||||
PREFIX=$1
|
||||
|
||||
if [ -z $PREFIX ]; then
|
||||
if [ -z "$PREFIX" ]; then
|
||||
PREFIX=.
|
||||
fi
|
||||
|
||||
mkdir -p $PREFIX
|
||||
|
||||
gcc -O2 -fPIC -I$LUA_INCLUDE -c lpcap.c -o $PREFIX/lpcap.o
|
||||
gcc -O2 -fPIC -I$LUA_INCLUDE -c lpcode.c -o $PREFIX/lpcode.o
|
||||
gcc -O2 -fPIC -I$LUA_INCLUDE -c lpprint.c -o $PREFIX/lpprint.o
|
||||
gcc -O2 -fPIC -I$LUA_INCLUDE -c lptree.c -o $PREFIX/lptree.o
|
||||
gcc -O2 -fPIC -I$LUA_INCLUDE -c lpvm.c -o $PREFIX/lpvm.o
|
||||
gcc -O2 -fPIC -I"$LUA_INCLUDE" -c lpcap.c -o $PREFIX/lpcap.o
|
||||
gcc -O2 -fPIC -I"$LUA_INCLUDE" -c lpcode.c -o $PREFIX/lpcode.o
|
||||
gcc -O2 -fPIC -I"$LUA_INCLUDE" -c lpprint.c -o $PREFIX/lpprint.o
|
||||
gcc -O2 -fPIC -I"$LUA_INCLUDE" -c lptree.c -o $PREFIX/lptree.o
|
||||
gcc -O2 -fPIC -I"$LUA_INCLUDE" -c lpvm.c -o $PREFIX/lpvm.o
|
||||
|
||||
|
||||
# For building lpeg.so, which we don't need now that we're statically linking lpeg.a into falco
|
||||
|
||||
@@ -1,3 +1 @@
|
||||
Sysdig Falco instruments your physical and virtual machines at the OS level by installing into the Linux kernel and capturing system calls and other OS events.
|
||||
Then, using a rule-based configuration, you can specify filters for events of interest that you would like to log or be notified of.
|
||||
|
||||
Falco is an open source project for intrusion and abnormality detection for Cloud Native platforms such as Kubernetes, Mesosphere, and Cloud Foundry. Detect abnormal application behavior. Alert via Slack, Fluentd, NATS, and more. Protect your platform by taking action through serverless (FaaS) frameworks, or other automation.
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (C) 2016-2018 Draios Inc dba Sysdig.
|
||||
#
|
||||
@@ -16,8 +17,6 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
cat ../sysdig/userspace/libscap/syscall_info_table.c | grep EF_DROP_FALCO | sed -e 's/.*\"\(.*\)\".*/\1/' | sort > ignored_syscall_info_table.txt
|
||||
cat ../sysdig/driver/event_table.c | grep EF_DROP_FALCO | sed -e 's/[^\"]*\"\([^\"]*\)\".*/\1/' | sort | uniq > ignored_driver_event_table.txt
|
||||
cat ../sysdig/userspace/libscap/event_table.c | grep EF_DROP_FALCO | sed -e 's/[^\"]*\"\([^\"]*\)\".*/\1/' | sort | uniq > ignored_userspace_event_table.txt
|
||||
|
||||
129
scripts/jenkins/build-pipeline/Jenkinsfile
vendored
129
scripts/jenkins/build-pipeline/Jenkinsfile
vendored
@@ -1,66 +1,95 @@
|
||||
void setBuildStatus(String context, String message, String state) {
|
||||
step([
|
||||
$class: "GitHubCommitStatusSetter",
|
||||
reposSource: [$class: "ManuallyEnteredRepositorySource", url: "https://github.com/falcosecurity/falco"],
|
||||
contextSource: [$class: "ManuallyEnteredCommitContextSource", context: context],
|
||||
errorHandlers: [[$class: "ChangingBuildStatusErrorHandler", result: "UNSTABLE"]],
|
||||
statusResultSource: [ $class: "ConditionalStatusResultSource", results: [[$class: "AnyBuildResult", message: message, state: state]] ]
|
||||
]);
|
||||
$class: "GitHubCommitStatusSetter",
|
||||
reposSource: [
|
||||
$class: "ManuallyEnteredRepositorySource",
|
||||
url: "https://github.com/falcosecurity/falco"
|
||||
],
|
||||
contextSource: [
|
||||
$class: "ManuallyEnteredCommitContextSource",
|
||||
context: context
|
||||
],
|
||||
errorHandlers: [[
|
||||
$class: "ChangingBuildStatusErrorHandler",
|
||||
result: "UNSTABLE"
|
||||
]],
|
||||
statusResultSource: [
|
||||
$class: "ConditionalStatusResultSource",
|
||||
results: [[
|
||||
$class: "AnyBuildResult",
|
||||
message: message,
|
||||
state: state
|
||||
]]
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
def version = 'UNKNOWN'
|
||||
|
||||
pipeline {
|
||||
agent { label "agent-docker-builder" }
|
||||
stages {
|
||||
stage("Check out dependencies") {
|
||||
steps {
|
||||
dir("falco") {
|
||||
checkout([$class: "GitSCM",
|
||||
branches: [[name: "refs/heads/"+env.BRANCH_NAME]],
|
||||
doGenerateSubmoduleConfigurations: false,
|
||||
extensions: [],
|
||||
submoduleCfg: [],
|
||||
userRemoteConfigs: [[credentialsId: "github-jenkins-user-token", url: "https://github.com/draios/falco"]]])
|
||||
}
|
||||
dir("sysdig") {
|
||||
checkout([$class: "GitSCM",
|
||||
branches: [[name: "dev"]],
|
||||
doGenerateSubmoduleConfigurations: false,
|
||||
extensions: [],
|
||||
submoduleCfg: [],
|
||||
userRemoteConfigs: [[credentialsId: "github-jenkins-user-token", url: "https://github.com/draios/sysdig"]]])
|
||||
steps {
|
||||
dir("falco") {
|
||||
checkout([
|
||||
$class: "GitSCM",
|
||||
branches: [[name: "refs/heads/"+env.BRANCH_NAME]],
|
||||
doGenerateSubmoduleConfigurations: false,
|
||||
extensions: [],
|
||||
submoduleCfg: [],
|
||||
userRemoteConfigs: [[
|
||||
credentialsId: "github-jenkins-user-token",
|
||||
url: "https://github.com/falcosecurity/falco"
|
||||
]]
|
||||
])
|
||||
}
|
||||
dir("sysdig") {
|
||||
checkout([
|
||||
$class: "GitSCM",
|
||||
branches: [[name: "dev"]],
|
||||
doGenerateSubmoduleConfigurations: false,
|
||||
extensions: [],
|
||||
submoduleCfg: [],
|
||||
userRemoteConfigs: [[
|
||||
credentialsId: "github-jenkins-user-token",
|
||||
url: "https://github.com/draios/sysdig"
|
||||
]]
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage("Build") {
|
||||
steps {
|
||||
script{
|
||||
sh("./falco/scripts/jenkins/build-pipeline/build.sh")
|
||||
}
|
||||
}
|
||||
post {
|
||||
success {
|
||||
setBuildStatus("Build", "Build Successful", "SUCCESS")
|
||||
}
|
||||
failure {
|
||||
setBuildStatus("Build", "Build Failed", "FAILURE")
|
||||
}
|
||||
}
|
||||
stage("Build") {
|
||||
steps {
|
||||
script{
|
||||
version = sh(returnStdout: true, script: "./falco/scripts/jenkins/build-pipeline/version")
|
||||
sh("./falco/scripts/jenkins/build-pipeline/build ${version}")
|
||||
}
|
||||
}
|
||||
post {
|
||||
success {
|
||||
setBuildStatus("Build", "Build Successful", "SUCCESS")
|
||||
}
|
||||
failure {
|
||||
setBuildStatus("Build", "Build Failed", "FAILURE")
|
||||
}
|
||||
}
|
||||
}
|
||||
stage("Run tests") {
|
||||
steps {
|
||||
script{
|
||||
sh("./falco/scripts/jenkins/build-pipeline/run-tests.sh")
|
||||
}
|
||||
steps {
|
||||
script{
|
||||
sh("./falco/scripts/jenkins/build-pipeline/run-tests ${version}")
|
||||
}
|
||||
}
|
||||
post {
|
||||
success {
|
||||
setBuildStatus("Run tests", "All tests passed", "SUCCESS")
|
||||
}
|
||||
failure {
|
||||
setBuildStatus("Run tests", "One or more tests failed", "FAILURE")
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
success {
|
||||
setBuildStatus("Run tests", "All tests passed", "SUCCESS")
|
||||
}
|
||||
failure {
|
||||
setBuildStatus("Run tests", "One or more tests failed", "FAILURE")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
|
||||
28
scripts/jenkins/build-pipeline/build
Executable file
28
scripts/jenkins/build-pipeline/build
Executable file
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
>&2 echo "Missing arguments."
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$1" ]; then
|
||||
>&2 echo "Missing version."
|
||||
exit 1
|
||||
fi
|
||||
if [ "$1" == "UNKNOWN" ]; then
|
||||
>&2 echo "Unknown version."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
FALCO_VERSION=$1
|
||||
BUILD_DIR="${WORKSPACE}/build"
|
||||
FALCOBUILDER_IMAGE="falcosecurity/falco-builder"
|
||||
|
||||
docker pull $FALCOBUILDER_IMAGE
|
||||
|
||||
rm -rf "$BUILD_DIR"
|
||||
mkdir "$BUILD_DIR"
|
||||
|
||||
docker run -u "$(id -u):$(id -g)" -v /etc/passwd:/etc/passwd:ro -e FALCO_VERSION="$FALCO_VERSION" -v "$WORKSPACE":/source -v "$BUILD_DIR":/build "$FALCOBUILDER_IMAGE" cmake
|
||||
docker run -u "$(id -u):$(id -g)" -v /etc/passwd:/etc/passwd:ro -e FALCO_VERSION="$FALCO_VERSION" -v $"$WORKSPACE":/source -v "$BUILD_DIR":/build "$FALCOBUILDER_IMAGE" package
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -xeuo pipefail
|
||||
|
||||
export FALCO_VERSION=0.1.$((2700+BUILD_NUMBER))dev
|
||||
|
||||
rm -rf ${WORKSPACE}/build
|
||||
mkdir ${WORKSPACE}/build
|
||||
|
||||
docker run --user $(id -u):$(id -g) -v /etc/passwd:/etc/passwd:ro -e FALCO_VERSION=${FALCO_VERSION} -e MAKE_JOBS=4 -v ${WORKSPACE}:/source -v ${WORKSPACE}/build:/build falcosecurity/falco-builder cmake
|
||||
docker run --user $(id -u):$(id -g) -v /etc/passwd:/etc/passwd:ro -e FALCO_VERSION=${FALCO_VERSION} -e MAKE_JOBS=4 -v ${WORKSPACE}:/source -v ${WORKSPACE}/build:/build falcosecurity/falco-builder package
|
||||
33
scripts/jenkins/build-pipeline/run-tests
Executable file
33
scripts/jenkins/build-pipeline/run-tests
Executable file
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
>&2 echo "Missing arguments."
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$1" ]; then
|
||||
>&2 echo "Missing version."
|
||||
exit 1
|
||||
fi
|
||||
if [ "$1" == "UNKNOWN" ]; then
|
||||
>&2 echo "Unknown version."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
FALCO_VERSION=$1
|
||||
BUILD_DIR="${WORKSPACE}/build"
|
||||
FALCOTESTER_IMAGE="falcosecurity/falco-tester"
|
||||
|
||||
docker pull $FALCOTESTER_IMAGE
|
||||
|
||||
docker run \
|
||||
-v /boot:/boot:ro \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v /etc/passwd:/etc/passwd:ro \
|
||||
-e FALCO_VERSION="$FALCO_VERSION" \
|
||||
-v "$WORKSPACE":/source \
|
||||
-v "$BUILD_DIR":/build \
|
||||
"$FALCOTESTER_IMAGE" test
|
||||
|
||||
exit 0
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -xeuo pipefail
|
||||
|
||||
export FALCO_VERSION=0.1.$((2700+BUILD_NUMBER))dev
|
||||
|
||||
docker pull falcosecurity/falco-tester
|
||||
docker run -v /boot:/boot:ro -v /var/run/docker.sock:/var/run/docker.sock -v /etc/passwd:/etc/passwd:ro -e FALCO_VERSION=${FALCO_VERSION} -v ${WORKSPACE}:/source -v ${WORKSPACE}/build:/build falcosecurity/falco-tester
|
||||
|
||||
exit 0
|
||||
23
scripts/jenkins/build-pipeline/version
Executable file
23
scripts/jenkins/build-pipeline/version
Executable file
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Do not add "x"
|
||||
set -eu -o pipefail
|
||||
|
||||
BUILD_DIR="${WORKSPACE}/build"
|
||||
FALCOBUILDER_IMAGE="falcosecurity/falco-builder"
|
||||
|
||||
docker pull $FALCOBUILDER_IMAGE > /dev/null
|
||||
|
||||
rm -rf "$BUILD_DIR"
|
||||
mkdir "$BUILD_DIR"
|
||||
|
||||
CMAKE_CMD="docker run -u $(id -u):$(id -g) -v /etc/passwd:/etc/passwd:ro -v $WORKSPACE:/source -v $BUILD_DIR:/build -a stdout -a stderr $FALCOBUILDER_IMAGE cmake"
|
||||
|
||||
FALCO_VERSION=$($CMAKE_CMD | grep -oP "Falco version: v?\K(\d+)\.[a-z0-9]{1,7}(\.[a-z0-9]+)?" || echo "UNKNOWN")
|
||||
|
||||
if [ "$FALCO_VERSION" == "UNKNOWN" ]; then
|
||||
>&2 echo "Unknown version."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "$FALCO_VERSION.$((2700+BUILD_NUMBER))"
|
||||
1
test/.gitignore
vendored
Normal file
1
test/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
falco_traces.yaml
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (C) 2016-2018 Draios Inc dba Sysdig.
|
||||
#
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright (C) 2016-2018 Draios Inc dba Sysdig.
|
||||
#
|
||||
@@ -34,13 +34,17 @@ class FalcoTest(Test):
|
||||
"""
|
||||
Load the sysdig kernel module if not already loaded.
|
||||
"""
|
||||
build_type = "Release"
|
||||
build_type = "release"
|
||||
if 'BUILD_TYPE' in os.environ:
|
||||
build_type = os.environ['BUILD_TYPE']
|
||||
build_type = os.environ['BUILD_TYPE'].lower()
|
||||
build_type = "debug" if build_type == "debug" else "release"
|
||||
|
||||
build_dir = os.path.join('/build', build_type)
|
||||
self.falcodir = self.params.get('falcodir', '/', default=os.path.join(self.basedir, build_dir))
|
||||
|
||||
self.stdout_is = self.params.get('stdout_is', '*', default='')
|
||||
self.stderr_is = self.params.get('stderr_is', '*', default='')
|
||||
|
||||
self.stdout_contains = self.params.get('stdout_contains', '*', default='')
|
||||
|
||||
if not isinstance(self.stdout_contains, list):
|
||||
@@ -83,8 +87,21 @@ class FalcoTest(Test):
|
||||
if not isinstance(self.rules_file, list):
|
||||
self.rules_file = [self.rules_file]
|
||||
|
||||
self.validate_rules_file = self.params.get('validate_rules_file', '*', default=False)
|
||||
|
||||
if self.validate_rules_file == False:
|
||||
self.validate_rules_file = []
|
||||
else:
|
||||
if not isinstance(self.validate_rules_file, list):
|
||||
self.validate_rules_file = [self.validate_rules_file]
|
||||
|
||||
self.rules_args = ""
|
||||
|
||||
for file in self.validate_rules_file:
|
||||
if not os.path.isabs(file):
|
||||
file = os.path.join(self.basedir, file)
|
||||
self.rules_args = self.rules_args + "-V " + file + " "
|
||||
|
||||
for file in self.rules_file:
|
||||
if not os.path.isabs(file):
|
||||
file = os.path.join(self.basedir, file)
|
||||
@@ -252,7 +269,7 @@ class FalcoTest(Test):
|
||||
triggered_rules = match.group(1)
|
||||
|
||||
for rule, count in self.detect_counts.iteritems():
|
||||
expected = '\s{}: (\d+)'.format(rule)
|
||||
expected = '\s{}: (\d+)'.format(re.sub(r'([$\.*+?()[\]{}|^])', r'\\\1', rule))
|
||||
match = re.search(expected, triggered_rules)
|
||||
|
||||
if match is None:
|
||||
@@ -433,6 +450,15 @@ class FalcoTest(Test):
|
||||
|
||||
res = self.falco_proc.run(timeout=180, sig=9)
|
||||
|
||||
if self.stdout_is != '':
|
||||
print(self.stdout_is)
|
||||
if self.stdout_is != res.stdout:
|
||||
self.fail("Stdout was not exactly {}".format(self.stdout_is))
|
||||
|
||||
if self.stderr_is != '':
|
||||
if self.stderr_is != res.stdout:
|
||||
self.fail("Stdout was not exactly {}".format(self.stderr_is))
|
||||
|
||||
for pattern in self.stderr_contains:
|
||||
match = re.search(pattern, res.stderr)
|
||||
if match is None:
|
||||
|
||||
@@ -86,6 +86,15 @@ trace_files: !mux
|
||||
- rules/rule_names_with_spaces.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_names_with_regex_chars:
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/rule_names_with_regex_chars.yaml
|
||||
detect_counts:
|
||||
- 'Open From Cat ($\.*+?()[]{}|^)': 8
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
multiple_rules_first_empty:
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
@@ -238,6 +247,274 @@ trace_files: !mux
|
||||
- rules/endswith.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_not_yaml:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Rules content is not yaml
|
||||
---
|
||||
This is not yaml
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_not_yaml.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_not_array:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Rules content is not yaml array of objects
|
||||
---
|
||||
foo: bar
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_not_array.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_array_item_not_object:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Unexpected element of type string. Each element should be a yaml associative array.
|
||||
---
|
||||
- foo
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_array_item_not_object.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_unexpected object:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Unknown rule object: {foo="bar"}
|
||||
---
|
||||
- foo: bar
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_unexpected_object.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_engine_version_not_number:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Value of required_engine_version must be a number
|
||||
---
|
||||
- required_engine_version: not-a-number
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_engine_version_not_number.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_yaml_parse_error:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
mapping values are not allowed in this context
|
||||
---
|
||||
this : is : not : yaml
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_yaml_parse_error.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_list_without_items:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
List must have property items
|
||||
---
|
||||
- list: bad_list
|
||||
no_items: foo
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_list_without_items.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_macro_without_condition:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Macro must have property condition
|
||||
---
|
||||
- macro: bad_macro
|
||||
nope: 1
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_macro_without_condition.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_rule_without_output:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Rule must have property output
|
||||
---
|
||||
- rule: no output rule
|
||||
desc: some desc
|
||||
condition: evt.type=fork
|
||||
priority: INFO
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_rule_without_output.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_append_rule_without_condition:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Rule must have property condition
|
||||
---
|
||||
- rule: no condition rule
|
||||
append: true
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_append_rule_without_condition.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_append_macro_dangling:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Macro dangling append has 'append' key but no macro by that name already exists
|
||||
---
|
||||
- macro: dangling append
|
||||
condition: and evt.type=execve
|
||||
append: true
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_append_macro_dangling.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_list_append_dangling:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
List my_list has 'append' key but no list by that name already exists
|
||||
---
|
||||
- list: my_list
|
||||
items: [not-cat]
|
||||
append: true
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/list_append_failure.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_rule_append_dangling:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Rule my_rule has 'append' key but no rule by that name already exists
|
||||
---
|
||||
- rule: my_rule
|
||||
condition: evt.type=open
|
||||
append: true
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/rule_append_failure.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_overwrite_macro:
|
||||
exit_status: 1
|
||||
stdout_contains: |+
|
||||
.*invalid_base_macro.yaml: Ok
|
||||
.*invalid_overwrite_macro.yaml: Compilation error when compiling "foo": Undefined macro 'foo' used in filter.
|
||||
---
|
||||
- macro: some macro
|
||||
condition: foo
|
||||
append: false
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_base_macro.yaml
|
||||
- rules/invalid_overwrite_macro.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_append_macro:
|
||||
exit_status: 1
|
||||
stdout_contains: |+
|
||||
.*invalid_base_macro.yaml: Ok
|
||||
.*invalid_append_macro.yaml: Compilation error when compiling "evt.type=execve foo": 17: syntax error, unexpected 'foo', expecting 'or', 'and'
|
||||
---
|
||||
- macro: some macro
|
||||
condition: evt.type=execve
|
||||
|
||||
- macro: some macro
|
||||
condition: foo
|
||||
append: true
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_base_macro.yaml
|
||||
- rules/invalid_append_macro.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_overwrite_rule:
|
||||
exit_status: 1
|
||||
stdout_contains: |+
|
||||
.*invalid_base_rule.yaml: Ok
|
||||
.*invalid_overwrite_rule.yaml: Undefined macro 'bar' used in filter.
|
||||
---
|
||||
- rule: some rule
|
||||
desc: some desc
|
||||
condition: bar
|
||||
output: some output
|
||||
priority: INFO
|
||||
append: false
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_base_rule.yaml
|
||||
- rules/invalid_overwrite_rule.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_append_rule:
|
||||
exit_status: 1
|
||||
stdout_contains: |+
|
||||
.*invalid_base_rule.yaml: Ok
|
||||
.*invalid_append_rule.yaml: Compilation error when compiling "evt.type=open bar": 15: syntax error, unexpected 'bar', expecting 'or', 'and'
|
||||
---
|
||||
- rule: some rule
|
||||
desc: some desc
|
||||
condition: evt.type=open
|
||||
output: some output
|
||||
priority: INFO
|
||||
|
||||
- rule: some rule
|
||||
desc: some desc
|
||||
condition: bar
|
||||
output: some output
|
||||
priority: INFO
|
||||
append: true
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_base_rule.yaml
|
||||
- rules/invalid_append_rule.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_missing_rule_name:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Rule name is empty
|
||||
---
|
||||
- rule:
|
||||
desc: some desc
|
||||
condition: evt.type=execve
|
||||
output: some output
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_missing_rule_name.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_missing_list_name:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
List name is empty
|
||||
---
|
||||
- list:
|
||||
items: [foo]
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_missing_list_name.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_missing_macro_name:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Macro name is empty
|
||||
---
|
||||
- macro:
|
||||
condition: evt.type=execve
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_missing_macro_name.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_rule_output:
|
||||
exit_status: 1
|
||||
stderr_contains: "Runtime error: Error loading rules:.* Invalid output format 'An open was seen %not_a_real_field': 'invalid formatting token not_a_real_field'. Exiting."
|
||||
@@ -254,13 +531,13 @@ trace_files: !mux
|
||||
- open_from_cat
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
disabled_rules_using_regex:
|
||||
disabled_rules_using_substring:
|
||||
detect: False
|
||||
rules_file:
|
||||
- rules/empty_rules.yaml
|
||||
- rules/single_rule.yaml
|
||||
disabled_rules:
|
||||
- "open.*"
|
||||
- "open_from"
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
disabled_rules_using_enabled_flag:
|
||||
@@ -601,7 +878,7 @@ trace_files: !mux
|
||||
|
||||
list_append_failure:
|
||||
exit_status: 1
|
||||
stderr_contains: "List my_list has 'append' key but no list by that name already exists. Exiting"
|
||||
stderr_contains: "List my_list has 'append' key but no list by that name already exists"
|
||||
rules_file:
|
||||
- rules/list_append_failure.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
@@ -621,7 +898,7 @@ trace_files: !mux
|
||||
|
||||
macro_append_failure:
|
||||
exit_status: 1
|
||||
stderr_contains: "Macro my_macro has 'append' key but no macro by that name already exists. Exiting"
|
||||
stderr_contains: "Macro my_macro has 'append' key but no macro by that name already exists"
|
||||
rules_file:
|
||||
- rules/macro_append_failure.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
@@ -641,7 +918,7 @@ trace_files: !mux
|
||||
|
||||
rule_append_failure:
|
||||
exit_status: 1
|
||||
stderr_contains: "Rule my_rule has 'append' key but no rule by that name already exists. Exiting"
|
||||
stderr_contains: "Rule my_rule has 'append' key but no rule by that name already exists"
|
||||
rules_file:
|
||||
- rules/rule_append_failure.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
3
test/rules/invalid_append_macro.yaml
Normal file
3
test/rules/invalid_append_macro.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
- macro: some macro
|
||||
condition: foo
|
||||
append: true
|
||||
3
test/rules/invalid_append_macro_dangling.yaml
Normal file
3
test/rules/invalid_append_macro_dangling.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
- macro: dangling append
|
||||
condition: and evt.type=execve
|
||||
append: true
|
||||
6
test/rules/invalid_append_rule.yaml
Normal file
6
test/rules/invalid_append_rule.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
- rule: some rule
|
||||
desc: some desc
|
||||
condition: bar
|
||||
output: some output
|
||||
priority: INFO
|
||||
append: true
|
||||
2
test/rules/invalid_append_rule_without_condition.yaml
Normal file
2
test/rules/invalid_append_rule_without_condition.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
- rule: no condition rule
|
||||
append: true
|
||||
1
test/rules/invalid_array_item_not_object.yaml
Normal file
1
test/rules/invalid_array_item_not_object.yaml
Normal file
@@ -0,0 +1 @@
|
||||
- foo
|
||||
2
test/rules/invalid_base_macro.yaml
Normal file
2
test/rules/invalid_base_macro.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
- macro: some macro
|
||||
condition: evt.type=execve
|
||||
5
test/rules/invalid_base_rule.yaml
Normal file
5
test/rules/invalid_base_rule.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
- rule: some rule
|
||||
desc: some desc
|
||||
condition: evt.type=open
|
||||
output: some output
|
||||
priority: INFO
|
||||
5
test/rules/invalid_condition_not_rule.yaml
Normal file
5
test/rules/invalid_condition_not_rule.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
- rule: condition not rule
|
||||
condition:
|
||||
desc: some desc
|
||||
output: some output
|
||||
priority: INFO
|
||||
34
test/rules/invalid_engine_version_not_number.yaml
Normal file
34
test/rules/invalid_engine_version_not_number.yaml
Normal file
@@ -0,0 +1,34 @@
|
||||
#
|
||||
# Copyright (C) 2016-2018 Draios Inc dba Sysdig.
|
||||
#
|
||||
# This file is part of falco.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
- required_engine_version: not-a-number
|
||||
|
||||
- list: cat_binaries
|
||||
items: [cat]
|
||||
|
||||
- list: cat_capable_binaries
|
||||
items: [cat_binaries]
|
||||
|
||||
- macro: is_cat
|
||||
condition: proc.name in (cat_capable_binaries)
|
||||
|
||||
- rule: open_from_cat
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and is_cat
|
||||
output: "An open was seen (command=%proc.cmdline)"
|
||||
priority: WARNING
|
||||
5
test/rules/invalid_list_without_items.yaml
Normal file
5
test/rules/invalid_list_without_items.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
- list: good_list
|
||||
items: [foo]
|
||||
|
||||
- list: bad_list
|
||||
no_items: foo
|
||||
2
test/rules/invalid_macro_comple_error.yaml
Normal file
2
test/rules/invalid_macro_comple_error.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
- macro: macro with comp error
|
||||
condition: gak
|
||||
6
test/rules/invalid_macro_without_condition.yaml
Normal file
6
test/rules/invalid_macro_without_condition.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
- macro: bad_macro
|
||||
nope: 1
|
||||
|
||||
- macro: good_macro
|
||||
condition: evt.type=execve
|
||||
|
||||
2
test/rules/invalid_missing_list_name.yaml
Normal file
2
test/rules/invalid_missing_list_name.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
- list:
|
||||
items: [foo]
|
||||
2
test/rules/invalid_missing_macro_name.yaml
Normal file
2
test/rules/invalid_missing_macro_name.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
- macro:
|
||||
condition: evt.type=execve
|
||||
4
test/rules/invalid_missing_rule_name.yaml
Normal file
4
test/rules/invalid_missing_rule_name.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
- rule:
|
||||
desc: some desc
|
||||
condition: evt.type=execve
|
||||
output: some output
|
||||
1
test/rules/invalid_not_array.yaml
Normal file
1
test/rules/invalid_not_array.yaml
Normal file
@@ -0,0 +1 @@
|
||||
foo: bar
|
||||
1
test/rules/invalid_not_yaml.yaml
Normal file
1
test/rules/invalid_not_yaml.yaml
Normal file
@@ -0,0 +1 @@
|
||||
This is not yaml
|
||||
3
test/rules/invalid_overwrite_macro.yaml
Normal file
3
test/rules/invalid_overwrite_macro.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
- macro: some macro
|
||||
condition: foo
|
||||
append: false
|
||||
6
test/rules/invalid_overwrite_rule.yaml
Normal file
6
test/rules/invalid_overwrite_rule.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
- rule: some rule
|
||||
desc: some desc
|
||||
condition: bar
|
||||
output: some output
|
||||
priority: INFO
|
||||
append: false
|
||||
4
test/rules/invalid_rule_without_output.yaml
Normal file
4
test/rules/invalid_rule_without_output.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
- rule: no output rule
|
||||
desc: some desc
|
||||
condition: evt.type=fork
|
||||
priority: INFO
|
||||
1
test/rules/invalid_unexpected_object.yaml
Normal file
1
test/rules/invalid_unexpected_object.yaml
Normal file
@@ -0,0 +1 @@
|
||||
- foo: bar
|
||||
1
test/rules/invalid_yaml_parse_error.yaml
Normal file
1
test/rules/invalid_yaml_parse_error.yaml
Normal file
@@ -0,0 +1 @@
|
||||
this : is : not : yaml
|
||||
25
test/rules/rule_names_with_regex_chars.yaml
Normal file
25
test/rules/rule_names_with_regex_chars.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
#
|
||||
# Copyright (C) 2016-2018 Draios Inc dba Sysdig.
|
||||
#
|
||||
# This file is part of falco.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
- macro: is_cat
|
||||
condition: proc.name=cat
|
||||
|
||||
- rule: Open From Cat ($\.*+?()[]{}|^)
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and is_cat
|
||||
output: "An open was seen (command=%proc.cmdline)"
|
||||
priority: WARNING
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (C) 2016-2018 Draios Inc dba Sysdig.
|
||||
#
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (C) 2016-2018 Draios Inc dba Sysdig.
|
||||
#
|
||||
|
||||
Binary file not shown.
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (C) 2016-2018 Draios Inc dba Sysdig.
|
||||
#
|
||||
@@ -23,4 +23,4 @@
|
||||
|
||||
# The remaining arguments are taken from the command line.
|
||||
|
||||
exec sudo sysdig not evt.type in '(mprotect,brk,mq_timedreceive,mq_receive,mq_timedsend,mq_send,getrusage,procinfo,rt_sigprocmask,rt_sigaction,ioctl,clock_getres,clock_gettime,clock_nanosleep,clock_settime,close,epoll_create,epoll_create1,epoll_ctl,epoll_pwait,epoll_wait,eventfd,fcntl,fcntl64,fstat,fstat64,fstatat64,fstatfs,fstatfs64,futex,getitimer,gettimeofday,ioprio_get,ioprio_set,llseek,lseek,lstat,lstat64,mmap,mmap2,munmap,nanosleep,poll,ppoll,pread,pread64,preadv,procinfo,pselect6,pwrite,pwrite64,pwritev,read,readv,recv,recvfrom,recvmmsg,recvmsg,sched_yield,select,send,sendfile,sendfile64,sendmmsg,sendmsg,sendto,setitimer,settimeofday,shutdown,splice,stat,stat64,statfs,statfs64,switch,tee,timer_create,timer_delete,timerfd_create,timerfd_gettime,timerfd_settime,timer_getoverrun,timer_gettime,timer_settime,wait4,write,writev) and user.name!=ec2-user' $@
|
||||
exec sudo sysdig not evt.type in '(mprotect,brk,mq_timedreceive,mq_receive,mq_timedsend,mq_send,getrusage,procinfo,rt_sigprocmask,rt_sigaction,ioctl,clock_getres,clock_gettime,clock_nanosleep,clock_settime,close,epoll_create,epoll_create1,epoll_ctl,epoll_pwait,epoll_wait,eventfd,fcntl,fcntl64,fstat,fstat64,fstatat64,fstatfs,fstatfs64,futex,getitimer,gettimeofday,ioprio_get,ioprio_set,llseek,lseek,lstat,lstat64,mmap,mmap2,munmap,nanosleep,poll,ppoll,pread,pread64,preadv,procinfo,pselect6,pwrite,pwrite64,pwritev,read,readv,recv,recvfrom,recvmmsg,recvmsg,sched_yield,select,send,sendfile,sendfile64,sendmmsg,sendmsg,sendto,setitimer,settimeofday,shutdown,splice,stat,stat64,statfs,statfs64,switch,tee,timer_create,timer_delete,timerfd_create,timerfd_gettime,timerfd_settime,timer_getoverrun,timer_gettime,timer_settime,wait4,write,writev) and user.name!=ec2-user' "$@"
|
||||
|
||||
@@ -206,17 +206,17 @@ void falco_engine::load_rules_file(const string &rules_filename, bool verbose, b
|
||||
load_rules(rules_content, verbose, all_events, required_engine_version);
|
||||
}
|
||||
|
||||
void falco_engine::enable_rule(const string &pattern, bool enabled, const string &ruleset)
|
||||
void falco_engine::enable_rule(const string &substring, bool enabled, const string &ruleset)
|
||||
{
|
||||
uint16_t ruleset_id = find_ruleset_id(ruleset);
|
||||
|
||||
m_sinsp_rules->enable(pattern, enabled, ruleset_id);
|
||||
m_k8s_audit_rules->enable(pattern, enabled, ruleset_id);
|
||||
m_sinsp_rules->enable(substring, enabled, ruleset_id);
|
||||
m_k8s_audit_rules->enable(substring, enabled, ruleset_id);
|
||||
}
|
||||
|
||||
void falco_engine::enable_rule(const string &pattern, bool enabled)
|
||||
void falco_engine::enable_rule(const string &substring, bool enabled)
|
||||
{
|
||||
enable_rule(pattern, enabled, m_default_ruleset);
|
||||
enable_rule(substring, enabled, m_default_ruleset);
|
||||
}
|
||||
|
||||
void falco_engine::enable_rule_by_tag(const set<string> &tags, bool enabled, const string &ruleset)
|
||||
|
||||
@@ -76,16 +76,17 @@ public:
|
||||
void load_rules(const std::string &rules_content, bool verbose, bool all_events, uint64_t &required_engine_version);
|
||||
|
||||
//
|
||||
// Enable/Disable any rules matching the provided pattern
|
||||
// (regex). When provided, enable/disable these rules in the
|
||||
// Enable/Disable any rules matching the provided substring.
|
||||
// If the substring is "", all rules are enabled/disabled.
|
||||
// When provided, enable/disable these rules in the
|
||||
// context of the provided ruleset. The ruleset (id) can later
|
||||
// be passed as an argument to process_event(). This allows
|
||||
// for different sets of rules being active at once.
|
||||
//
|
||||
void enable_rule(const std::string &pattern, bool enabled, const std::string &ruleset);
|
||||
void enable_rule(const std::string &substring, bool enabled, const std::string &ruleset);
|
||||
|
||||
// Wrapper that assumes the default ruleset
|
||||
void enable_rule(const std::string &pattern, bool enabled);
|
||||
void enable_rule(const std::string &substring, bool enabled);
|
||||
|
||||
//
|
||||
// Enable/Disable any rules with any of the provided tags (set, exact matches only)
|
||||
|
||||
@@ -19,9 +19,9 @@ limitations under the License.
|
||||
|
||||
// The version of rules/filter fields/etc supported by this falco
|
||||
// engine.
|
||||
#define FALCO_ENGINE_VERSION (3)
|
||||
#define FALCO_ENGINE_VERSION (4)
|
||||
|
||||
// This is the result of running "falco --list -N | sha256sum" and
|
||||
// represents the fields supported by this version of falco. It's used
|
||||
// at build time to detect a changed set of fields.
|
||||
#define FALCO_FIELDS_CHECKSUM "9b5557ec8f16f5606a1544573b152d211d5212f653ee039146836a17266ff449"
|
||||
#define FALCO_FIELDS_CHECKSUM "ceb069d9f9b2d4ebcc5de39bddc53b7af2e6b8f072edc293668fd6ac4e532413"
|
||||
|
||||
@@ -19,8 +19,8 @@ limitations under the License.
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "uri.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include "falco_common.h"
|
||||
#include "json_evt.h"
|
||||
@@ -30,7 +30,6 @@ using namespace std;
|
||||
|
||||
json_event::json_event()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
json_event::~json_event()
|
||||
@@ -60,7 +59,7 @@ std::string json_event_filter_check::def_format(const json &j, std::string &fiel
|
||||
|
||||
std::string json_event_filter_check::json_as_string(const json &j)
|
||||
{
|
||||
if (j.type() == json::value_t::string)
|
||||
if(j.type() == json::value_t::string)
|
||||
{
|
||||
return j;
|
||||
}
|
||||
@@ -70,32 +69,35 @@ std::string json_event_filter_check::json_as_string(const json &j)
|
||||
}
|
||||
}
|
||||
|
||||
json_event_filter_check::field_info::field_info()
|
||||
: m_idx_mode(IDX_NONE), m_idx_type(IDX_NUMERIC)
|
||||
json_event_filter_check::field_info::field_info():
|
||||
m_idx_mode(IDX_NONE), m_idx_type(IDX_NUMERIC)
|
||||
{
|
||||
}
|
||||
|
||||
json_event_filter_check::field_info::field_info(std::string name,
|
||||
std::string desc)
|
||||
: m_name(name), m_desc(desc),
|
||||
m_idx_mode(IDX_NONE), m_idx_type(IDX_NUMERIC)
|
||||
std::string desc):
|
||||
m_name(name),
|
||||
m_desc(desc),
|
||||
m_idx_mode(IDX_NONE), m_idx_type(IDX_NUMERIC)
|
||||
{
|
||||
}
|
||||
|
||||
json_event_filter_check::field_info::field_info(std::string name,
|
||||
std::string desc,
|
||||
index_mode mode)
|
||||
: m_name(name), m_desc(desc),
|
||||
m_idx_mode(mode), m_idx_type(IDX_NUMERIC)
|
||||
index_mode mode):
|
||||
m_name(name),
|
||||
m_desc(desc),
|
||||
m_idx_mode(mode), m_idx_type(IDX_NUMERIC)
|
||||
{
|
||||
}
|
||||
|
||||
json_event_filter_check::field_info::field_info(std::string name,
|
||||
std::string desc,
|
||||
index_mode mode,
|
||||
index_type itype)
|
||||
: m_name(name), m_desc(desc),
|
||||
m_idx_mode(mode), m_idx_type(itype)
|
||||
index_type itype):
|
||||
m_name(name),
|
||||
m_desc(desc),
|
||||
m_idx_mode(mode), m_idx_type(itype)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -107,14 +109,15 @@ json_event_filter_check::alias::alias()
|
||||
{
|
||||
}
|
||||
|
||||
json_event_filter_check::alias::alias(nlohmann::json::json_pointer ptr)
|
||||
: m_jptr(ptr), m_format(def_format)
|
||||
json_event_filter_check::alias::alias(nlohmann::json::json_pointer ptr):
|
||||
m_jptr(ptr), m_format(def_format)
|
||||
{
|
||||
}
|
||||
|
||||
json_event_filter_check::alias::alias(nlohmann::json::json_pointer ptr,
|
||||
format_t format)
|
||||
: m_jptr(ptr), m_format(format)
|
||||
format_t format):
|
||||
m_jptr(ptr),
|
||||
m_format(format)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -122,8 +125,8 @@ json_event_filter_check::alias::~alias()
|
||||
{
|
||||
}
|
||||
|
||||
json_event_filter_check::json_event_filter_check()
|
||||
: m_format(def_format)
|
||||
json_event_filter_check::json_event_filter_check():
|
||||
m_format(def_format)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -150,7 +153,7 @@ int32_t json_event_filter_check::parse_field_name(const char *str, bool alloc_st
|
||||
|
||||
// What follows the match must not be alphanumeric or a dot
|
||||
if(strncmp(info.m_name.c_str(), str, info.m_name.size()) == 0 &&
|
||||
!isalnum((int) str[info.m_name.size()]) &&
|
||||
!isalnum((int)str[info.m_name.size()]) &&
|
||||
str[info.m_name.size()] != '.' &&
|
||||
info.m_name.size() > match_len)
|
||||
{
|
||||
@@ -169,7 +172,7 @@ int32_t json_event_filter_check::parse_field_name(const char *str, bool alloc_st
|
||||
|
||||
if(end != NULL)
|
||||
{
|
||||
m_idx = string(start, end-start);
|
||||
m_idx = string(start, end - start);
|
||||
}
|
||||
|
||||
idx_len = (end - start + 2);
|
||||
@@ -197,14 +200,14 @@ int32_t json_event_filter_check::parse_field_name(const char *str, bool alloc_st
|
||||
return match_len + idx_len;
|
||||
}
|
||||
|
||||
void json_event_filter_check::add_filter_value(const char* str, uint32_t len, uint32_t i)
|
||||
void json_event_filter_check::add_filter_value(const char *str, uint32_t len, uint32_t i)
|
||||
{
|
||||
m_values.push_back(string(str));
|
||||
}
|
||||
|
||||
bool json_event_filter_check::compare(gen_event *evt)
|
||||
{
|
||||
json_event *jevt = (json_event *) evt;
|
||||
json_event *jevt = (json_event *)evt;
|
||||
|
||||
std::string value = extract(jevt);
|
||||
|
||||
@@ -225,7 +228,7 @@ bool json_event_filter_check::compare(gen_event *evt)
|
||||
case CO_IN:
|
||||
for(auto &val : m_values)
|
||||
{
|
||||
if (value == val)
|
||||
if(value == val)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -268,11 +271,12 @@ json_event_filter_check::check_info &json_event_filter_check::get_fields()
|
||||
return m_info;
|
||||
}
|
||||
|
||||
uint8_t* json_event_filter_check::extract(gen_event *evt, uint32_t* len, bool sanitize_strings)
|
||||
uint8_t *json_event_filter_check::extract(gen_event *evt, uint32_t *len, bool sanitize_strings)
|
||||
{
|
||||
json_event *jevt = (json_event *) evt;
|
||||
json_event *jevt = (json_event *)evt;
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
const json &j = jevt->jevt().at(m_jptr);
|
||||
|
||||
// Only format when the value was actually found in
|
||||
@@ -286,7 +290,7 @@ uint8_t* json_event_filter_check::extract(gen_event *evt, uint32_t* len, bool sa
|
||||
|
||||
*len = m_tstr.size();
|
||||
|
||||
return (uint8_t *) m_tstr.c_str();
|
||||
return (uint8_t *)m_tstr.c_str();
|
||||
}
|
||||
|
||||
std::string json_event_filter_check::extract(json_event *evt)
|
||||
@@ -299,7 +303,7 @@ std::string json_event_filter_check::extract(json_event *evt)
|
||||
|
||||
if(res != NULL)
|
||||
{
|
||||
ret.assign((const char *) res, len);
|
||||
ret.assign((const char *)res, len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -315,18 +319,15 @@ jevt_filter_check::jevt_filter_check()
|
||||
{
|
||||
m_info = {"jevt",
|
||||
"generic ways to access json events",
|
||||
{
|
||||
{s_jevt_time_field, "json event timestamp as a string that includes the nanosecond part"},
|
||||
{s_jevt_time_iso_8601_field, "json event timestamp in ISO 8601 format, including nanoseconds and time zone offset (in UTC)"},
|
||||
{s_jevt_rawtime_field, "absolute event timestamp, i.e. nanoseconds from epoch."},
|
||||
{s_jevt_value_field, "General way to access single property from json object. The syntax is [<json pointer expression>]. The property is returned as a string", IDX_REQUIRED, IDX_KEY},
|
||||
{s_jevt_obj_field, "The entire json object, stringified"}
|
||||
}};
|
||||
{{s_jevt_time_field, "json event timestamp as a string that includes the nanosecond part"},
|
||||
{s_jevt_time_iso_8601_field, "json event timestamp in ISO 8601 format, including nanoseconds and time zone offset (in UTC)"},
|
||||
{s_jevt_rawtime_field, "absolute event timestamp, i.e. nanoseconds from epoch."},
|
||||
{s_jevt_value_field, "General way to access single property from json object. The syntax is [<json pointer expression>]. The property is returned as a string", IDX_REQUIRED, IDX_KEY},
|
||||
{s_jevt_obj_field, "The entire json object, stringified"}}};
|
||||
}
|
||||
|
||||
jevt_filter_check::~jevt_filter_check()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int32_t jevt_filter_check::parse_field_name(const char *str, bool alloc_state, bool needed_for_filtering)
|
||||
@@ -360,55 +361,56 @@ int32_t jevt_filter_check::parse_field_name(const char *str, bool alloc_state, b
|
||||
const char *end;
|
||||
|
||||
// What follows must be [<json pointer expression>]
|
||||
if (*(str + s_jevt_value_field.size()) != '[' ||
|
||||
((end = strchr(str + 1, ']')) == NULL))
|
||||
if(*(str + s_jevt_value_field.size()) != '[' ||
|
||||
((end = strchr(str + 1, ']')) == NULL))
|
||||
|
||||
{
|
||||
throw falco_exception(string("Could not parse filtercheck field \"") + str + "\". Did not have expected format with 'jevt.value[<json pointer>]'");
|
||||
}
|
||||
|
||||
try {
|
||||
m_jptr = json::json_pointer(string(str + (s_jevt_value_field.size()+1), (end-str-(s_jevt_value_field.size()+1))));
|
||||
try
|
||||
{
|
||||
m_jptr = json::json_pointer(string(str + (s_jevt_value_field.size() + 1), (end - str - (s_jevt_value_field.size() + 1))));
|
||||
}
|
||||
catch (json::parse_error& e)
|
||||
catch(json::parse_error &e)
|
||||
{
|
||||
throw falco_exception(string("Could not parse filtercheck field \"") + str + "\". Invalid json selector (" + e.what() + ")");
|
||||
}
|
||||
|
||||
// The +1 accounts for the closing ']'
|
||||
m_field = string(str, end-str + 1);
|
||||
m_field = string(str, end - str + 1);
|
||||
return (end - str + 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t* jevt_filter_check::extract(gen_event *evt, uint32_t* len, bool sanitize_stings)
|
||||
uint8_t *jevt_filter_check::extract(gen_event *evt, uint32_t *len, bool sanitize_stings)
|
||||
{
|
||||
if(m_field == s_jevt_rawtime_field)
|
||||
{
|
||||
m_tstr = to_string(evt->get_ts());
|
||||
*len = m_tstr.size();
|
||||
return (uint8_t *) m_tstr.c_str();
|
||||
return (uint8_t *)m_tstr.c_str();
|
||||
}
|
||||
else if(m_field == s_jevt_time_field)
|
||||
{
|
||||
sinsp_utils::ts_to_string(evt->get_ts(), &m_tstr, false, true);
|
||||
*len = m_tstr.size();
|
||||
return (uint8_t *) m_tstr.c_str();
|
||||
return (uint8_t *)m_tstr.c_str();
|
||||
}
|
||||
else if(m_field == s_jevt_time_iso_8601_field)
|
||||
{
|
||||
sinsp_utils::ts_to_iso_8601(evt->get_ts(), &m_tstr);
|
||||
*len = m_tstr.size();
|
||||
return (uint8_t *) m_tstr.c_str();
|
||||
return (uint8_t *)m_tstr.c_str();
|
||||
}
|
||||
else if(m_field == s_jevt_obj_field)
|
||||
{
|
||||
json_event *jevt = (json_event *) evt;
|
||||
json_event *jevt = (json_event *)evt;
|
||||
m_tstr = jevt->jevt().dump();
|
||||
*len = m_tstr.size();
|
||||
return (uint8_t *) m_tstr.c_str();
|
||||
return (uint8_t *)m_tstr.c_str();
|
||||
}
|
||||
|
||||
return json_event_filter_check::extract(evt, len, sanitize_stings);
|
||||
@@ -418,7 +420,7 @@ json_event_filter_check *jevt_filter_check::allocate_new()
|
||||
{
|
||||
jevt_filter_check *chk = new jevt_filter_check();
|
||||
|
||||
return (json_event_filter_check *) chk;
|
||||
return (json_event_filter_check *)chk;
|
||||
}
|
||||
|
||||
std::string k8s_audit_filter_check::index_image(const json &j, std::string &field, std::string &idx)
|
||||
@@ -427,8 +429,9 @@ std::string k8s_audit_filter_check::index_image(const json &j, std::string &fiel
|
||||
|
||||
string image;
|
||||
|
||||
try {
|
||||
image = j[idx_num].at("image");
|
||||
try
|
||||
{
|
||||
image = j[idx_num].at("image");
|
||||
}
|
||||
catch(json::out_of_range &e)
|
||||
{
|
||||
@@ -470,7 +473,6 @@ std::string k8s_audit_filter_check::index_has_name(const json &j, std::string &f
|
||||
return string("false");
|
||||
}
|
||||
|
||||
|
||||
std::string k8s_audit_filter_check::index_query_param(const json &j, std::string &field, std::string &idx)
|
||||
{
|
||||
string uri = j;
|
||||
@@ -489,7 +491,7 @@ std::string k8s_audit_filter_check::index_query_param(const json &j, std::string
|
||||
{
|
||||
std::vector<std::string> param_parts = sinsp_split(part, '=');
|
||||
|
||||
if(param_parts.size() == 2 && uri::decode(param_parts[0], true)==idx)
|
||||
if(param_parts.size() == 2 && uri::decode(param_parts[0], true) == idx)
|
||||
{
|
||||
return uri::decode(param_parts[1]);
|
||||
}
|
||||
@@ -498,7 +500,6 @@ std::string k8s_audit_filter_check::index_query_param(const json &j, std::string
|
||||
return string("<NA>");
|
||||
}
|
||||
|
||||
|
||||
std::string k8s_audit_filter_check::index_generic(const json &j, std::string &field, std::string &idx)
|
||||
{
|
||||
json item;
|
||||
@@ -511,7 +512,8 @@ std::string k8s_audit_filter_check::index_generic(const json &j, std::string &fi
|
||||
{
|
||||
uint64_t idx_num = (idx.empty() ? 0 : stoi(idx));
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
item = j[idx_num];
|
||||
}
|
||||
catch(json::out_of_range &e)
|
||||
@@ -529,7 +531,7 @@ std::string k8s_audit_filter_check::index_select(const json &j, std::string &fie
|
||||
|
||||
// Use the suffix of the field to determine which property to
|
||||
// select from each object.
|
||||
std::string prop = field.substr(field.find_last_of(".")+1);
|
||||
std::string prop = field.substr(field.find_last_of(".") + 1);
|
||||
|
||||
std::string ret;
|
||||
|
||||
@@ -542,7 +544,8 @@ std::string k8s_audit_filter_check::index_select(const json &j, std::string &fie
|
||||
ret += " ";
|
||||
}
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
ret += json_event_filter_check::json_as_string(obj.at(prop));
|
||||
}
|
||||
catch(json::out_of_range &e)
|
||||
@@ -553,7 +556,8 @@ std::string k8s_audit_filter_check::index_select(const json &j, std::string &fie
|
||||
}
|
||||
else
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
ret = j[stoi(idx)].at(prop);
|
||||
}
|
||||
catch(json::out_of_range &e)
|
||||
@@ -573,7 +577,8 @@ std::string k8s_audit_filter_check::index_privileged(const json &j, std::string
|
||||
|
||||
if(!idx.empty())
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
privileged = j[stoi(idx)].at(jpriv);
|
||||
}
|
||||
catch(json::out_of_range &e)
|
||||
@@ -584,7 +589,8 @@ std::string k8s_audit_filter_check::index_privileged(const json &j, std::string
|
||||
{
|
||||
for(auto &container : j)
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
if(container.at(jpriv))
|
||||
{
|
||||
privileged = true;
|
||||
@@ -621,42 +627,41 @@ k8s_audit_filter_check::k8s_audit_filter_check()
|
||||
{
|
||||
m_info = {"ka",
|
||||
"Access K8s Audit Log Events",
|
||||
{
|
||||
{"ka.auditid", "The unique id of the audit event"},
|
||||
{"ka.stage", "Stage of the request (e.g. RequestReceived, ResponseComplete, etc.)"},
|
||||
{"ka.auth.decision", "The authorization decision"},
|
||||
{"ka.auth.reason", "The authorization reason"},
|
||||
{"ka.user.name", "The user name performing the request"},
|
||||
{"ka.user.groups", "The groups to which the user belongs"},
|
||||
{"ka.impuser.name", "The impersonated user name"},
|
||||
{"ka.verb", "The action being performed"},
|
||||
{"ka.uri", "The request URI as sent from client to server"},
|
||||
{"ka.uri.param", "The value of a given query parameter in the uri (e.g. when uri=/foo?key=val, ka.uri.param[key] is val).", IDX_REQUIRED, IDX_KEY},
|
||||
{"ka.target.name", "The target object name"},
|
||||
{"ka.target.namespace", "The target object namespace"},
|
||||
{"ka.target.resource", "The target object resource"},
|
||||
{"ka.target.subresource", "The target object subresource"},
|
||||
{"ka.req.binding.subjects", "When the request object refers to a cluster role binding, the subject (e.g. account/users) being linked by the binding"},
|
||||
{"ka.req.binding.subject.has_name", "When the request object refers to a cluster role binding, return true if a subject with the provided name exists", IDX_REQUIRED, IDX_KEY},
|
||||
{"ka.req.binding.role", "When the request object refers to a cluster role binding, the role being linked by the binding"},
|
||||
{"ka.req.configmap.name", "If the request object refers to a configmap, the configmap name"},
|
||||
{"ka.req.configmap.obj", "If the request object refers to a configmap, the entire configmap object"},
|
||||
{"ka.req.container.image", "When the request object refers to a container, the container's images. Can be indexed (e.g. ka.req.container.image[0]). Without any index, returns the first image", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.container.image.repository", "The same as req.container.image, but only the repository part (e.g. sysdig/falco)", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.container.host_network", "When the request object refers to a container, the value of the hostNetwork flag."},
|
||||
{"ka.req.container.privileged", "When the request object refers to a container, whether or not any container is run privileged. With an index, return whether or not the ith container is run privileged.", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.role.rules", "When the request object refers to a role/cluster role, the rules associated with the role"},
|
||||
{"ka.req.role.rules.apiGroups", "When the request object refers to a role/cluster role, the api groups associated with the role's rules. With an index, return only the api groups from the ith rule. Without an index, return all api groups concatenated", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.role.rules.nonResourceURLs", "When the request object refers to a role/cluster role, the non resource urls associated with the role's rules. With an index, return only the non resource urls from the ith rule. Without an index, return all non resource urls concatenated", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.role.rules.verbs", "When the request object refers to a role/cluster role, the verbs associated with the role's rules. With an index, return only the verbs from the ith rule. Without an index, return all verbs concatenated", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.role.rules.resources", "When the request object refers to a role/cluster role, the resources associated with the role's rules. With an index, return only the resources from the ith rule. Without an index, return all resources concatenated", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.service.type", "When the request object refers to a service, the service type"},
|
||||
{"ka.req.service.ports", "When the request object refers to a service, the service's ports. Can be indexed (e.g. ka.req.service.ports[0]). Without any index, returns all ports", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.volume.hostpath", "If the request object contains volume definitions, whether or not a hostPath volume exists that mounts the specified path from the host (...hostpath[/etc]=true if a volume mounts /etc from the host). The index can be a glob, in which case all volumes are considered to find any path matching the specified glob (...hostpath[/usr/*] would match either /usr/local or /usr/bin)", IDX_REQUIRED, IDX_KEY},
|
||||
{"ka.resp.name", "The response object name"},
|
||||
{"ka.response.code", "The response code"},
|
||||
{"ka.response.reason", "The response reason (usually present only for failures)"}
|
||||
}};
|
||||
{{"ka.auditid", "The unique id of the audit event"},
|
||||
{"ka.stage", "Stage of the request (e.g. RequestReceived, ResponseComplete, etc.)"},
|
||||
{"ka.auth.decision", "The authorization decision"},
|
||||
{"ka.auth.reason", "The authorization reason"},
|
||||
{"ka.user.name", "The user name performing the request"},
|
||||
{"ka.user.groups", "The groups to which the user belongs"},
|
||||
{"ka.impuser.name", "The impersonated user name"},
|
||||
{"ka.verb", "The action being performed"},
|
||||
{"ka.uri", "The request URI as sent from client to server"},
|
||||
{"ka.uri.param", "The value of a given query parameter in the uri (e.g. when uri=/foo?key=val, ka.uri.param[key] is val).", IDX_REQUIRED, IDX_KEY},
|
||||
{"ka.target.name", "The target object name"},
|
||||
{"ka.target.namespace", "The target object namespace"},
|
||||
{"ka.target.resource", "The target object resource"},
|
||||
{"ka.target.subresource", "The target object subresource"},
|
||||
{"ka.req.binding.subjects", "When the request object refers to a cluster role binding, the subject (e.g. account/users) being linked by the binding"},
|
||||
{"ka.req.binding.subject.has_name", "When the request object refers to a cluster role binding, return true if a subject with the provided name exists", IDX_REQUIRED, IDX_KEY},
|
||||
{"ka.req.binding.role", "When the request object refers to a cluster role binding, the role being linked by the binding"},
|
||||
{"ka.req.configmap.name", "If the request object refers to a configmap, the configmap name"},
|
||||
{"ka.req.configmap.obj", "If the request object refers to a configmap, the entire configmap object"},
|
||||
{"ka.req.container.image", "When the request object refers to a container, the container's images. Can be indexed (e.g. ka.req.container.image[0]). Without any index, returns the first image", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.container.image.repository", "The same as req.container.image, but only the repository part (e.g. sysdig/falco)", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.container.host_network", "When the request object refers to a container, the value of the hostNetwork flag."},
|
||||
{"ka.req.container.privileged", "When the request object refers to a container, whether or not any container is run privileged. With an index, return whether or not the ith container is run privileged.", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.role.rules", "When the request object refers to a role/cluster role, the rules associated with the role"},
|
||||
{"ka.req.role.rules.apiGroups", "When the request object refers to a role/cluster role, the api groups associated with the role's rules. With an index, return only the api groups from the ith rule. Without an index, return all api groups concatenated", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.role.rules.nonResourceURLs", "When the request object refers to a role/cluster role, the non resource urls associated with the role's rules. With an index, return only the non resource urls from the ith rule. Without an index, return all non resource urls concatenated", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.role.rules.verbs", "When the request object refers to a role/cluster role, the verbs associated with the role's rules. With an index, return only the verbs from the ith rule. Without an index, return all verbs concatenated", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.role.rules.resources", "When the request object refers to a role/cluster role, the resources associated with the role's rules. With an index, return only the resources from the ith rule. Without an index, return all resources concatenated", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.service.type", "When the request object refers to a service, the service type"},
|
||||
{"ka.req.service.ports", "When the request object refers to a service, the service's ports. Can be indexed (e.g. ka.req.service.ports[0]). Without any index, returns all ports", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.volume.hostpath", "If the request object contains volume definitions, whether or not a hostPath volume exists that mounts the specified path from the host (...hostpath[/etc]=true if a volume mounts /etc from the host). The index can be a glob, in which case all volumes are considered to find any path matching the specified glob (...hostpath[/usr/*] would match either /usr/local or /usr/bin)", IDX_REQUIRED, IDX_KEY},
|
||||
{"ka.resp.name", "The response object name"},
|
||||
{"ka.response.code", "The response code"},
|
||||
{"ka.response.reason", "The response reason (usually present only for failures)"},
|
||||
{"ka.useragent", "The useragent of the client who made the request to the apiserver"}}};
|
||||
|
||||
{
|
||||
m_aliases = {
|
||||
@@ -693,21 +698,20 @@ k8s_audit_filter_check::k8s_audit_filter_check()
|
||||
{"ka.req.volume.hostpath", {"/requestObject/spec/volumes"_json_pointer, check_hostpath_vols}},
|
||||
{"ka.resp.name", {"/responseObject/metadata/name"_json_pointer}},
|
||||
{"ka.response.code", {"/responseStatus/code"_json_pointer}},
|
||||
{"ka.response.reason", {"/responseStatus/reason"_json_pointer}}
|
||||
};
|
||||
{"ka.response.reason", {"/responseStatus/reason"_json_pointer}},
|
||||
{"ka.useragent", {"/userAgent"_json_pointer}}};
|
||||
}
|
||||
}
|
||||
|
||||
k8s_audit_filter_check::~k8s_audit_filter_check()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
json_event_filter_check *k8s_audit_filter_check::allocate_new()
|
||||
{
|
||||
k8s_audit_filter_check *chk = new k8s_audit_filter_check();
|
||||
|
||||
return (json_event_filter_check *) chk;
|
||||
return (json_event_filter_check *)chk;
|
||||
}
|
||||
|
||||
json_event_filter::json_event_filter()
|
||||
@@ -762,9 +766,9 @@ std::list<json_event_filter_check::check_info> &json_event_filter_factory::get_f
|
||||
return m_info;
|
||||
}
|
||||
|
||||
json_event_formatter::json_event_formatter(json_event_filter_factory &json_factory, std::string &format)
|
||||
: m_format(format),
|
||||
m_json_factory(json_factory)
|
||||
json_event_formatter::json_event_formatter(json_event_filter_factory &json_factory, std::string &format):
|
||||
m_format(format),
|
||||
m_json_factory(json_factory)
|
||||
{
|
||||
parse_format();
|
||||
}
|
||||
@@ -777,7 +781,7 @@ std::string json_event_formatter::tostring(json_event *ev)
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
std::list<std::pair<std::string,std::string>> resolved;
|
||||
std::list<std::pair<std::string, std::string>> resolved;
|
||||
|
||||
resolve_tokens(ev, resolved);
|
||||
|
||||
@@ -793,7 +797,7 @@ std::string json_event_formatter::tojson(json_event *ev)
|
||||
{
|
||||
nlohmann::json ret;
|
||||
|
||||
std::list<std::pair<std::string,std::string>> resolved;
|
||||
std::list<std::pair<std::string, std::string>> resolved;
|
||||
|
||||
resolve_tokens(ev, resolved);
|
||||
|
||||
@@ -828,11 +832,11 @@ void json_event_formatter::parse_format()
|
||||
{
|
||||
// Skip the %
|
||||
tformat.erase(0, 1);
|
||||
json_event_filter_check *chk = (json_event_filter_check *) m_json_factory.new_filtercheck(tformat.c_str());
|
||||
json_event_filter_check *chk = (json_event_filter_check *)m_json_factory.new_filtercheck(tformat.c_str());
|
||||
|
||||
if(!chk)
|
||||
{
|
||||
throw falco_exception(string ("Could not parse format string \"") + m_format + "\": unknown filtercheck field " + tformat);
|
||||
throw falco_exception(string("Could not parse format string \"") + m_format + "\": unknown filtercheck field " + tformat);
|
||||
}
|
||||
|
||||
size = chk->parsed_size();
|
||||
@@ -852,7 +856,7 @@ void json_event_formatter::parse_format()
|
||||
// Empty fields are only allowed at the beginning of the string
|
||||
if(m_tokens.size() > 0)
|
||||
{
|
||||
throw falco_exception(string ("Could not parse format string \"" + m_format + "\": empty filtercheck field"));
|
||||
throw falco_exception(string("Could not parse format string \"" + m_format + "\": empty filtercheck field"));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -864,7 +868,7 @@ void json_event_formatter::parse_format()
|
||||
}
|
||||
}
|
||||
|
||||
void json_event_formatter::resolve_tokens(json_event *ev, std::list<std::pair<std::string,std::string>> &resolved)
|
||||
void json_event_formatter::resolve_tokens(json_event *ev, std::list<std::pair<std::string, std::string>> &resolved)
|
||||
{
|
||||
for(auto tok : m_tokens)
|
||||
{
|
||||
|
||||
@@ -62,12 +62,12 @@ function expand_macros(ast, defs, changed)
|
||||
elseif ast.type == "Filter" then
|
||||
if (ast.value.type == "Macro") then
|
||||
if (defs[ast.value.value] == nil) then
|
||||
error("Undefined macro '".. ast.value.value .. "' used in filter.")
|
||||
return false, "Undefined macro '".. ast.value.value .. "' used in filter."
|
||||
end
|
||||
defs[ast.value.value].used = true
|
||||
ast.value = copy_ast_obj(defs[ast.value.value].ast)
|
||||
changed = true
|
||||
return changed
|
||||
return true, changed
|
||||
end
|
||||
return expand_macros(ast.value, defs, changed)
|
||||
|
||||
@@ -75,7 +75,7 @@ function expand_macros(ast, defs, changed)
|
||||
|
||||
if (ast.left.type == "Macro") then
|
||||
if (defs[ast.left.value] == nil) then
|
||||
error("Undefined macro '".. ast.left.value .. "' used in filter.")
|
||||
return false, "Undefined macro '".. ast.left.value .. "' used in filter."
|
||||
end
|
||||
defs[ast.left.value].used = true
|
||||
ast.left = copy_ast_obj(defs[ast.left.value].ast)
|
||||
@@ -84,21 +84,27 @@ function expand_macros(ast, defs, changed)
|
||||
|
||||
if (ast.right.type == "Macro") then
|
||||
if (defs[ast.right.value] == nil) then
|
||||
error("Undefined macro ".. ast.right.value .. " used in filter.")
|
||||
return false, "Undefined macro ".. ast.right.value .. " used in filter."
|
||||
end
|
||||
defs[ast.right.value].used = true
|
||||
ast.right = copy_ast_obj(defs[ast.right.value].ast)
|
||||
changed = true
|
||||
end
|
||||
|
||||
local changed_left = expand_macros(ast.left, defs, false)
|
||||
local changed_right = expand_macros(ast.right, defs, false)
|
||||
return changed or changed_left or changed_right
|
||||
local status, changed_left = expand_macros(ast.left, defs, false)
|
||||
if status == false then
|
||||
return false, changed_left
|
||||
end
|
||||
local status, changed_right = expand_macros(ast.right, defs, false)
|
||||
if status == false then
|
||||
return false, changed_right
|
||||
end
|
||||
return true, changed or changed_left or changed_right
|
||||
|
||||
elseif ast.type == "UnaryBoolOp" then
|
||||
if (ast.argument.type == "Macro") then
|
||||
if (defs[ast.argument.value] == nil) then
|
||||
error("Undefined macro ".. ast.argument.value .. " used in filter.")
|
||||
return false, "Undefined macro ".. ast.argument.value .. " used in filter."
|
||||
end
|
||||
defs[ast.argument.value].used = true
|
||||
ast.argument = copy_ast_obj(defs[ast.argument.value].ast)
|
||||
@@ -106,7 +112,7 @@ function expand_macros(ast, defs, changed)
|
||||
end
|
||||
return expand_macros(ast.argument, defs, changed)
|
||||
end
|
||||
return changed
|
||||
return true, changed
|
||||
end
|
||||
|
||||
function get_macros(ast, set)
|
||||
@@ -195,7 +201,7 @@ function compiler.compile_macro(line, macro_defs, list_defs)
|
||||
|
||||
if (error_msg) then
|
||||
msg = "Compilation error when compiling \""..line.."\": ".. error_msg
|
||||
error(msg)
|
||||
return false, msg
|
||||
end
|
||||
|
||||
-- Simply as a validation step, try to expand all macros in this
|
||||
@@ -206,14 +212,18 @@ function compiler.compile_macro(line, macro_defs, list_defs)
|
||||
if (ast.type == "Rule") then
|
||||
-- Line is a filter, so expand macro references
|
||||
repeat
|
||||
expanded = expand_macros(ast_copy, macro_defs, false)
|
||||
status, expanded = expand_macros(ast_copy, macro_defs, false)
|
||||
if status == false then
|
||||
msg = "Compilation error when compiling \""..line.."\": ".. expanded
|
||||
return false, msg
|
||||
end
|
||||
until expanded == false
|
||||
|
||||
else
|
||||
error("Unexpected top-level AST type: "..ast.type)
|
||||
return false, "Unexpected top-level AST type: "..ast.type
|
||||
end
|
||||
|
||||
return ast
|
||||
return true, ast
|
||||
end
|
||||
|
||||
--[[
|
||||
@@ -227,22 +237,25 @@ function compiler.compile_filter(name, source, macro_defs, list_defs)
|
||||
|
||||
if (error_msg) then
|
||||
msg = "Compilation error when compiling \""..source.."\": "..error_msg
|
||||
error(msg)
|
||||
return false, msg
|
||||
end
|
||||
|
||||
if (ast.type == "Rule") then
|
||||
-- Line is a filter, so expand macro references
|
||||
repeat
|
||||
expanded = expand_macros(ast, macro_defs, false)
|
||||
status, expanded = expand_macros(ast, macro_defs, false)
|
||||
if status == false then
|
||||
return false, expanded
|
||||
end
|
||||
until expanded == false
|
||||
|
||||
else
|
||||
error("Unexpected top-level AST type: "..ast.type)
|
||||
return false, "Unexpected top-level AST type: "..ast.type
|
||||
end
|
||||
|
||||
filters = get_filters(ast)
|
||||
|
||||
return ast, filters
|
||||
return true, ast, filters
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -63,8 +63,9 @@ end
|
||||
-- Permissive for case and for common abbreviations.
|
||||
priorities = {
|
||||
Emergency=0, Alert=1, Critical=2, Error=3, Warning=4, Notice=5, Informational=5, Debug=7,
|
||||
emergency=0, alert=1, critical=2, error=3, warning=4, notice=5, informational=5, debug=7,
|
||||
EMERGENCY=0, ALERT=1, CRITICAL=2, ERROR=3, WARNING=4, NOTICE=5, INFORMATIONAL=5, DEBUG=7,
|
||||
INFO=5
|
||||
INFO=5, info=5
|
||||
}
|
||||
|
||||
--[[
|
||||
@@ -179,6 +180,73 @@ function table.tostring( tbl )
|
||||
return "{" .. table.concat( result, "," ) .. "}"
|
||||
end
|
||||
|
||||
-- Split rules_content by lines and also remember the line numbers for
|
||||
-- each top -level object. Returns a table of lines and a table of
|
||||
-- line numbers for objects.
|
||||
|
||||
function split_lines(rules_content)
|
||||
lines = {}
|
||||
indices = {}
|
||||
|
||||
idx = 1
|
||||
last_pos = 1
|
||||
pos = string.find(rules_content, "\n", 1, true)
|
||||
|
||||
while pos ~= nil do
|
||||
line = string.sub(rules_content, last_pos, pos-1)
|
||||
if line ~= "" then
|
||||
lines[#lines+1] = line
|
||||
if string.len(line) >= 3 and string.sub(line, 1, 3) == "---" then
|
||||
-- Document marker, skip
|
||||
elseif string.sub(line, 1, 1) == '-' then
|
||||
indices[#indices+1] = idx
|
||||
end
|
||||
|
||||
idx = idx + 1
|
||||
end
|
||||
|
||||
last_pos = pos+1
|
||||
pos = string.find(rules_content, "\n", pos+1, true)
|
||||
end
|
||||
|
||||
if last_pos < string.len(rules_content) then
|
||||
line = string.sub(rules_content, last_pos)
|
||||
lines[#lines+1] = line
|
||||
if string.sub(line, 1, 1) == '-' then
|
||||
indices[#indices+1] = idx
|
||||
end
|
||||
|
||||
idx = idx + 1
|
||||
end
|
||||
|
||||
-- Add a final index for last line in document
|
||||
indices[#indices+1] = idx
|
||||
|
||||
return lines, indices
|
||||
end
|
||||
|
||||
function get_orig_yaml_obj(rules_lines, row, num_lines)
|
||||
local ret = ""
|
||||
|
||||
idx = row
|
||||
while (idx < (row + num_lines) and idx <= #rules_lines) do
|
||||
ret = ret..rules_lines[idx].."\n"
|
||||
idx = idx + 1
|
||||
end
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
function build_error(rules_lines, row, num_lines, err)
|
||||
local ret = err.."\n---\n"..get_orig_yaml_obj(rules_lines, row, num_lines).."---"
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
function build_error_with_context(ctx, err)
|
||||
local ret = err.."\n---\n"..ctx.."---"
|
||||
return ret
|
||||
end
|
||||
|
||||
function load_rules(sinsp_lua_parser,
|
||||
json_lua_parser,
|
||||
@@ -190,16 +258,45 @@ function load_rules(sinsp_lua_parser,
|
||||
replace_container_info,
|
||||
min_priority)
|
||||
|
||||
local rules = yaml.load(rules_content)
|
||||
local required_engine_version = 0
|
||||
|
||||
local lines, indices = split_lines(rules_content)
|
||||
|
||||
local status, rules = pcall(yaml.load, rules_content)
|
||||
|
||||
if status == false then
|
||||
local pat = "^([%d]+):([%d]+): "
|
||||
-- rules is actually an error string
|
||||
|
||||
local row = 0
|
||||
local col = 0
|
||||
|
||||
row, col = string.match(rules, pat)
|
||||
if row ~= nil and col ~= nil then
|
||||
rules = string.gsub(rules, pat, "")
|
||||
end
|
||||
|
||||
row = tonumber(row)
|
||||
col = tonumber(col)
|
||||
|
||||
return false, build_error(lines, row, 3, rules)
|
||||
end
|
||||
|
||||
if rules == nil then
|
||||
-- An empty rules file is acceptable
|
||||
return required_engine_version
|
||||
return true, required_engine_version
|
||||
end
|
||||
|
||||
if type(rules) ~= "table" then
|
||||
error("Rules content \""..rules_content.."\" is not yaml")
|
||||
return false, build_error(lines, 1, 1, "Rules content is not yaml")
|
||||
end
|
||||
|
||||
-- Look for non-numeric indices--implies that document is not array
|
||||
-- of objects.
|
||||
for key, val in pairs(rules) do
|
||||
if type(key) ~= "number" then
|
||||
return false, build_error(lines, 1, 1, "Rules content is not yaml array of objects")
|
||||
end
|
||||
end
|
||||
|
||||
-- Iterate over yaml list. In this pass, all we're doing is
|
||||
@@ -208,18 +305,31 @@ function load_rules(sinsp_lua_parser,
|
||||
-- second pass
|
||||
for i,v in ipairs(rules) do
|
||||
|
||||
-- Save back the original object as it appeared in the file. Will be used to provide context.
|
||||
local context = get_orig_yaml_obj(lines, indices[i], (indices[i+1]-indices[i]))
|
||||
|
||||
if (not (type(v) == "table")) then
|
||||
error ("Unexpected element of type " ..type(v)..". Each element should be a yaml associative array.")
|
||||
return false, build_error_with_context(context, "Unexpected element of type " ..type(v)..". Each element should be a yaml associative array.")
|
||||
end
|
||||
|
||||
v['context'] = context
|
||||
|
||||
if (v['required_engine_version']) then
|
||||
required_engine_version = v['required_engine_version']
|
||||
if type(required_engine_version) ~= "number" then
|
||||
return false, build_error_with_context(v['context'], "Value of required_engine_version must be a number")
|
||||
end
|
||||
|
||||
if falco_rules.engine_version(rules_mgr) < v['required_engine_version'] then
|
||||
error("Rules require engine version "..v['required_engine_version']..", but engine version is "..falco_rules.engine_version(rules_mgr))
|
||||
return false, build_error_with_context(v['context'], "Rules require engine version "..v['required_engine_version']..", but engine version is "..falco_rules.engine_version(rules_mgr))
|
||||
end
|
||||
|
||||
elseif (v['macro']) then
|
||||
|
||||
if (v['macro'] == nil or type(v['macro']) == "table") then
|
||||
return false, build_error_with_context(v['context'], "Macro name is empty")
|
||||
end
|
||||
|
||||
if v['source'] == nil then
|
||||
v['source'] = "syscall"
|
||||
end
|
||||
@@ -228,9 +338,9 @@ function load_rules(sinsp_lua_parser,
|
||||
state.ordered_macro_names[#state.ordered_macro_names+1] = v['macro']
|
||||
end
|
||||
|
||||
for i, field in ipairs({'condition'}) do
|
||||
for j, field in ipairs({'condition'}) do
|
||||
if (v[field] == nil) then
|
||||
error ("Missing "..field.." in macro with name "..v['macro'])
|
||||
return false, build_error_with_context(v['context'], "Macro must have property "..field)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -243,24 +353,31 @@ function load_rules(sinsp_lua_parser,
|
||||
|
||||
if append then
|
||||
if state.macros_by_name[v['macro']] == nil then
|
||||
error ("Macro " ..v['macro'].. " has 'append' key but no macro by that name already exists")
|
||||
return false, build_error_with_context(v['context'], "Macro " ..v['macro'].. " has 'append' key but no macro by that name already exists")
|
||||
end
|
||||
|
||||
state.macros_by_name[v['macro']]['condition'] = state.macros_by_name[v['macro']]['condition'] .. " " .. v['condition']
|
||||
|
||||
-- Add the current object to the context of the base macro
|
||||
state.macros_by_name[v['macro']]['context'] = state.macros_by_name[v['macro']]['context'].."\n"..v['context']
|
||||
|
||||
else
|
||||
state.macros_by_name[v['macro']] = v
|
||||
end
|
||||
|
||||
elseif (v['list']) then
|
||||
|
||||
if (v['list'] == nil or type(v['list']) == "table") then
|
||||
return false, build_error_with_context(v['context'], "List name is empty")
|
||||
end
|
||||
|
||||
if state.lists_by_name[v['list']] == nil then
|
||||
state.ordered_list_names[#state.ordered_list_names+1] = v['list']
|
||||
end
|
||||
|
||||
for i, field in ipairs({'items'}) do
|
||||
for j, field in ipairs({'items'}) do
|
||||
if (v[field] == nil) then
|
||||
error ("Missing "..field.." in list with name "..v['list'])
|
||||
return false, build_error_with_context(v['context'], "List must have property "..field)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -273,10 +390,10 @@ function load_rules(sinsp_lua_parser,
|
||||
|
||||
if append then
|
||||
if state.lists_by_name[v['list']] == nil then
|
||||
error ("List " ..v['list'].. " has 'append' key but no list by that name already exists")
|
||||
return false, build_error_with_context(v['context'], "List " ..v['list'].. " has 'append' key but no list by that name already exists")
|
||||
end
|
||||
|
||||
for i, elem in ipairs(v['items']) do
|
||||
for j, elem in ipairs(v['items']) do
|
||||
table.insert(state.lists_by_name[v['list']]['items'], elem)
|
||||
end
|
||||
else
|
||||
@@ -286,7 +403,7 @@ function load_rules(sinsp_lua_parser,
|
||||
elseif (v['rule']) then
|
||||
|
||||
if (v['rule'] == nil or type(v['rule']) == "table") then
|
||||
error ("Missing name in rule")
|
||||
return false, build_error_with_context(v['context'], "Rule name is empty")
|
||||
end
|
||||
|
||||
-- By default, if a rule's condition refers to an unknown
|
||||
@@ -309,25 +426,28 @@ function load_rules(sinsp_lua_parser,
|
||||
if append then
|
||||
|
||||
-- For append rules, all you need is the condition
|
||||
for i, field in ipairs({'condition'}) do
|
||||
for j, field in ipairs({'condition'}) do
|
||||
if (v[field] == nil) then
|
||||
error ("Missing "..field.." in rule with name "..v['rule'])
|
||||
return false, build_error_with_context(v['context'], "Rule must have property "..field)
|
||||
end
|
||||
end
|
||||
|
||||
if state.rules_by_name[v['rule']] == nil then
|
||||
if state.skipped_rules_by_name[v['rule']] == nil then
|
||||
error ("Rule " ..v['rule'].. " has 'append' key but no rule by that name already exists")
|
||||
return false, build_error_with_context(v['context'], "Rule " ..v['rule'].. " has 'append' key but no rule by that name already exists")
|
||||
end
|
||||
else
|
||||
state.rules_by_name[v['rule']]['condition'] = state.rules_by_name[v['rule']]['condition'] .. " " .. v['condition']
|
||||
|
||||
-- Add the current object to the context of the base rule
|
||||
state.rules_by_name[v['rule']]['context'] = state.rules_by_name[v['rule']]['context'].."\n"..v['context']
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
for i, field in ipairs({'condition', 'output', 'desc', 'priority'}) do
|
||||
for j, field in ipairs({'condition', 'output', 'desc', 'priority'}) do
|
||||
if (v[field] == nil) then
|
||||
error ("Missing "..field.." in rule with name "..v['rule'])
|
||||
return false, build_error_with_context(v['context'], "Rule must have property "..field)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -356,7 +476,10 @@ function load_rules(sinsp_lua_parser,
|
||||
end
|
||||
end
|
||||
else
|
||||
error ("Unknown rule object: "..table.tostring(v))
|
||||
-- Remove the context from the table, so the table is exactly what was parsed
|
||||
local context = v['context']
|
||||
v['context'] = nil
|
||||
return false, build_error_with_context(context, "Unknown rule object: "..table.tostring(v))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -389,11 +512,15 @@ function load_rules(sinsp_lua_parser,
|
||||
state.lists[v['list']] = {["items"] = items, ["used"] = false}
|
||||
end
|
||||
|
||||
for i, name in ipairs(state.ordered_macro_names) do
|
||||
for _, name in ipairs(state.ordered_macro_names) do
|
||||
|
||||
local v = state.macros_by_name[name]
|
||||
|
||||
local ast = compiler.compile_macro(v['condition'], state.macros, state.lists)
|
||||
local status, ast = compiler.compile_macro(v['condition'], state.macros, state.lists)
|
||||
|
||||
if status == false then
|
||||
return false, build_error_with_context(v['context'], ast)
|
||||
end
|
||||
|
||||
if v['source'] == "syscall" then
|
||||
if not all_events then
|
||||
@@ -404,7 +531,7 @@ function load_rules(sinsp_lua_parser,
|
||||
state.macros[v['macro']] = {["ast"] = ast.filter.value, ["used"] = false}
|
||||
end
|
||||
|
||||
for i, name in ipairs(state.ordered_rule_names) do
|
||||
for _, name in ipairs(state.ordered_rule_names) do
|
||||
|
||||
local v = state.rules_by_name[name]
|
||||
|
||||
@@ -413,8 +540,12 @@ function load_rules(sinsp_lua_parser,
|
||||
warn_evttypes = v['warn_evttypes']
|
||||
end
|
||||
|
||||
local filter_ast, filters = compiler.compile_filter(v['rule'], v['condition'],
|
||||
state.macros, state.lists)
|
||||
local status, filter_ast, filters = compiler.compile_filter(v['rule'], v['condition'],
|
||||
state.macros, state.lists)
|
||||
|
||||
if status == false then
|
||||
return false, build_error_with_context(v['context'], filter_ast)
|
||||
end
|
||||
|
||||
local evtttypes = {}
|
||||
local syscallnums = {}
|
||||
@@ -551,7 +682,7 @@ function load_rules(sinsp_lua_parser,
|
||||
formatter = formats.formatter(v['source'], v['output'])
|
||||
formats.free_formatter(v['source'], formatter)
|
||||
else
|
||||
error ("Unexpected type in load_rule: "..filter_ast.type)
|
||||
return false, build_error_with_context(v['context'], "Unexpected type in load_rule: "..filter_ast.type)
|
||||
end
|
||||
|
||||
::next_rule::
|
||||
@@ -574,7 +705,7 @@ function load_rules(sinsp_lua_parser,
|
||||
|
||||
io.flush()
|
||||
|
||||
return required_engine_version
|
||||
return true, required_engine_version
|
||||
end
|
||||
|
||||
local rule_fmt = "%-50s %s"
|
||||
|
||||
@@ -425,15 +425,30 @@ void falco_rules::load_rules(const string &rules_content,
|
||||
lua_pushstring(m_ls, extra.c_str());
|
||||
lua_pushboolean(m_ls, (replace_container_info ? 1 : 0));
|
||||
lua_pushnumber(m_ls, min_priority);
|
||||
if(lua_pcall(m_ls, 9, 1, 0) != 0)
|
||||
if(lua_pcall(m_ls, 9, 2, 0) != 0)
|
||||
{
|
||||
const char* lerr = lua_tostring(m_ls, -1);
|
||||
|
||||
string err = "Error loading rules: " + string(lerr);
|
||||
|
||||
throw falco_exception(err);
|
||||
}
|
||||
|
||||
required_engine_version = lua_tonumber(m_ls, -1);
|
||||
lua_pop(m_ls, 1);
|
||||
// Either returns (true, required_engine_version), or (false, error string)
|
||||
bool successful = lua_toboolean(m_ls, -2);
|
||||
|
||||
if(successful)
|
||||
{
|
||||
required_engine_version = lua_tonumber(m_ls, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string err = lua_tostring(m_ls, -1);
|
||||
throw falco_exception(err);
|
||||
}
|
||||
|
||||
lua_pop(m_ls, 4);
|
||||
|
||||
} else {
|
||||
throw falco_exception("No function " + m_lua_load_rules + " found in lua rule module");
|
||||
}
|
||||
|
||||
@@ -202,19 +202,8 @@ void falco_ruleset::add(string &name,
|
||||
}
|
||||
}
|
||||
|
||||
void falco_ruleset::enable(const string &pattern, bool enabled, uint16_t ruleset)
|
||||
void falco_ruleset::enable(const string &substring, bool enabled, uint16_t ruleset)
|
||||
{
|
||||
regex re;
|
||||
bool match_using_regex = true;
|
||||
|
||||
try {
|
||||
re.assign(pattern);
|
||||
}
|
||||
catch (std::regex_error e)
|
||||
{
|
||||
match_using_regex = false;
|
||||
}
|
||||
|
||||
while (m_rulesets.size() < (size_t) ruleset + 1)
|
||||
{
|
||||
m_rulesets.push_back(new ruleset_filters());
|
||||
@@ -223,14 +212,9 @@ void falco_ruleset::enable(const string &pattern, bool enabled, uint16_t ruleset
|
||||
for(const auto &val : m_filters)
|
||||
{
|
||||
bool matches;
|
||||
if(match_using_regex)
|
||||
{
|
||||
matches = regex_match(val.first, re);
|
||||
}
|
||||
else
|
||||
{
|
||||
matches = (val.first.find(pattern) != string::npos);
|
||||
}
|
||||
|
||||
matches = (substring == "" || (val.first.find(substring) != string::npos));
|
||||
|
||||
if (matches)
|
||||
{
|
||||
if(enabled)
|
||||
|
||||
@@ -24,7 +24,6 @@ limitations under the License.
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <regex>
|
||||
|
||||
#include "sinsp.h"
|
||||
#include "filter.h"
|
||||
@@ -48,9 +47,9 @@ public:
|
||||
// specifying unnecessarily large rulesets will result in
|
||||
// unnecessarily large vectors.
|
||||
|
||||
// Find those rules matching the provided pattern and set
|
||||
// Find those rules matching the provided substring and set
|
||||
// their enabled status to enabled.
|
||||
void enable(const std::string &pattern, bool enabled, uint16_t ruleset = 0);
|
||||
void enable(const std::string &substring, 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
|
||||
|
||||
@@ -19,7 +19,7 @@ limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#define FALCO_VERSION "${FALCO_VERSION}"
|
||||
#define FALCO_VERSION "@FALCO_VERSION@"
|
||||
|
||||
#define FALCO_LUA_DIR "${CMAKE_INSTALL_PREFIX}/${FALCO_SHARE_DIR}/lua/"
|
||||
#define FALCO_SOURCE_DIR "${PROJECT_SOURCE_DIR}"
|
||||
|
||||
@@ -76,7 +76,7 @@ static void restart_falco(int signal)
|
||||
static void usage()
|
||||
{
|
||||
printf(
|
||||
"falco version " FALCO_VERSION "\n"
|
||||
"Falco version: " FALCO_VERSION "\n"
|
||||
"Usage: falco [options]\n\n"
|
||||
"Options:\n"
|
||||
" -h, --help Print this page\n"
|
||||
@@ -87,7 +87,7 @@ static void usage()
|
||||
" --cri <path> Path to CRI socket for container metadata\n"
|
||||
" Use the specified socket to fetch data from a CRI-compatible runtime\n"
|
||||
" -d, --daemon Run as a daemon\n"
|
||||
" -D <pattern> Disable any rules matching the regex <pattern>. Can be specified multiple times.\n"
|
||||
" -D <substring> Disable any rules with names having the substring <substring>. Can be specified multiple times.\n"
|
||||
" Can not be specified with -t.\n"
|
||||
" -e <events_file> Read the events from <events_file> (in .scap format for sinsp events, or jsonl for\n"
|
||||
" k8s audit events) instead of tapping into live.\n"
|
||||
@@ -471,9 +471,9 @@ int falco_init(int argc, char **argv)
|
||||
|
||||
try
|
||||
{
|
||||
set<string> disabled_rule_patterns;
|
||||
string pattern;
|
||||
string all_rules = ".*";
|
||||
set<string> disabled_rule_substrings;
|
||||
string substring;
|
||||
string all_rules = "";
|
||||
set<string> disabled_rule_tags;
|
||||
set<string> enabled_rule_tags;
|
||||
|
||||
@@ -502,8 +502,8 @@ int falco_init(int argc, char **argv)
|
||||
daemon = true;
|
||||
break;
|
||||
case 'D':
|
||||
pattern = optarg;
|
||||
disabled_rule_patterns.insert(pattern);
|
||||
substring = optarg;
|
||||
disabled_rule_substrings.insert(substring);
|
||||
break;
|
||||
case 'e':
|
||||
trace_filename = optarg;
|
||||
@@ -604,7 +604,7 @@ int falco_init(int argc, char **argv)
|
||||
case 0:
|
||||
if(string(long_options[long_index].name) == "version")
|
||||
{
|
||||
printf("falco version %s\n", FALCO_VERSION);
|
||||
printf("Falco version: %s\n", FALCO_VERSION);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
else if (string(long_options[long_index].name) == "cri")
|
||||
@@ -716,7 +716,17 @@ int falco_init(int argc, char **argv)
|
||||
}
|
||||
for(auto file : validate_rules_filenames)
|
||||
{
|
||||
engine->load_rules_file(file, verbose, all_events);
|
||||
// Only include the prefix if there is more than one file
|
||||
std::string prefix = (validate_rules_filenames.size() > 1 ? file + ": " : "");
|
||||
try {
|
||||
engine->load_rules_file(file, verbose, all_events);
|
||||
}
|
||||
catch(falco_exception &e)
|
||||
{
|
||||
printf("%s%s\n", prefix.c_str(), e.what());
|
||||
throw;
|
||||
}
|
||||
printf("%sOk\n", prefix.c_str());
|
||||
}
|
||||
falco_logger::log(LOG_INFO, "Ok\n");
|
||||
goto exit;
|
||||
@@ -771,15 +781,15 @@ int falco_init(int argc, char **argv)
|
||||
}
|
||||
|
||||
// You can't both disable and enable rules
|
||||
if((disabled_rule_patterns.size() + disabled_rule_tags.size() > 0) &&
|
||||
if((disabled_rule_substrings.size() + disabled_rule_tags.size() > 0) &&
|
||||
enabled_rule_tags.size() > 0) {
|
||||
throw std::invalid_argument("You can not specify both disabled (-D/-T) and enabled (-t) rules");
|
||||
}
|
||||
|
||||
for (auto pattern : disabled_rule_patterns)
|
||||
for (auto substring : disabled_rule_substrings)
|
||||
{
|
||||
falco_logger::log(LOG_INFO, "Disabling rules matching pattern: " + pattern + "\n");
|
||||
engine->enable_rule(pattern, false);
|
||||
falco_logger::log(LOG_INFO, "Disabling rules matching substring: " + substring + "\n");
|
||||
engine->enable_rule(substring, false);
|
||||
}
|
||||
|
||||
if(disabled_rule_tags.size() > 0)
|
||||
@@ -905,6 +915,63 @@ int falco_init(int argc, char **argv)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// If daemonizing, do it here so any init errors will
|
||||
// be returned in the foreground process.
|
||||
if (daemon && !g_daemonized) {
|
||||
pid_t pid, sid;
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
// error
|
||||
falco_logger::log(LOG_ERR, "Could not fork. Exiting.\n");
|
||||
result = EXIT_FAILURE;
|
||||
goto exit;
|
||||
} else if (pid > 0) {
|
||||
// parent. Write child pid to pidfile and exit
|
||||
std::ofstream pidfile;
|
||||
pidfile.open(pidfilename);
|
||||
|
||||
if (!pidfile.good())
|
||||
{
|
||||
falco_logger::log(LOG_ERR, "Could not write pid to pid file " + pidfilename + ". Exiting.\n");
|
||||
result = EXIT_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
pidfile << pid;
|
||||
pidfile.close();
|
||||
goto exit;
|
||||
}
|
||||
// if here, child.
|
||||
|
||||
// Become own process group.
|
||||
sid = setsid();
|
||||
if (sid < 0) {
|
||||
falco_logger::log(LOG_ERR, "Could not set session id. Exiting.\n");
|
||||
result = EXIT_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// Set umask so no files are world anything or group writable.
|
||||
umask(027);
|
||||
|
||||
// Change working directory to '/'
|
||||
if ((chdir("/")) < 0) {
|
||||
falco_logger::log(LOG_ERR, "Could not change working directory to '/'. Exiting.\n");
|
||||
result = EXIT_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// Close stdin, stdout, stderr and reopen to /dev/null
|
||||
close(0);
|
||||
close(1);
|
||||
close(2);
|
||||
open("/dev/null", O_RDONLY);
|
||||
open("/dev/null", O_RDWR);
|
||||
open("/dev/null", O_RDWR);
|
||||
|
||||
g_daemonized = true;
|
||||
}
|
||||
|
||||
if (trace_filename.size())
|
||||
{
|
||||
// Try to open the trace file as a sysdig
|
||||
@@ -969,63 +1036,6 @@ int falco_init(int argc, char **argv)
|
||||
inspector->start_dropping_mode(1);
|
||||
}
|
||||
|
||||
// If daemonizing, do it here so any init errors will
|
||||
// be returned in the foreground process.
|
||||
if (daemon && !g_daemonized) {
|
||||
pid_t pid, sid;
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
// error
|
||||
falco_logger::log(LOG_ERR, "Could not fork. Exiting.\n");
|
||||
result = EXIT_FAILURE;
|
||||
goto exit;
|
||||
} else if (pid > 0) {
|
||||
// parent. Write child pid to pidfile and exit
|
||||
std::ofstream pidfile;
|
||||
pidfile.open(pidfilename);
|
||||
|
||||
if (!pidfile.good())
|
||||
{
|
||||
falco_logger::log(LOG_ERR, "Could not write pid to pid file " + pidfilename + ". Exiting.\n");
|
||||
result = EXIT_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
pidfile << pid;
|
||||
pidfile.close();
|
||||
goto exit;
|
||||
}
|
||||
// if here, child.
|
||||
|
||||
// Become own process group.
|
||||
sid = setsid();
|
||||
if (sid < 0) {
|
||||
falco_logger::log(LOG_ERR, "Could not set session id. Exiting.\n");
|
||||
result = EXIT_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// Set umask so no files are world anything or group writable.
|
||||
umask(027);
|
||||
|
||||
// Change working directory to '/'
|
||||
if ((chdir("/")) < 0) {
|
||||
falco_logger::log(LOG_ERR, "Could not change working directory to '/'. Exiting.\n");
|
||||
result = EXIT_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// Close stdin, stdout, stderr and reopen to /dev/null
|
||||
close(0);
|
||||
close(1);
|
||||
close(2);
|
||||
open("/dev/null", O_RDONLY);
|
||||
open("/dev/null", O_RDWR);
|
||||
open("/dev/null", O_RDWR);
|
||||
|
||||
g_daemonized = true;
|
||||
}
|
||||
|
||||
if(outfile != "")
|
||||
{
|
||||
inspector->setup_cycle_writer(outfile, rollover_mb, duration_seconds, file_limit, event_limit, compress);
|
||||
|
||||
Reference in New Issue
Block a user