mirror of
https://github.com/falcosecurity/falco.git
synced 2026-03-21 04:02:14 +00:00
Compare commits
12 Commits
update/cli
...
add-except
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dbd4ff08eb | ||
|
|
9c70ae19be | ||
|
|
9cb25be5bd | ||
|
|
1f533e5964 | ||
|
|
854318cacf | ||
|
|
0cc10b0fbe | ||
|
|
e3f1ac1be3 | ||
|
|
fb4e07e220 | ||
|
|
9014153d7b | ||
|
|
0bb6addcc0 | ||
|
|
3aa8ff6e84 | ||
|
|
a4b7d46717 |
@@ -282,8 +282,6 @@ jobs:
|
||||
- run:
|
||||
name: Execute integration tests
|
||||
command: /usr/bin/entrypoint test
|
||||
- store_test_results:
|
||||
path: /build/release/integration-tests-xunit
|
||||
"tests/integration-static":
|
||||
docker:
|
||||
- image: falcosecurity/falco-tester:latest
|
||||
@@ -299,8 +297,6 @@ jobs:
|
||||
- run:
|
||||
name: Execute integration tests
|
||||
command: /usr/bin/entrypoint test
|
||||
- store_test_results:
|
||||
path: /build-static/release/integration-tests-xunit
|
||||
"tests/driver-loader/integration":
|
||||
machine:
|
||||
image: ubuntu-1604:202004-01
|
||||
|
||||
20
.github/stale.yml
vendored
Normal file
20
.github/stale.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 60
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 7
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- cncf
|
||||
- roadmap
|
||||
- "help wanted"
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: wontfix
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
Issues labeled "cncf", "roadmap" and "help wanted" will not be automatically closed.
|
||||
Please refer to a maintainer to get such label added if you think this should be kept open.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: false
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -11,6 +11,8 @@ test/.phoronix-test-suite
|
||||
test/results*.json.*
|
||||
test/build
|
||||
|
||||
userspace/falco/lua/re.lua
|
||||
userspace/falco/lua/lpeg.so
|
||||
userspace/engine/lua/lyaml
|
||||
userspace/engine/lua/lyaml.lua
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
std = "min"
|
||||
cache = true
|
||||
include_files = {
|
||||
"userspace/falco/lua/*.lua",
|
||||
"userspace/engine/lua/*.lua",
|
||||
"userspace/engine/lua/lyaml/*.lua",
|
||||
"*.luacheckrc"
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
# Change Log
|
||||
|
||||
## v0.26.2
|
||||
|
||||
Released on 2020-11-10
|
||||
|
||||
### Major Changes
|
||||
|
||||
* update: DRIVERS_REPO now defaults to https://download.falco.org/driver [[#1460](https://github.com/falcosecurity/falco/pull/1460)] - [@leodido](https://github.com/leodido)
|
||||
|
||||
## v0.26.1
|
||||
|
||||
Released on 2020-10-01
|
||||
|
||||
@@ -83,7 +83,7 @@ include(GetFalcoVersion)
|
||||
set(PACKAGE_NAME "falco")
|
||||
set(PROBE_NAME "falco")
|
||||
set(PROBE_DEVICE_NAME "falco")
|
||||
set(DRIVERS_REPO "https://download.falco.org/driver")
|
||||
set(DRIVERS_REPO "https://dl.bintray.com/falcosecurity/driver")
|
||||
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||
set(CMAKE_INSTALL_PREFIX
|
||||
/usr
|
||||
@@ -115,8 +115,20 @@ set(CURSES_NEED_NCURSES TRUE)
|
||||
find_package(Curses REQUIRED)
|
||||
message(STATUS "Found ncurses: include: ${CURSES_INCLUDE_DIR}, lib: ${CURSES_LIBRARIES}")
|
||||
|
||||
# b64
|
||||
include(b64)
|
||||
# libb64
|
||||
|
||||
set(B64_SRC "${PROJECT_BINARY_DIR}/b64-prefix/src/b64")
|
||||
message(STATUS "Using bundled b64 in '${B64_SRC}'")
|
||||
set(B64_INCLUDE "${B64_SRC}/include")
|
||||
set(B64_LIB "${B64_SRC}/src/libb64.a")
|
||||
ExternalProject_Add(
|
||||
b64
|
||||
URL "https://github.com/libb64/libb64/archive/v1.2.1.zip"
|
||||
URL_HASH "SHA256=665134c2b600098a7ebd3d00b6a866cb34909a6d48e0e37a0eda226a4ad2638a"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_COMMAND "")
|
||||
|
||||
# yaml-cpp
|
||||
include(yaml-cpp)
|
||||
@@ -130,16 +142,52 @@ if(NOT MINIMAL_BUILD)
|
||||
endif()
|
||||
|
||||
# LuaJIT
|
||||
include(luajit)
|
||||
set(LUAJIT_SRC "${PROJECT_BINARY_DIR}/luajit-prefix/src/luajit/src")
|
||||
message(STATUS "Using bundled LuaJIT in '${LUAJIT_SRC}'")
|
||||
set(LUAJIT_INCLUDE "${LUAJIT_SRC}")
|
||||
set(LUAJIT_LIB "${LUAJIT_SRC}/libluajit.a")
|
||||
ExternalProject_Add(
|
||||
luajit
|
||||
URL "https://github.com/LuaJIT/LuaJIT/archive/v2.0.3.tar.gz"
|
||||
URL_HASH "SHA256=8da3d984495a11ba1bce9a833ba60e18b532ca0641e7d90d97fafe85ff014baa"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_COMMAND "")
|
||||
|
||||
# Lpeg
|
||||
include(lpeg)
|
||||
set(LPEG_SRC "${PROJECT_BINARY_DIR}/lpeg-prefix/src/lpeg")
|
||||
set(LPEG_LIB "${PROJECT_BINARY_DIR}/lpeg-prefix/src/lpeg/build/lpeg.a")
|
||||
message(STATUS "Using bundled lpeg in '${LPEG_SRC}'")
|
||||
set(LPEG_DEPENDENCIES "")
|
||||
list(APPEND LPEG_DEPENDENCIES "luajit")
|
||||
ExternalProject_Add(
|
||||
lpeg
|
||||
DEPENDS ${LPEG_DEPENDENCIES}
|
||||
URL "http://www.inf.puc-rio.br/~roberto/lpeg/lpeg-1.0.2.tar.gz"
|
||||
URL_HASH "SHA256=48d66576051b6c78388faad09b70493093264588fcd0f258ddaab1cdd4a15ffe"
|
||||
BUILD_COMMAND LUA_INCLUDE=${LUAJIT_INCLUDE} "${PROJECT_SOURCE_DIR}/scripts/build-lpeg.sh" "${LPEG_SRC}/build"
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND ""
|
||||
INSTALL_COMMAND "")
|
||||
|
||||
# libyaml
|
||||
include(libyaml)
|
||||
|
||||
# lyaml
|
||||
include(lyaml)
|
||||
set(LYAML_SRC "${PROJECT_BINARY_DIR}/lyaml-prefix/src/lyaml/ext/yaml")
|
||||
set(LYAML_LIB "${LYAML_SRC}/.libs/yaml.a")
|
||||
message(STATUS "Using bundled lyaml in '${LYAML_SRC}'")
|
||||
ExternalProject_Add(
|
||||
lyaml
|
||||
DEPENDS luajit libyaml
|
||||
URL "https://github.com/gvvaughan/lyaml/archive/release-v6.0.tar.gz"
|
||||
URL_HASH "SHA256=9d7cf74d776999ff6f758c569d5202ff5da1f303c6f4229d3b41f71cd3a3e7a7"
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND ./configure --enable-static CFLAGS=-I${LIBYAML_INSTALL_DIR}/include CPPFLAGS=-I${LIBYAML_INSTALL_DIR}/include LDFLAGS=-L${LIBYAML_INSTALL_DIR}/lib LIBS=-lyaml LUA=${LUAJIT_SRC}/luajit LUA_INCLUDE=-I${LUAJIT_INCLUDE}
|
||||
INSTALL_COMMAND sh -c
|
||||
"cp -R ${PROJECT_BINARY_DIR}/lyaml-prefix/src/lyaml/lib/* ${PROJECT_SOURCE_DIR}/userspace/engine/lua")
|
||||
|
||||
# One TBB
|
||||
set(TBB_SRC "${PROJECT_BINARY_DIR}/tbb-prefix/src/tbb")
|
||||
@@ -172,16 +220,12 @@ if(NOT MINIMAL_BUILD)
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${CIVETWEB_SRC}/install/include
|
||||
BUILD_IN_SOURCE 1
|
||||
BUILD_COMMAND ${CMD_MAKE} COPT="-DNO_FILES" WITH_CPP=1
|
||||
BUILD_BYPRODUCTS ${CIVETWEB_LIB}
|
||||
INSTALL_COMMAND ${CMD_MAKE} COPT="-DNO_FILES" install-lib install-headers PREFIX=${CIVETWEB_SRC}/install "WITH_CPP=1")
|
||||
endif()
|
||||
|
||||
# string-view-lite
|
||||
#string-view-lite
|
||||
include(DownloadStringViewLite)
|
||||
|
||||
# cxxopts
|
||||
include(DownloadCxxOpts)
|
||||
|
||||
if(NOT MINIMAL_BUILD)
|
||||
# gRPC
|
||||
include(gRPC)
|
||||
|
||||
16
README.md
16
README.md
@@ -5,9 +5,7 @@
|
||||
|
||||
[](https://circleci.com/gh/falcosecurity/falco) [](https://bestpractices.coreinfrastructure.org/projects/2317) [](COPYING)
|
||||
|
||||
Want to talk? Join us on the [#falco](https://kubernetes.slack.com/archives/CMWH3EH32) channel in the [Kubernetes Slack](https://slack.k8s.io).
|
||||
|
||||
### Latest releases
|
||||
#### Latest releases
|
||||
|
||||
Read the [change log](CHANGELOG.md).
|
||||
|
||||
@@ -41,7 +39,7 @@ If you would like to run Falco in **production** please adhere to the [official
|
||||
|
||||
Falco is designed to be extensible such that it can be built into cloud-native applications and infrastructure.
|
||||
|
||||
Falco has a [gRPC](https://falco.org/docs/grpc/) endpoint and an API defined in [protobuf](https://github.com/falcosecurity/falco/blob/master/userspace/falco/outputs.proto).
|
||||
Falco has a [gRPC](https://falco.org/docs/grpc/) endpoint and an API defined in [protobuf](https://github.com/falcosecurity/falco/blob/update-readme/userspace/falco/outputs.proto).
|
||||
The Falco Project supports various SDKs for this endpoint.
|
||||
|
||||
##### SDKs
|
||||
@@ -65,7 +63,6 @@ For example, Falco can easily detect incidents including but not limited to:
|
||||
- Unexpected read of a sensitive file, such as `/etc/shadow`.
|
||||
- A non-device file is written to `/dev`.
|
||||
- A standard system binary, such as `ls`, is making an outbound network connection.
|
||||
- A privileged pod is started in a Kubernetes cluster.
|
||||
|
||||
### Documentation
|
||||
|
||||
@@ -75,13 +72,6 @@ The [Official Documentation](https://falco.org/docs/) is the best resource to le
|
||||
|
||||
To get involved with The Falco Project please visit [the community repository](https://github.com/falcosecurity/community) to find more.
|
||||
|
||||
How to reach out?
|
||||
|
||||
- Join the #falco channel on the [Kubernetes Slack](https://slack.k8s.io)
|
||||
- [Join the Falco mailing list](https://lists.cncf.io/g/cncf-falco-dev)
|
||||
- [Read the Falco documentation](https://falco.org/docs/)
|
||||
|
||||
|
||||
### Contributing
|
||||
|
||||
See the [CONTRIBUTING.md](https://github.com/falcosecurity/.github/blob/master/CONTRIBUTING.md).
|
||||
@@ -104,4 +94,4 @@ Falco is licensed to you under the [Apache 2.0](./COPYING) open source license.
|
||||
[3]: https://dl.bintray.com/falcosecurity/deb-dev/stable
|
||||
[4]: https://dl.bintray.com/falcosecurity/deb/stable
|
||||
[5]: https://dl.bintray.com/falcosecurity/bin-dev/x86_64
|
||||
[6]: https://dl.bintray.com/falcosecurity/bin/x86_64
|
||||
[6]: https://dl.bintray.com/falcosecurity/bin/x86_64
|
||||
10
RELEASE.md
10
RELEASE.md
@@ -90,16 +90,6 @@ Now assume `x.y.z` is the new version.
|
||||
|
||||
- Finally, publish the release!
|
||||
|
||||
### 3. Update the meeting notes
|
||||
|
||||
For each release we archive the meeting notes in git for historical purposes.
|
||||
|
||||
- The notes from the Falco meetings can be [found here](https://hackmd.io/6sEAlInlSaGnLz2FnFz21A).
|
||||
- Note: There may be other notes from working groups that can optionally be added as well as needed.
|
||||
- Add the entire content of the document to a new file in [github.com/falcosecurity/community/tree/master/meeting-notes](https://github.com/falcosecurity/community/tree/master/meeting-notes) as a new file labeled `release-x.y.z.md`
|
||||
- Open up a pull request with the new change.
|
||||
|
||||
|
||||
## Post-Release tasks
|
||||
|
||||
Announce the new release to the world!
|
||||
|
||||
@@ -30,15 +30,9 @@ if(NOT CPACK_GENERATOR)
|
||||
endif()
|
||||
|
||||
message(STATUS "Using package generators: ${CPACK_GENERATOR}")
|
||||
message(STATUS "Package architecture: ${CMAKE_SYSTEM_PROCESSOR}")
|
||||
set(CPACK_DEBIAN_PACKAGE_SECTION "utils")
|
||||
|
||||
if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64")
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64")
|
||||
endif()
|
||||
if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "arm64")
|
||||
endif()
|
||||
set(CPACK_DEBIAN_PACKAGE_SECTION "utils")
|
||||
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
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
#
|
||||
|
||||
include(ExternalProject)
|
||||
|
||||
set(CXXOPTS_PREFIX ${CMAKE_BINARY_DIR}/cxxopts-prefix)
|
||||
set(CXXOPTS_INCLUDE ${CXXOPTS_PREFIX}/include)
|
||||
message(STATUS "Using bundled cxxopts in ${CXXOPTS_INCLUDE}")
|
||||
|
||||
ExternalProject_Add(
|
||||
cxxopts
|
||||
PREFIX ${CXXOPTS_PREFIX}
|
||||
GIT_REPOSITORY "https://github.com/jarro2783/cxxopts.git"
|
||||
GIT_TAG "master"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ${CMAKE_COMMAND} -E copy ${CXXOPTS_PREFIX}/src/cxxopts/include/cxxopts.hpp
|
||||
${CXXOPTS_INCLUDE}/cxxopts.hpp)
|
||||
@@ -1,27 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
#
|
||||
|
||||
set(B64_SRC "${PROJECT_BINARY_DIR}/b64-prefix/src/b64")
|
||||
message(STATUS "Using bundled b64 in '${B64_SRC}'")
|
||||
set(B64_INCLUDE "${B64_SRC}/include")
|
||||
set(B64_LIB "${B64_SRC}/src/libb64.a")
|
||||
externalproject_add(
|
||||
b64
|
||||
URL "https://github.com/libb64/libb64/archive/ce864b17ea0e24a91e77c7dd3eb2d1ac4175b3f0.tar.gz"
|
||||
URL_HASH "SHA256=d07173e66f435e5c77dbf81bd9313f8d0e4a3b4edd4105a62f4f8132ba932811"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
BUILD_BYPRODUCTS ${B64_LIB}
|
||||
INSTALL_COMMAND ""
|
||||
)
|
||||
@@ -115,7 +115,7 @@ else()
|
||||
grpc
|
||||
DEPENDS openssl
|
||||
GIT_REPOSITORY https://github.com/grpc/grpc.git
|
||||
GIT_TAG v1.32.0
|
||||
GIT_TAG v1.31.1
|
||||
GIT_SUBMODULES "third_party/protobuf third_party/zlib third_party/cares/cares third_party/abseil-cpp third_party/re2"
|
||||
BUILD_IN_SOURCE 1
|
||||
BUILD_BYPRODUCTS ${GRPC_LIB} ${GRPCPP_LIB}
|
||||
|
||||
@@ -15,13 +15,12 @@ set(LIBYAML_SRC "${PROJECT_BINARY_DIR}/libyaml-prefix/src/libyaml")
|
||||
set(LIBYAML_INSTALL_DIR "${LIBYAML_SRC}/target")
|
||||
message(STATUS "Using bundled libyaml in '${LIBYAML_SRC}'")
|
||||
set(LIBYAML_LIB "${LIBYAML_SRC}/src/.libs/libyaml.a")
|
||||
externalproject_add(
|
||||
libyaml
|
||||
URL "https://github.com/yaml/libyaml/releases/download/0.2.5/yaml-0.2.5.tar.gz"
|
||||
URL_HASH "SHA256=c642ae9b75fee120b2d96c712538bd2cf283228d2337df2cf2988e3c02678ef4"
|
||||
CONFIGURE_COMMAND ./configure --prefix=${LIBYAML_INSTALL_DIR} CFLAGS=-fPIC CPPFLAGS=-fPIC --enable-static=true --enable-shared=false
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
BUILD_BYPRODUCTS ${LIBYAML_LIB}
|
||||
INSTALL_COMMAND ${CMD_MAKE} install
|
||||
)
|
||||
ExternalProject_Add(
|
||||
libyaml
|
||||
URL "https://github.com/yaml/libyaml/releases/download/0.2.5/yaml-0.2.5.tar.gz"
|
||||
URL_HASH "SHA256=c642ae9b75fee120b2d96c712538bd2cf283228d2337df2cf2988e3c02678ef4"
|
||||
CONFIGURE_COMMAND ./configure --prefix=${LIBYAML_INSTALL_DIR} CFLAGS=-fPIC CPPFLAGS=-fPIC --enable-static=true --enable-shared=false
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_COMMAND ${CMD_MAKE} install)
|
||||
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
#
|
||||
|
||||
set(LPEG_SRC "${PROJECT_BINARY_DIR}/lpeg-prefix/src/lpeg")
|
||||
set(LPEG_LIB "${PROJECT_BINARY_DIR}/lpeg-prefix/src/lpeg/build/lpeg.a")
|
||||
message(STATUS "Using bundled lpeg in '${LPEG_SRC}'")
|
||||
set(LPEG_DEPENDENCIES "")
|
||||
list(APPEND LPEG_DEPENDENCIES "luajit")
|
||||
ExternalProject_Add(
|
||||
lpeg
|
||||
DEPENDS ${LPEG_DEPENDENCIES}
|
||||
URL "http://www.inf.puc-rio.br/~roberto/lpeg/lpeg-1.0.2.tar.gz"
|
||||
URL_HASH "SHA256=48d66576051b6c78388faad09b70493093264588fcd0f258ddaab1cdd4a15ffe"
|
||||
BUILD_COMMAND LUA_INCLUDE=${LUAJIT_INCLUDE} "${PROJECT_SOURCE_DIR}/scripts/build-lpeg.sh" "${LPEG_SRC}/build"
|
||||
BUILD_IN_SOURCE 1
|
||||
BUILD_BYPRODUCTS ${LPEG_LIB}
|
||||
CONFIGURE_COMMAND ""
|
||||
INSTALL_COMMAND "")
|
||||
@@ -1,27 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
#
|
||||
|
||||
set(LUAJIT_SRC "${PROJECT_BINARY_DIR}/luajit-prefix/src/luajit/src")
|
||||
message(STATUS "Using bundled LuaJIT in '${LUAJIT_SRC}'")
|
||||
set(LUAJIT_INCLUDE "${LUAJIT_SRC}")
|
||||
set(LUAJIT_LIB "${LUAJIT_SRC}/libluajit.a")
|
||||
externalproject_add(
|
||||
luajit
|
||||
GIT_REPOSITORY "https://github.com/LuaJIT/LuaJIT"
|
||||
GIT_TAG "1d8b747c161db457e032a023ebbff511f5de5ec2"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
BUILD_BYPRODUCTS ${LUAJIT_LIB}
|
||||
INSTALL_COMMAND ""
|
||||
)
|
||||
@@ -1,28 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
#
|
||||
|
||||
set(LYAML_SRC "${PROJECT_BINARY_DIR}/lyaml-prefix/src/lyaml/ext/yaml")
|
||||
set(LYAML_LIB "${LYAML_SRC}/.libs/yaml.a")
|
||||
message(STATUS "Using bundled lyaml in '${LYAML_SRC}'")
|
||||
externalproject_add(
|
||||
lyaml
|
||||
DEPENDS luajit libyaml
|
||||
URL "https://github.com/gvvaughan/lyaml/archive/release-v6.0.tar.gz"
|
||||
URL_HASH "SHA256=9d7cf74d776999ff6f758c569d5202ff5da1f303c6f4229d3b41f71cd3a3e7a7"
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
BUILD_BYPRODUCTS ${LYAML_LIB}
|
||||
CONFIGURE_COMMAND ./configure --enable-static CFLAGS=-I${LIBYAML_INSTALL_DIR}/include CPPFLAGS=-I${LIBYAML_INSTALL_DIR}/include LDFLAGS=-L${LIBYAML_INSTALL_DIR}/lib LIBS=-lyaml LUA=${LUAJIT_SRC}/luajit LUA_INCLUDE=-I${LUAJIT_INCLUDE}
|
||||
INSTALL_COMMAND sh -c
|
||||
"cp -R ${PROJECT_BINARY_DIR}/lyaml-prefix/src/lyaml/lib/* ${PROJECT_SOURCE_DIR}/userspace/engine/lua"
|
||||
)
|
||||
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
# Copyright (C) 2019 The Falco Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
@@ -25,4 +25,4 @@ ExternalProject_Add(
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
PATCH_COMMAND patch -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/patch/libscap.patch && patch -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/patch/luajit.patch)
|
||||
PATCH_COMMAND patch -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/patch/libscap.patch)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
diff --git a/userspace/libscap/scap.c b/userspace/libscap/scap.c
|
||||
index 6f51588e..5f9ea84e 100644
|
||||
index e9faea51..a1b3b501 100644
|
||||
--- a/userspace/libscap/scap.c
|
||||
+++ b/userspace/libscap/scap.c
|
||||
@@ -55,7 +55,7 @@ limitations under the License.
|
||||
@@ -52,7 +52,7 @@ limitations under the License.
|
||||
//#define NDEBUG
|
||||
#include <assert.h>
|
||||
|
||||
@@ -11,16 +11,7 @@ index 6f51588e..5f9ea84e 100644
|
||||
|
||||
//
|
||||
// Probe version string size
|
||||
@@ -114,7 +114,7 @@ scap_t* scap_open_udig_int(char *error, int32_t *rc,
|
||||
static uint32_t get_max_consumers()
|
||||
{
|
||||
uint32_t max;
|
||||
- FILE *pfile = fopen("/sys/module/" PROBE_DEVICE_NAME "_probe/parameters/max_consumers", "r");
|
||||
+ FILE *pfile = fopen("/sys/module/" PROBE_DEVICE_NAME "/parameters/max_consumers", "r");
|
||||
if(pfile != NULL)
|
||||
{
|
||||
int w = fscanf(pfile, "%"PRIu32, &max);
|
||||
@@ -186,7 +186,7 @@ scap_t* scap_open_live_int(char *error, int32_t *rc,
|
||||
@@ -171,7 +171,7 @@ scap_t* scap_open_live_int(char *error, int32_t *rc,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -29,27 +20,7 @@ index 6f51588e..5f9ea84e 100644
|
||||
bpf_probe = buf;
|
||||
}
|
||||
}
|
||||
@@ -344,7 +344,7 @@ scap_t* scap_open_live_int(char *error, int32_t *rc,
|
||||
else if(errno == EBUSY)
|
||||
{
|
||||
uint32_t curr_max_consumers = get_max_consumers();
|
||||
- snprintf(error, SCAP_LASTERR_SIZE, "Too many sysdig instances attached to device %s. Current value for /sys/module/" PROBE_DEVICE_NAME "_probe/parameters/max_consumers is '%"PRIu32"'.", filename, curr_max_consumers);
|
||||
+ snprintf(error, SCAP_LASTERR_SIZE, "Too many Falco instances attached to device %s. Current value for /sys/module/" PROBE_DEVICE_NAME "/parameters/max_consumers is '%"PRIu32"'.", filename, curr_max_consumers);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -579,8 +579,8 @@ scap_t* scap_open_udig_int(char *error, int32_t *rc,
|
||||
//
|
||||
// Map the ppm_ring_buffer_info that contains the buffer pointers
|
||||
//
|
||||
- if(udig_alloc_ring_descriptors(&(handle->m_devs[0].m_bufinfo_fd),
|
||||
- &handle->m_devs[0].m_bufinfo,
|
||||
+ if(udig_alloc_ring_descriptors(&(handle->m_devs[0].m_bufinfo_fd),
|
||||
+ &handle->m_devs[0].m_bufinfo,
|
||||
&handle->m_devs[0].m_bufstatus,
|
||||
error) != SCAP_SUCCESS)
|
||||
{
|
||||
@@ -2175,7 +2175,7 @@ int32_t scap_disable_dynamic_snaplen(scap_t* handle)
|
||||
@@ -1808,7 +1808,7 @@ int32_t scap_disable_dynamic_snaplen(scap_t* handle)
|
||||
|
||||
const char* scap_get_host_root()
|
||||
{
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
diff --git a/userspace/libsinsp/chisel.cpp b/userspace/libsinsp/chisel.cpp
|
||||
index 0a6e3cf8..0c2e255a 100644
|
||||
--- a/userspace/libsinsp/chisel.cpp
|
||||
+++ b/userspace/libsinsp/chisel.cpp
|
||||
@@ -98,7 +98,7 @@ void lua_stackdump(lua_State *L)
|
||||
// Lua callbacks
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#ifdef HAS_LUA_CHISELS
|
||||
-const static struct luaL_reg ll_sysdig [] =
|
||||
+const static struct luaL_Reg ll_sysdig [] =
|
||||
{
|
||||
{"set_filter", &lua_cbacks::set_global_filter},
|
||||
{"set_snaplen", &lua_cbacks::set_snaplen},
|
||||
@@ -134,7 +134,7 @@ const static struct luaL_reg ll_sysdig [] =
|
||||
{NULL,NULL}
|
||||
};
|
||||
|
||||
-const static struct luaL_reg ll_chisel [] =
|
||||
+const static struct luaL_Reg ll_chisel [] =
|
||||
{
|
||||
{"request_field", &lua_cbacks::request_field},
|
||||
{"set_filter", &lua_cbacks::set_filter},
|
||||
@@ -146,7 +146,7 @@ const static struct luaL_reg ll_chisel [] =
|
||||
{NULL,NULL}
|
||||
};
|
||||
|
||||
-const static struct luaL_reg ll_evt [] =
|
||||
+const static struct luaL_Reg ll_evt [] =
|
||||
{
|
||||
{"field", &lua_cbacks::field},
|
||||
{"get_num", &lua_cbacks::get_num},
|
||||
diff --git a/userspace/libsinsp/lua_parser.cpp b/userspace/libsinsp/lua_parser.cpp
|
||||
index 0e26617d..78810d96 100644
|
||||
--- a/userspace/libsinsp/lua_parser.cpp
|
||||
+++ b/userspace/libsinsp/lua_parser.cpp
|
||||
@@ -32,7 +32,7 @@ extern "C" {
|
||||
#include "lauxlib.h"
|
||||
}
|
||||
|
||||
-const static struct luaL_reg ll_filter [] =
|
||||
+const static struct luaL_Reg ll_filter [] =
|
||||
{
|
||||
{"rel_expr", &lua_parser_cbacks::rel_expr},
|
||||
{"bool_op", &lua_parser_cbacks::bool_op},
|
||||
diff --git a/userspace/libsinsp/lua_parser_api.cpp b/userspace/libsinsp/lua_parser_api.cpp
|
||||
index c89e9126..c3d8008a 100644
|
||||
--- a/userspace/libsinsp/lua_parser_api.cpp
|
||||
+++ b/userspace/libsinsp/lua_parser_api.cpp
|
||||
@@ -266,7 +266,7 @@ int lua_parser_cbacks::rel_expr(lua_State *ls)
|
||||
string err = "Got non-table as in-expression operand\n";
|
||||
throw sinsp_exception("parser API error");
|
||||
}
|
||||
- int n = luaL_getn(ls, 4); /* get size of table */
|
||||
+ int n = lua_objlen (ls, 4); /* get size of table */
|
||||
for (i=1; i<=n; i++)
|
||||
{
|
||||
lua_rawgeti(ls, 4, i);
|
||||
@@ -29,8 +29,8 @@ file(MAKE_DIRECTORY ${SYSDIG_CMAKE_WORKING_DIR})
|
||||
# default below In case you want to test against another sysdig version just pass the variable - ie., `cmake
|
||||
# -DSYSDIG_VERSION=dev ..`
|
||||
if(NOT SYSDIG_VERSION)
|
||||
set(SYSDIG_VERSION "5c0b863ddade7a45568c0ac97d037422c9efb750")
|
||||
set(SYSDIG_CHECKSUM "SHA256=9de717b3a4b611ea6df56afee05171860167112f74bb7717b394bcc88ac843cd")
|
||||
set(SYSDIG_VERSION "2aa88dcf6243982697811df4c1b484bcbe9488a2")
|
||||
set(SYSDIG_CHECKSUM "SHA256=a737077543a6f3473ab306b424bcf7385d788149829ed1538252661b0f20d0f6")
|
||||
endif()
|
||||
set(PROBE_VERSION "${SYSDIG_VERSION}")
|
||||
|
||||
@@ -57,7 +57,6 @@ add_subdirectory("${SYSDIG_SOURCE_DIR}/driver" "${PROJECT_BINARY_DIR}/driver")
|
||||
# Add libscap directory
|
||||
add_definitions(-D_GNU_SOURCE)
|
||||
add_definitions(-DHAS_CAPTURE)
|
||||
add_definitions(-DNOCURSESUI)
|
||||
if(MUSL_OPTIMIZED_BUILD)
|
||||
add_definitions(-DMUSL_OPTIMIZED)
|
||||
endif()
|
||||
|
||||
@@ -3,7 +3,7 @@ FROM falcosecurity/falco:${FALCO_IMAGE_TAG}
|
||||
|
||||
LABEL maintainer="cncf-falco-dev@lists.cncf.io"
|
||||
|
||||
LABEL usage="docker run -i -t --privileged -v /root/.falco:/root/.falco -v /proc:/host/proc:ro -v /boot:/host/boot:ro -v /lib/modules:/host/lib/modules:ro -v /usr:/host/usr:ro -v /etc:/host/etc:ro --name NAME IMAGE"
|
||||
LABEL usage="docker run -i -t -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 HOST_ROOT /host
|
||||
ENV HOME /root
|
||||
|
||||
@@ -2,7 +2,7 @@ FROM debian:stable
|
||||
|
||||
LABEL maintainer="cncf-falco-dev@lists.cncf.io"
|
||||
|
||||
LABEL usage="docker run -i -t --privileged -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 -v /etc:/host/etc --name NAME IMAGE"
|
||||
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"
|
||||
|
||||
ARG FALCO_VERSION=latest
|
||||
ARG VERSION_BUCKET=deb
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
FROM ubuntu:18.04 as ubuntu
|
||||
|
||||
LABEL maintainer="cncf-falco-dev@lists.cncf.io"
|
||||
|
||||
ARG FALCO_VERSION
|
||||
ARG VERSION_BUCKET=bin
|
||||
|
||||
@@ -20,14 +22,6 @@ RUN sed -e 's/time_format_iso_8601: false/time_format_iso_8601: true/' < /falco/
|
||||
|
||||
FROM scratch
|
||||
|
||||
LABEL maintainer="cncf-falco-dev@lists.cncf.io"
|
||||
|
||||
LABEL usage="docker run -i -t --privileged -v /var/run/docker.sock:/host/var/run/docker.sock -v /dev:/host/dev -v /proc:/host/proc:ro --name NAME IMAGE"
|
||||
# NOTE: for the "least privileged" use case, please refer to the official documentation
|
||||
|
||||
ENV HOST_ROOT /host
|
||||
ENV HOME /root
|
||||
|
||||
COPY --from=ubuntu /falco /
|
||||
|
||||
CMD ["/usr/bin/falco", "-o", "time_format_iso_8601=true"]
|
||||
@@ -1,5 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -u -o pipefail
|
||||
|
||||
BUILD_DIR=${BUILD_DIR:-/build}
|
||||
SOURCE_DIR=${SOURCE_DIR:-/source}
|
||||
SKIP_PACKAGES_TESTS=${SKIP_PACKAGES_TESTS:-false}
|
||||
@@ -7,9 +9,6 @@ SKIP_PACKAGES_TESTS=${SKIP_PACKAGES_TESTS:-false}
|
||||
CMD=${1:-test}
|
||||
shift
|
||||
|
||||
# Stop the execution if a command in the pipeline has an error, from now on
|
||||
set -e -u -o pipefail
|
||||
|
||||
# build type can be "debug" or "release", fallbacks to "release" by default
|
||||
BUILD_TYPE=$(echo "$BUILD_TYPE" | tr "[:upper:]" "[:lower:]")
|
||||
case "$BUILD_TYPE" in
|
||||
@@ -50,8 +49,7 @@ case "$CMD" in
|
||||
"test")
|
||||
if [ -z "$FALCO_VERSION" ]; then
|
||||
echo "Automatically figuring out Falco version."
|
||||
FALCO_VERSION_FULL=$("$BUILD_DIR/$BUILD_TYPE/userspace/falco/falco" --version)
|
||||
FALCO_VERSION=$(echo "$FALCO_VERSION_FULL" | head -n 1 | cut -d' ' -f3 | tr -d '\r')
|
||||
FALCO_VERSION=$("$BUILD_DIR/$BUILD_TYPE/userspace/falco/falco" --version | head -n 1 | cut -d' ' -f3 | tr -d '\r')
|
||||
echo "Falco version: $FALCO_VERSION"
|
||||
fi
|
||||
if [ -z "$FALCO_VERSION" ]; then
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
# Falco Drivers Storage S3
|
||||
|
||||
Supersedes: [20200818-artifacts-storage.md#drivers](20200818-artifacts-storage.md#drivers)
|
||||
|
||||
Supersedes: [20200901-artifacts-cleanup.md#drivers](20200901-artifacts-cleanup.md#drivers)
|
||||
|
||||
## Introduction
|
||||
|
||||
In the past days, as many people probably noticed, Bintray started rate-limiting our users, effectively preventing them from downloading any kernel module, rpm/deb package or any pre-built dependency we host there.
|
||||
|
||||
This does not only interrupt the workflow of our users but also the workflow of the contributors, since without bintray most of our container images and CMake files can’t download the dependencies we mirror.
|
||||
|
||||
### What is the cause?
|
||||
|
||||
We had a spike in adoption apparently, either a user with many nodes or an increased number of users. We don’t know this detail specifically yet because bintray does not give us very fine-grained statistics on this.
|
||||
|
||||
This is the 30-days history:
|
||||
|
||||

|
||||
|
||||
As you can see, we can only see that they downloaded the latest kernel module driver version, however we can’t see if:
|
||||
|
||||
* It’s a single source or many different users
|
||||
|
||||
* What is the kernel/OS they are using
|
||||
|
||||
### What do we host on Bintray?
|
||||
|
||||
* RPM packages: high traffic but very manageable ~90k downloads a month
|
||||
|
||||
* Deb packages:low traffic ~5k downloads a month
|
||||
|
||||
* Pre-built image Dependencies: low traffic, will eventually disappear in the future
|
||||
|
||||
* Kernel modules: very high traffic, 700k downloads in 10 days, this is what is causing the current problems. They are primarily used by users of our container images.
|
||||
|
||||
* eBPF probes: low traffic ~5k downloads a month
|
||||
|
||||
### Motivations to go to S3 instead of Bintray for the Drivers
|
||||
|
||||
Bintray does an excellent service at building the rpm/deb structures for us, however we also use them for S3-like storage for the drivers. We have ten thousand files hosted there and the combinations are infinite.
|
||||
|
||||
|
||||
Before today, we had many issues with storage even without the spike in users we are seeing since the last ten days.
|
||||
|
||||
## Context on AWS
|
||||
|
||||
Amazon AWS, recently gave credits to the Falco project to operate some parts of the infrastructure on AWS. The CNCF is providing a sub-account we are already using for the migration of the other pieces (like Prow).
|
||||
|
||||
## Interactions with other teams and the CNCF
|
||||
|
||||
* The setup on the AWS account side already done, this is all technical work.
|
||||
|
||||
* We need to open a CNCF service account ticket for the download.falco.org subdomain to point to the S3 bucket we want to use
|
||||
|
||||
## The Plan
|
||||
|
||||
We want to propose to move the drivers and the container dependencies to S3.
|
||||
|
||||
#### Moving means:
|
||||
|
||||
* We create a public S3 bucket with [stats enabled](https://docs.aws.amazon.com/AmazonS3/latest/dev/analytics-storage-class.html)
|
||||
|
||||
* We attach the bucket to a cloudfront distribution behind the download.falco.org subdomain
|
||||
|
||||
* We move the current content keeping the same web server directory structure
|
||||
|
||||
* We change the Falco Dockerfiles and driver loader script accordingly
|
||||
|
||||
* We update test-infra to push the drivers to S3
|
||||
|
||||
* Once we have the drivers in S3, we can ask bintray to relax the limits for this month so that our users are able to download the other packages we keep there. Otherwise they will have to wait until November 1st. We only want to do that after the moving because otherwise we will hit the limits pretty quickly.
|
||||
|
||||
#### The repositories we want to move are:
|
||||
|
||||
* [https://bintray.com/falcosecurity/driver](https://bintray.com/falcosecurity/driver) will become https://download.falco.org/driver
|
||||
|
||||
* [https://bintray.com/falcosecurity/dependencies](https://bintray.com/falcosecurity/dependencies) will become https://download.falco.org/dependencies
|
||||
|
||||
#### Changes in Falco
|
||||
|
||||
* [Search for bintray ](https://github.com/falcosecurity/falco/search?p=2&q=bintray)on the Falco repo and replace the URL for the CMake and Docker files.
|
||||
|
||||
* It’s very important to change the DRIVERS_REPO environment variable [here](https://github.com/falcosecurity/falco/blob/0a33f555eb8e019806b46fea8b80a6302a935421/CMakeLists.txt#L86) - this is what updates the falco-driver-loader scripts that the users and container images use to fetch the module
|
||||
|
||||
#### Changes in Test Infra
|
||||
|
||||
* We need to use the S3 cli instead of jfrog cli to upload to the s3 bucket after building [here](https://github.com/falcosecurity/test-infra/blob/master/.circleci/config.yml)
|
||||
|
||||
* We can probably remove jfrog from that repo since it only deals with drivers and drivers are being put on S3 now
|
||||
|
||||
* Instructions on how to setup the S3 directory structure [here](https://falco.org/docs/installation/#install-driver)
|
||||
|
||||
* `/$driver_version$/falco_$target$_$kernelrelease$_$kernelversion$.[ko|o]`
|
||||
|
||||
#### Changes to Falco website
|
||||
|
||||
* Changes should not be necessary, we are not updating the way people install Falco but only the driver. The driver is managed by a script we can change.
|
||||
|
||||
## Mitigation and next steps for the users
|
||||
|
||||
* **The average users should be good to go now, Bintray raised our limits and we have some room to do this without requiring manual steps on your end**
|
||||
|
||||
* **Users that can’t wait for us to have the S3 setup done: **can setup an S3 as driver repo themselves, push the drivers they need to it after compiling them (they can use [Driverkit](https://github.com/falcosecurity/driverkit) for that) Instructions on how to setup the S3 directory structure [here](https://falco.org/docs/installation/#install-driver).
|
||||
|
||||
* **Users that can’t wait but don’t want to setup a webserver themselves**: the falco-driver-loader script can also compile the module for you. Make sure to install the kernel-headers on your nodes.
|
||||
|
||||
* **Users that can wait** we will approve this document and act on the plan described here by providing the DRIVERS_REPO at [https://download.falco.org/driver](https://download.falco.org/driver) that then you can use
|
||||
|
||||
### How to use an alternative DRIVERS_REPO ?
|
||||
|
||||
**On bash:**
|
||||
|
||||
export DRIVERS_REPO=https://your-url-here
|
||||
|
||||
**Docker**
|
||||
|
||||
Pass it as environment variable using the docker run flag -e - for example:
|
||||
|
||||
docker run -e DRIVERS_REPO=[https://your-url-here](https://your-url-here)
|
||||
|
||||
**Kubernetes**
|
||||
|
||||
spec:
|
||||
|
||||
containers:
|
||||
|
||||
- env:
|
||||
|
||||
- name: DRIVERS_REPO
|
||||
|
||||
value: https://your-url-here
|
||||
|
||||
## Release
|
||||
|
||||
Next release is on December 1st, we want to rollout a hotfix 0.26.2 release that only contains the updated script before that date so that users don’t get confused and we can just tell them "update Falco" to get the thing working again.
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 43 KiB |
File diff suppressed because it is too large
Load Diff
@@ -49,8 +49,7 @@
|
||||
"kubernetes-admin",
|
||||
vertical_pod_autoscaler_users,
|
||||
cluster-autoscaler,
|
||||
"system:addon-manager",
|
||||
"cloud-controller-manager"
|
||||
"system:addon-manager"
|
||||
]
|
||||
|
||||
- rule: Disallowed K8s User
|
||||
@@ -537,7 +536,7 @@
|
||||
condition: >
|
||||
kevt
|
||||
and non_system_user
|
||||
and ka.user.name in (full_admin_k8s_users)
|
||||
and ka.user.name in (admin_k8s_users)
|
||||
and not allowed_full_admin_users
|
||||
output: K8s Operation performed by full admin user (user=%ka.user.name target=%ka.target.name/%ka.target.resource verb=%ka.verb uri=%ka.uri resp=%ka.response.code)
|
||||
priority: WARNING
|
||||
|
||||
@@ -220,7 +220,7 @@ load_kernel_module() {
|
||||
rmmod "${DRIVER_NAME}" 2>/dev/null
|
||||
WAIT_TIME=0
|
||||
KMOD_NAME=$(echo "${DRIVER_NAME}" | tr "-" "_")
|
||||
while lsmod | cut -d' ' -f1 | grep -qx "${KMOD_NAME}" && [ $WAIT_TIME -lt "${MAX_RMMOD_WAIT}" ]; do
|
||||
while lsmod | grep "${KMOD_NAME}" > /dev/null 2>&1 && [ $WAIT_TIME -lt "${MAX_RMMOD_WAIT}" ]; do
|
||||
if rmmod "${DRIVER_NAME}" 2>/dev/null; then
|
||||
echo "* Unloading ${DRIVER_NAME} module succeeded after ${WAIT_TIME}s"
|
||||
break
|
||||
@@ -232,7 +232,7 @@ load_kernel_module() {
|
||||
sleep 1
|
||||
done
|
||||
|
||||
if lsmod | cut -d' ' -f1 | grep -qx "${KMOD_NAME}" > /dev/null 2>&1; then
|
||||
if lsmod | grep "${KMOD_NAME}" > /dev/null 2>&1; then
|
||||
echo "* ${DRIVER_NAME} module seems to still be loaded, hoping the best"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
@@ -41,4 +41,4 @@ stdout_output:
|
||||
|
||||
program_output:
|
||||
enabled: true
|
||||
program: cat >> /tmp/falco_outputs/program_output.txt
|
||||
program: cat > /tmp/falco_outputs/program_output.txt
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright (C) 2019 The Falco Authors.
|
||||
#
|
||||
@@ -31,7 +31,6 @@ from avocado.utils import process
|
||||
from watchdog.observers import Observer
|
||||
from watchdog.events import PatternMatchingEventHandler
|
||||
|
||||
|
||||
class FalcoTest(Test):
|
||||
|
||||
def setUp(self):
|
||||
@@ -50,20 +49,17 @@ class FalcoTest(Test):
|
||||
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='')
|
||||
self.stdout_contains = self.params.get('stdout_contains', '*', default='')
|
||||
|
||||
if not isinstance(self.stdout_contains, list):
|
||||
self.stdout_contains = [self.stdout_contains]
|
||||
|
||||
self.stderr_contains = self.params.get(
|
||||
'stderr_contains', '*', default='')
|
||||
self.stderr_contains = self.params.get('stderr_contains', '*', default='')
|
||||
|
||||
if not isinstance(self.stderr_contains, list):
|
||||
self.stderr_contains = [self.stderr_contains]
|
||||
|
||||
self.stdout_not_contains = self.params.get(
|
||||
'stdout_not_contains', '*', default='')
|
||||
self.stdout_not_contains = self.params.get('stdout_not_contains', '*', default='')
|
||||
|
||||
if not isinstance(self.stdout_not_contains, list):
|
||||
if self.stdout_not_contains == '':
|
||||
@@ -71,8 +67,7 @@ class FalcoTest(Test):
|
||||
else:
|
||||
self.stdout_not_contains = [self.stdout_not_contains]
|
||||
|
||||
self.stderr_not_contains = self.params.get(
|
||||
'stderr_not_contains', '*', default='')
|
||||
self.stderr_not_contains = self.params.get('stderr_not_contains', '*', default='')
|
||||
|
||||
if not isinstance(self.stderr_not_contains, list):
|
||||
if self.stderr_not_contains == '':
|
||||
@@ -88,18 +83,15 @@ class FalcoTest(Test):
|
||||
self.trace_file = os.path.join(build_dir, "test", self.trace_file)
|
||||
|
||||
self.json_output = self.params.get('json_output', '*', default=False)
|
||||
self.json_include_output_property = self.params.get(
|
||||
'json_include_output_property', '*', default=True)
|
||||
self.json_include_output_property = self.params.get('json_include_output_property', '*', default=True)
|
||||
self.all_events = self.params.get('all_events', '*', default=False)
|
||||
self.priority = self.params.get('priority', '*', default='debug')
|
||||
self.rules_file = self.params.get(
|
||||
'rules_file', '*', default=os.path.join(self.basedir, '../rules/falco_rules.yaml'))
|
||||
self.rules_file = self.params.get('rules_file', '*', default=os.path.join(self.basedir, '../rules/falco_rules.yaml'))
|
||||
|
||||
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)
|
||||
self.validate_rules_file = self.params.get('validate_rules_file', '*', default=False)
|
||||
|
||||
if self.validate_rules_file == False:
|
||||
self.validate_rules_file = []
|
||||
@@ -126,15 +118,13 @@ class FalcoTest(Test):
|
||||
file = os.path.join(self.basedir, file)
|
||||
self.rules_args = self.rules_args + "-r " + file + " "
|
||||
|
||||
self.conf_file = self.params.get(
|
||||
'conf_file', '*', default=os.path.join(self.basedir, '../falco.yaml'))
|
||||
self.conf_file = self.params.get('conf_file', '*', default=os.path.join(self.basedir, '../falco.yaml'))
|
||||
if not os.path.isabs(self.conf_file):
|
||||
self.conf_file = os.path.join(self.basedir, self.conf_file)
|
||||
|
||||
self.run_duration = self.params.get('run_duration', '*', default='')
|
||||
|
||||
self.disabled_rules = self.params.get(
|
||||
'disabled_rules', '*', default='')
|
||||
self.disabled_rules = self.params.get('disabled_rules', '*', default='')
|
||||
|
||||
if self.disabled_rules == '':
|
||||
self.disabled_rules = []
|
||||
@@ -147,8 +137,7 @@ class FalcoTest(Test):
|
||||
for rule in self.disabled_rules:
|
||||
self.disabled_args = self.disabled_args + "-D " + rule + " "
|
||||
|
||||
self.detect_counts = self.params.get(
|
||||
'detect_counts', '*', default=False)
|
||||
self.detect_counts = self.params.get('detect_counts', '*', default=False)
|
||||
if self.detect_counts == False:
|
||||
self.detect_counts = {}
|
||||
else:
|
||||
@@ -158,8 +147,7 @@ class FalcoTest(Test):
|
||||
detect_counts[key] = value
|
||||
self.detect_counts = detect_counts
|
||||
|
||||
self.rules_warning = self.params.get(
|
||||
'rules_warning', '*', default=False)
|
||||
self.rules_warning = self.params.get('rules_warning', '*', default=False)
|
||||
if self.rules_warning == False:
|
||||
self.rules_warning = set()
|
||||
else:
|
||||
@@ -184,11 +172,9 @@ class FalcoTest(Test):
|
||||
|
||||
self.package = self.params.get('package', '*', default='None')
|
||||
|
||||
self.addl_docker_run_args = self.params.get(
|
||||
'addl_docker_run_args', '*', default='')
|
||||
self.addl_docker_run_args = self.params.get('addl_docker_run_args', '*', default='')
|
||||
|
||||
self.copy_local_driver = self.params.get(
|
||||
'copy_local_driver', '*', default=False)
|
||||
self.copy_local_driver = self.params.get('copy_local_driver', '*', default=False)
|
||||
|
||||
# Used by possibly_copy_local_driver as well as docker run
|
||||
self.module_dir = os.path.expanduser("~/.falco")
|
||||
@@ -211,33 +197,9 @@ class FalcoTest(Test):
|
||||
os.makedirs(filedir)
|
||||
self.outputs = outputs
|
||||
|
||||
self.output_strictly_contains = self.params.get(
|
||||
'output_strictly_contains', '*', default='')
|
||||
|
||||
if self.output_strictly_contains == '':
|
||||
self.output_strictly_contains = {}
|
||||
else:
|
||||
output_strictly_contains = []
|
||||
for item in self.output_strictly_contains:
|
||||
for key, value in list(item.items()):
|
||||
output = {}
|
||||
output['actual'] = key
|
||||
output['expected'] = value
|
||||
output_strictly_contains.append(output)
|
||||
if not output['actual'] == 'stdout':
|
||||
# Clean up file from previous tests, if any
|
||||
if os.path.exists(output['actual']):
|
||||
os.remove(output['actual'])
|
||||
# Create the parent directory for the file if it doesn't exist.
|
||||
filedir = os.path.dirname(output['actual'])
|
||||
if not os.path.isdir(filedir):
|
||||
os.makedirs(filedir)
|
||||
self.output_strictly_contains = output_strictly_contains
|
||||
|
||||
self.grpcurl_res = None
|
||||
self.grpc_observer = None
|
||||
self.grpc_address = self.params.get(
|
||||
'address', 'grpc/*', default='/var/run/falco.sock')
|
||||
self.grpc_address = self.params.get('address', 'grpc/*', default='/var/run/falco.sock')
|
||||
if self.grpc_address.startswith("unix://"):
|
||||
self.is_grpc_using_unix_socket = True
|
||||
self.grpc_address = self.grpc_address[len("unix://"):]
|
||||
@@ -249,22 +211,21 @@ class FalcoTest(Test):
|
||||
self.grpc_results = self.params.get('results', 'grpc/*', default='')
|
||||
if self.grpc_results == '':
|
||||
self.grpc_results = []
|
||||
else:
|
||||
else:
|
||||
if type(self.grpc_results) == str:
|
||||
self.grpc_results = [self.grpc_results]
|
||||
|
||||
self.disable_tags = self.params.get('disable_tags', '*', default='')
|
||||
|
||||
if self.disable_tags == '':
|
||||
self.disable_tags = []
|
||||
self.disable_tags=[]
|
||||
|
||||
self.run_tags = self.params.get('run_tags', '*', default='')
|
||||
|
||||
if self.run_tags == '':
|
||||
self.run_tags = []
|
||||
self.run_tags=[]
|
||||
|
||||
self.time_iso_8601 = self.params.get(
|
||||
'time_iso_8601', '*', default=False)
|
||||
self.time_iso_8601 = self.params.get('time_iso_8601', '*', default=False)
|
||||
|
||||
def tearDown(self):
|
||||
if self.package != 'None':
|
||||
@@ -283,8 +244,7 @@ class FalcoTest(Test):
|
||||
self.log.debug("Actual warning rules: {}".format(found_warning))
|
||||
|
||||
if found_warning != self.rules_warning:
|
||||
self.fail("Expected rules with warnings {} does not match actual rules with warnings {}".format(
|
||||
self.rules_warning, found_warning))
|
||||
self.fail("Expected rules with warnings {} does not match actual rules with warnings {}".format(self.rules_warning, found_warning))
|
||||
|
||||
def check_rules_events(self, res):
|
||||
|
||||
@@ -295,60 +255,50 @@ class FalcoTest(Test):
|
||||
events = set(match.group(2).split(","))
|
||||
found_events[rule] = events
|
||||
|
||||
self.log.debug(
|
||||
"Expected events for rules: {}".format(self.rules_events))
|
||||
self.log.debug("Expected events for rules: {}".format(self.rules_events))
|
||||
self.log.debug("Actual events for rules: {}".format(found_events))
|
||||
|
||||
for rule in list(found_events.keys()):
|
||||
if found_events.get(rule) != self.rules_events.get(rule):
|
||||
self.fail("rule {}: expected events {} differs from actual events {}".format(
|
||||
rule, self.rules_events.get(rule), found_events.get(rule)))
|
||||
self.fail("rule {}: expected events {} differs from actual events {}".format(rule, self.rules_events.get(rule), found_events.get(rule)))
|
||||
|
||||
def check_detections(self, res):
|
||||
# Get the number of events detected.
|
||||
match = re.search('Events detected: (\d+)', res.stdout.decode("utf-8"))
|
||||
if match is None:
|
||||
self.fail(
|
||||
"Could not find a line 'Events detected: <count>' in falco output")
|
||||
self.fail("Could not find a line 'Events detected: <count>' in falco output")
|
||||
|
||||
events_detected = int(match.group(1))
|
||||
|
||||
if not self.should_detect and events_detected > 0:
|
||||
self.fail("Detected {} events when should have detected none".format(
|
||||
events_detected))
|
||||
self.fail("Detected {} events when should have detected none".format(events_detected))
|
||||
|
||||
if self.should_detect:
|
||||
if events_detected == 0:
|
||||
self.fail("Detected {} events when should have detected > 0".format(
|
||||
events_detected))
|
||||
self.fail("Detected {} events when should have detected > 0".format(events_detected))
|
||||
|
||||
for level in self.detect_level:
|
||||
level_line = '(?i){}: (\d+)'.format(level)
|
||||
match = re.search(level_line, res.stdout.decode("utf-8"))
|
||||
|
||||
if match is None:
|
||||
self.fail(
|
||||
"Could not find a line '{}: <count>' in falco output".format(level))
|
||||
self.fail("Could not find a line '{}: <count>' in falco output".format(level))
|
||||
|
||||
events_detected = int(match.group(1))
|
||||
|
||||
if not events_detected > 0:
|
||||
self.fail("Detected {} events at level {} when should have detected > 0".format(
|
||||
events_detected, level))
|
||||
self.fail("Detected {} events at level {} when should have detected > 0".format(events_detected, level))
|
||||
|
||||
def check_detections_by_rule(self, res):
|
||||
# Get the number of events detected for each rule. Must match the expected counts.
|
||||
match = re.search('Triggered rules by rule name:(.*)',
|
||||
res.stdout.decode("utf-8"), re.DOTALL)
|
||||
match = re.search('Triggered rules by rule name:(.*)', res.stdout.decode("utf-8"), re.DOTALL)
|
||||
if match is None:
|
||||
self.fail(
|
||||
"Could not find a block 'Triggered rules by rule name: ...' in falco output")
|
||||
self.fail("Could not find a block 'Triggered rules by rule name: ...' in falco output")
|
||||
|
||||
triggered_rules = match.group(1)
|
||||
|
||||
for rule, count in list(self.detect_counts.items()):
|
||||
expected = '\s{}: (\d+)'.format(
|
||||
re.sub(r'([$\.*+?()[\]{}|^])', r'\\\1', rule))
|
||||
expected = '\s{}: (\d+)'.format(re.sub(r'([$\.*+?()[\]{}|^])', r'\\\1', rule))
|
||||
match = re.search(expected, triggered_rules)
|
||||
|
||||
if match is None:
|
||||
@@ -357,11 +307,9 @@ class FalcoTest(Test):
|
||||
actual_count = int(match.group(1))
|
||||
|
||||
if actual_count != count:
|
||||
self.fail("Different counts for rule {}: expected={}, actual={}".format(
|
||||
rule, count, actual_count))
|
||||
self.fail("Different counts for rule {}: expected={}, actual={}".format(rule, count, actual_count))
|
||||
else:
|
||||
self.log.debug(
|
||||
"Found expected count for rule {}: {}".format(rule, count))
|
||||
self.log.debug("Found expected count for rule {}: {}".format(rule, count))
|
||||
|
||||
def check_outputs(self):
|
||||
for output in self.outputs:
|
||||
@@ -376,8 +324,7 @@ class FalcoTest(Test):
|
||||
found = True
|
||||
|
||||
if found == False:
|
||||
self.fail("Could not find a line '{}' in file '{}'".format(
|
||||
output['line'], output['file']))
|
||||
self.fail("Could not find a line '{}' in file '{}'".format(output['line'], output['file']))
|
||||
|
||||
return True
|
||||
|
||||
@@ -394,27 +341,7 @@ class FalcoTest(Test):
|
||||
attrs = ['time', 'rule', 'priority']
|
||||
for attr in attrs:
|
||||
if not attr in obj:
|
||||
self.fail(
|
||||
"Falco JSON object {} does not contain property \"{}\"".format(line, attr))
|
||||
|
||||
def check_output_strictly_contains(self, res):
|
||||
for output in self.output_strictly_contains:
|
||||
# Read the expected output (from a file) and actual output (either from a file or the stdout),
|
||||
# then check if the actual one strictly contains the expected one.
|
||||
|
||||
expected = open(output['expected']).read()
|
||||
|
||||
if output['actual'] == 'stdout':
|
||||
actual = res.stdout.decode("utf-8")
|
||||
else:
|
||||
actual = open(output['actual']).read()
|
||||
|
||||
if expected not in actual:
|
||||
self.fail("Output '{}' does not strictly contains the expected content '{}'".format(
|
||||
output['actual'], output['expected']))
|
||||
return False
|
||||
|
||||
return True
|
||||
self.fail("Falco JSON object {} does not contain property \"{}\"".format(line, attr))
|
||||
|
||||
def install_package(self):
|
||||
|
||||
@@ -433,39 +360,35 @@ class FalcoTest(Test):
|
||||
self.module_dir, self.addl_docker_run_args, image)
|
||||
|
||||
elif self.package.endswith(".deb"):
|
||||
self.falco_binary_path = '/usr/bin/falco'
|
||||
self.falco_binary_path = '/usr/bin/falco';
|
||||
|
||||
package_glob = "{}/{}".format(self.falcodir, self.package)
|
||||
|
||||
matches = glob.glob(package_glob)
|
||||
|
||||
if len(matches) != 1:
|
||||
self.fail("Package path {} did not match exactly 1 file. Instead it matched: {}",
|
||||
package_glob, ",".join(matches))
|
||||
self.fail("Package path {} did not match exactly 1 file. Instead it matched: {}", package_glob, ",".join(matches))
|
||||
|
||||
package_path = matches[0]
|
||||
|
||||
cmdline = "dpkg -i {}".format(package_path)
|
||||
self.log.debug(
|
||||
"Installing debian package via \"{}\"".format(cmdline))
|
||||
self.log.debug("Installing debian package via \"{}\"".format(cmdline))
|
||||
res = process.run(cmdline, timeout=120, sudo=True)
|
||||
|
||||
elif self.package.endswith(".rpm"):
|
||||
self.falco_binary_path = '/usr/bin/falco'
|
||||
self.falco_binary_path = '/usr/bin/falco';
|
||||
|
||||
package_glob = "{}/{}".format(self.falcodir, self.package)
|
||||
|
||||
matches = glob.glob(package_glob)
|
||||
|
||||
if len(matches) != 1:
|
||||
self.fail("Package path {} did not match exactly 1 file. Instead it matched: {}",
|
||||
package_glob, ",".join(matches))
|
||||
self.fail("Package path {} did not match exactly 1 file. Instead it matched: {}", package_glob, ",".join(matches))
|
||||
|
||||
package_path = matches[0]
|
||||
|
||||
cmdline = "rpm -i --nodeps --noscripts {}".format(package_path)
|
||||
self.log.debug(
|
||||
"Installing centos package via \"{}\"".format(cmdline))
|
||||
self.log.debug("Installing centos package via \"{}\"".format(cmdline))
|
||||
res = process.run(cmdline, timeout=120, sudo=True)
|
||||
|
||||
def uninstall_package(self):
|
||||
@@ -475,29 +398,25 @@ class FalcoTest(Test):
|
||||
|
||||
elif self.package.endswith(".rpm"):
|
||||
cmdline = "rpm -e --noscripts --nodeps falco"
|
||||
self.log.debug(
|
||||
"Uninstalling centos package via \"{}\"".format(cmdline))
|
||||
self.log.debug("Uninstalling centos package via \"{}\"".format(cmdline))
|
||||
res = process.run(cmdline, timeout=120, sudo=True)
|
||||
|
||||
elif self.package.endswith(".deb"):
|
||||
cmdline = "dpkg --purge falco"
|
||||
self.log.debug(
|
||||
"Uninstalling debian package via \"{}\"".format(cmdline))
|
||||
self.log.debug("Uninstalling debian package via \"{}\"".format(cmdline))
|
||||
res = process.run(cmdline, timeout=120, sudo=True)
|
||||
|
||||
def possibly_copy_driver(self):
|
||||
# Remove the contents of ~/.falco regardless of copy_local_driver.
|
||||
self.log.debug("Checking for module dir {}".format(self.module_dir))
|
||||
if os.path.isdir(self.module_dir):
|
||||
self.log.info(
|
||||
"Removing files below directory {}".format(self.module_dir))
|
||||
self.log.info("Removing files below directory {}".format(self.module_dir))
|
||||
for rmfile in glob.glob(self.module_dir + "/*"):
|
||||
self.log.debug("Removing file {}".format(rmfile))
|
||||
os.remove(rmfile)
|
||||
|
||||
if self.copy_local_driver:
|
||||
verlines = [str.strip() for str in subprocess.check_output(
|
||||
[self.falco_binary_path, "--version"]).splitlines()]
|
||||
verlines = [str.strip() for str in subprocess.check_output([self.falco_binary_path, "--version"]).splitlines()]
|
||||
verstr = verlines[0].decode("utf-8")
|
||||
self.log.info("verstr {}".format(verstr))
|
||||
falco_version = verstr.split(" ")[2]
|
||||
@@ -509,12 +428,10 @@ class FalcoTest(Test):
|
||||
|
||||
# falco-driver-loader has a more comprehensive set of ways to
|
||||
# find the config hash. We only look at /boot/config-<kernel release>
|
||||
md5_output = subprocess.check_output(
|
||||
["md5sum", "/boot/config-{}".format(kernel_release)]).rstrip()
|
||||
md5_output = subprocess.check_output(["md5sum", "/boot/config-{}".format(kernel_release)]).rstrip()
|
||||
config_hash = md5_output.split(" ")[0]
|
||||
|
||||
probe_filename = "falco-{}-{}-{}-{}.ko".format(
|
||||
falco_version, arch, kernel_release, config_hash)
|
||||
probe_filename = "falco-{}-{}-{}-{}.ko".format(falco_version, arch, kernel_release, config_hash)
|
||||
driver_path = os.path.join(self.falcodir, "driver", "falco.ko")
|
||||
module_path = os.path.join(self.module_dir, probe_filename)
|
||||
self.log.debug("Copying {} to {}".format(driver_path, module_path))
|
||||
@@ -525,22 +442,20 @@ class FalcoTest(Test):
|
||||
if len(self.grpc_results) > 0:
|
||||
if not self.is_grpc_using_unix_socket:
|
||||
self.fail("This test suite supports gRPC with unix socket only")
|
||||
|
||||
cmdline = "grpcurl -format text -import-path ../userspace/falco " \
|
||||
"-proto {} -plaintext -unix {} " \
|
||||
"{}/{}".format(self.grpc_proto, self.grpc_address,
|
||||
self.grpc_service, self.grpc_method)
|
||||
|
||||
cmdline = "grpcurl -import-path ../userspace/falco " \
|
||||
"-proto {} -plaintext -unix {} " \
|
||||
"{}/{}".format(self.grpc_proto, self.grpc_address, self.grpc_service, self.grpc_method)
|
||||
that = self
|
||||
|
||||
class GRPCUnixSocketEventHandler(PatternMatchingEventHandler):
|
||||
def on_created(self, event):
|
||||
# that.log.info("EVENT: {}", event)
|
||||
that.grpcurl_res = process.run(cmdline)
|
||||
|
||||
|
||||
path = os.path.dirname(self.grpc_address)
|
||||
process.run("mkdir -p {}".format(path))
|
||||
event_handler = GRPCUnixSocketEventHandler(patterns=['*'],
|
||||
ignore_directories=True)
|
||||
ignore_directories=True)
|
||||
self.grpc_observer = Observer()
|
||||
self.grpc_observer.schedule(event_handler, path, recursive=False)
|
||||
self.grpc_observer.start()
|
||||
@@ -555,19 +470,19 @@ class FalcoTest(Test):
|
||||
for exp_result in self.grpc_results:
|
||||
found = False
|
||||
for line in self.grpcurl_res.stdout.decode("utf-8").splitlines():
|
||||
if exp_result in line:
|
||||
match = re.search(exp_result, line)
|
||||
|
||||
if match is not None:
|
||||
found = True
|
||||
break
|
||||
|
||||
if found == False:
|
||||
self.fail(
|
||||
"Could not find a line with '{}' in gRPC responses (protobuf text".format(exp_result))
|
||||
self.fail("Could not find a line '{}' in gRPC responses".format(exp_result))
|
||||
|
||||
|
||||
def test(self):
|
||||
self.log.info("Trace file %s", self.trace_file)
|
||||
|
||||
self.falco_binary_path = '{}/userspace/falco/falco'.format(
|
||||
self.falcodir)
|
||||
self.falco_binary_path = '{}/userspace/falco/falco'.format(self.falcodir)
|
||||
|
||||
self.possibly_copy_driver()
|
||||
|
||||
@@ -586,11 +501,9 @@ class FalcoTest(Test):
|
||||
if self.psp_file != "":
|
||||
|
||||
if not os.path.isfile(self.psp_conv_path):
|
||||
self.log.info("Downloading {} to {}".format(
|
||||
self.psp_conv_url, self.psp_conv_path))
|
||||
self.log.info("Downloading {} to {}".format(self.psp_conv_url, self.psp_conv_path))
|
||||
|
||||
urllib.request.urlretrieve(
|
||||
self.psp_conv_url, self.psp_conv_path)
|
||||
urllib.request.urlretrieve(self.psp_conv_url, self.psp_conv_path)
|
||||
os.chmod(self.psp_conv_path, stat.S_IEXEC)
|
||||
|
||||
conv_cmd = '{} convert psp --psp-path {} --rules-path {}'.format(
|
||||
@@ -608,6 +521,7 @@ class FalcoTest(Test):
|
||||
psp_rules = myfile.read()
|
||||
self.log.debug("Converted Rules: {}".format(psp_rules))
|
||||
|
||||
|
||||
# Run falco
|
||||
cmd = '{} {} {} -c {} {} -o json_output={} -o json_include_output_property={} -o priority={} -v'.format(
|
||||
self.falco_binary_path, self.rules_args, self.disabled_args, self.conf_file, trace_arg, self.json_output, self.json_include_output_property, self.priority)
|
||||
@@ -643,26 +557,22 @@ class FalcoTest(Test):
|
||||
for pattern in self.stderr_contains:
|
||||
match = re.search(pattern, res.stderr.decode("utf-8"))
|
||||
if match is None:
|
||||
self.fail(
|
||||
"Stderr of falco process did not contain content matching {}".format(pattern))
|
||||
self.fail("Stderr of falco process did not contain content matching {}".format(pattern))
|
||||
|
||||
for pattern in self.stdout_contains:
|
||||
match = re.search(pattern, res.stdout.decode("utf-8"))
|
||||
if match is None:
|
||||
self.fail("Stdout of falco process '{}' did not contain content matching {}".format(
|
||||
res.stdout.decode("utf-8"), pattern))
|
||||
self.fail("Stdout of falco process '{}' did not contain content matching {}".format(res.stdout.decode("utf-8"), pattern))
|
||||
|
||||
for pattern in self.stderr_not_contains:
|
||||
match = re.search(pattern, res.stderr.decode("utf-8"))
|
||||
if match is not None:
|
||||
self.fail(
|
||||
"Stderr of falco process contained content matching {} when it should have not".format(pattern))
|
||||
self.fail("Stderr of falco process contained content matching {} when it should have not".format(pattern))
|
||||
|
||||
for pattern in self.stdout_not_contains:
|
||||
match = re.search(pattern, res.stdout.decode("utf-8"))
|
||||
if match is not None:
|
||||
self.fail("Stdout of falco process '{}' did contain content matching {} when it should have not".format(
|
||||
res.stdout.decode("utf-8"), pattern))
|
||||
self.fail("Stdout of falco process '{}' did contain content matching {} when it should have not".format(res.stdout.decode("utf-8"), pattern))
|
||||
|
||||
if res.exit_status != self.exit_status:
|
||||
self.error("Falco command \"{}\" exited with unexpected return value {} (!= {})".format(
|
||||
@@ -675,12 +585,12 @@ class FalcoTest(Test):
|
||||
self.check_rules_warnings(res)
|
||||
if len(self.rules_events) > 0:
|
||||
self.check_rules_events(res)
|
||||
self.check_detections(res)
|
||||
if len(self.validate_rules_file) == 0:
|
||||
self.check_detections(res)
|
||||
if len(self.detect_counts) > 0:
|
||||
self.check_detections_by_rule(res)
|
||||
self.check_json_output(res)
|
||||
self.check_outputs()
|
||||
self.check_output_strictly_contains(res)
|
||||
self.check_grpc()
|
||||
pass
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
# Copyright (C) 2016-2018 The Falco Authors..
|
||||
#
|
||||
# This file is part of falco.
|
||||
#
|
||||
@@ -262,6 +262,7 @@ trace_files: !mux
|
||||
invalid_not_yaml:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
Rules content is not yaml
|
||||
---
|
||||
This is not yaml
|
||||
@@ -273,6 +274,7 @@ trace_files: !mux
|
||||
invalid_not_array:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
Rules content is not yaml array of objects
|
||||
---
|
||||
foo: bar
|
||||
@@ -284,6 +286,7 @@ trace_files: !mux
|
||||
invalid_array_item_not_object:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
Unexpected element of type string. Each element should be a yaml associative array.
|
||||
---
|
||||
- foo
|
||||
@@ -295,6 +298,7 @@ trace_files: !mux
|
||||
invalid_unexpected object:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
Unknown rule object: {foo="bar"}
|
||||
---
|
||||
- foo: bar
|
||||
@@ -306,6 +310,7 @@ trace_files: !mux
|
||||
invalid_engine_version_not_number:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
Value of required_engine_version must be a number
|
||||
---
|
||||
- required_engine_version: not-a-number
|
||||
@@ -317,6 +322,7 @@ trace_files: !mux
|
||||
invalid_yaml_parse_error:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
mapping values are not allowed in this context
|
||||
---
|
||||
this : is : not : yaml
|
||||
@@ -328,6 +334,7 @@ trace_files: !mux
|
||||
invalid_list_without_items:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
List must have property items
|
||||
---
|
||||
- list: bad_list
|
||||
@@ -340,6 +347,7 @@ trace_files: !mux
|
||||
invalid_macro_without_condition:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
Macro must have property condition
|
||||
---
|
||||
- macro: bad_macro
|
||||
@@ -352,6 +360,7 @@ trace_files: !mux
|
||||
invalid_rule_without_output:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
Rule must have property output
|
||||
---
|
||||
- rule: no output rule
|
||||
@@ -366,6 +375,7 @@ trace_files: !mux
|
||||
invalid_append_rule_without_condition:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
Rule must have property condition
|
||||
---
|
||||
- rule: no condition rule
|
||||
@@ -378,6 +388,7 @@ trace_files: !mux
|
||||
invalid_append_macro_dangling:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
Macro dangling append has 'append' key but no macro by that name already exists
|
||||
---
|
||||
- macro: dangling append
|
||||
@@ -391,6 +402,7 @@ trace_files: !mux
|
||||
invalid_list_append_dangling:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
List my_list has 'append' key but no list by that name already exists
|
||||
---
|
||||
- list: my_list
|
||||
@@ -404,6 +416,7 @@ trace_files: !mux
|
||||
invalid_rule_append_dangling:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
Rule my_rule has 'append' key but no rule by that name already exists
|
||||
---
|
||||
- rule: my_rule
|
||||
@@ -450,6 +463,7 @@ trace_files: !mux
|
||||
invalid_overwrite_macro_multiple_docs:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
Compilation error when compiling "foo": Undefined macro 'foo' used in filter.
|
||||
---
|
||||
- macro: some macro
|
||||
@@ -463,6 +477,7 @@ trace_files: !mux
|
||||
invalid_append_macro_multiple_docs:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
Compilation error when compiling "evt.type=execve foo": 17: syntax error, unexpected 'foo', expecting 'or', 'and'
|
||||
---
|
||||
- macro: some macro
|
||||
@@ -521,6 +536,7 @@ trace_files: !mux
|
||||
invalid_overwrite_rule_multiple_docs:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
Undefined macro 'bar' used in filter.
|
||||
---
|
||||
- rule: some rule
|
||||
@@ -559,6 +575,7 @@ trace_files: !mux
|
||||
invalid_missing_rule_name:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
Rule name is empty
|
||||
---
|
||||
- rule:
|
||||
@@ -573,6 +590,7 @@ trace_files: !mux
|
||||
invalid_missing_list_name:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
List name is empty
|
||||
---
|
||||
- list:
|
||||
@@ -585,6 +603,7 @@ trace_files: !mux
|
||||
invalid_missing_macro_name:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
Macro name is empty
|
||||
---
|
||||
- macro:
|
||||
@@ -652,50 +671,25 @@ trace_files: !mux
|
||||
trace_file: trace_files/cat_write.scap
|
||||
stdout_contains: "Warning An open was seen .cport=<NA> command=cat /dev/null."
|
||||
|
||||
stdout_output_strict:
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/single_rule.yaml
|
||||
conf_file: confs/stdout_output.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
time_iso_8601: true
|
||||
output_strictly_contains:
|
||||
- stdout: output_files/single_rule_with_cat_write.txt
|
||||
|
||||
stdout_output_json_strict:
|
||||
json_output: True
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/single_rule.yaml
|
||||
conf_file: confs/stdout_output.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
time_iso_8601: true
|
||||
output_strictly_contains:
|
||||
- stdout: output_files/single_rule_with_cat_write.json
|
||||
|
||||
file_output_strict:
|
||||
file_output:
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/single_rule.yaml
|
||||
conf_file: confs/file_output.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
time_iso_8601: true
|
||||
output_strictly_contains:
|
||||
- /tmp/falco_outputs/file_output.txt: output_files/single_rule_with_cat_write.txt
|
||||
outputs:
|
||||
- /tmp/falco_outputs/file_output.txt: Warning An open was seen
|
||||
|
||||
program_output_strict:
|
||||
program_output:
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/single_rule.yaml
|
||||
conf_file: confs/program_output.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
time_iso_8601: true
|
||||
output_strictly_contains:
|
||||
- /tmp/falco_outputs/program_output.txt: output_files/single_rule_with_cat_write.txt
|
||||
outputs:
|
||||
- /tmp/falco_outputs/program_output.txt: Warning An open was seen
|
||||
|
||||
grpc_unix_socket_outputs:
|
||||
detect: True
|
||||
@@ -705,26 +699,13 @@ trace_files: !mux
|
||||
conf_file: confs/grpc_unix_socket.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
run_duration: 5
|
||||
time_iso_8601: true
|
||||
grpc:
|
||||
address: unix:///tmp/falco/falco.sock
|
||||
proto: outputs.proto
|
||||
service: falco.outputs.service
|
||||
method: get
|
||||
# protobuf text format
|
||||
results:
|
||||
- "seconds:1470327477 nanos:881781397"
|
||||
- "priority: WARNING"
|
||||
- "rule: \"open_from_cat\""
|
||||
- "output: \"2016-08-04T16:17:57.881781397+0000: Warning An open was seen (command=cat /dev/null)\""
|
||||
# output fields
|
||||
- "key: \"evt.time.iso8601\""
|
||||
- "value: \"2016-08-04T16:17:57.881781397+0000\""
|
||||
- "key: \"proc.cmdline\""
|
||||
- "value: \"cat /dev/null\""
|
||||
# For the hostname, since we don't know that beforehand,
|
||||
# only check the field presence
|
||||
- "hostname: "
|
||||
- "Warning An open was seen"
|
||||
|
||||
detect_counts:
|
||||
detect: True
|
||||
|
||||
323
test/falco_tests_exceptions.yaml
Normal file
323
test/falco_tests_exceptions.yaml
Normal file
@@ -0,0 +1,323 @@
|
||||
#
|
||||
# Copyright (C) 2016-2020 The Falco Authors..
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
trace_files: !mux
|
||||
|
||||
rule_exception_no_fields:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
Rule exception item ex1: must have fields property with a list of fields
|
||||
---
|
||||
- rule: My Rule
|
||||
desc: Some desc
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: Some output
|
||||
exceptions:
|
||||
- name: ex1
|
||||
priority: error
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/exceptions/item_no_fields.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_no_name:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
Rule exception item must have name property
|
||||
---
|
||||
- rule: My Rule
|
||||
desc: Some desc
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: Some output
|
||||
exceptions:
|
||||
- fields: [proc.name, fd.filename]
|
||||
priority: error
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/exceptions/item_no_name.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_append_no_name:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
Rule exception item must have name property
|
||||
---
|
||||
- rule: My Rule
|
||||
exceptions:
|
||||
- values:
|
||||
- [nginx, /tmp/foo]
|
||||
append: true
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/exceptions/append_item_no_name.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_unknown_fields:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
Rule exception item ex1: field name not.exist is not a supported filter field
|
||||
---
|
||||
- rule: My Rule
|
||||
desc: Some desc
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: Some output
|
||||
exceptions:
|
||||
- name: ex1
|
||||
fields: [not.exist]
|
||||
priority: error
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/exceptions/item_unknown_fields.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_comps_fields_len_mismatch:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
Rule exception item ex1: fields and comps lists must have equal length
|
||||
---
|
||||
- rule: My Rule
|
||||
desc: Some desc
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: Some output
|
||||
exceptions:
|
||||
- name: ex1
|
||||
fields: [proc.name, fd.filename]
|
||||
comps: [=]
|
||||
priority: error
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/exceptions/item_comps_fields_len_mismatch.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_unknown_comp:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
Rule exception item ex1: comparison operator no-comp is not a supported comparison operator
|
||||
---
|
||||
- rule: My Rule
|
||||
desc: Some desc
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: Some output
|
||||
exceptions:
|
||||
- name: ex1
|
||||
fields: [proc.name, fd.filename]
|
||||
comps: [=, no-comp]
|
||||
priority: error
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/exceptions/item_unknown_comp.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_fields_values_len_mismatch:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
Exception item ex1: fields and values lists must have equal length
|
||||
---
|
||||
- rule: My Rule
|
||||
desc: Some desc
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: Some output
|
||||
exceptions:
|
||||
- name: ex1
|
||||
fields: [proc.name, fd.filename]
|
||||
values:
|
||||
- [nginx]
|
||||
priority: error
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/exceptions/item_fields_values_len_mismatch.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_append_fields_values_len_mismatch:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
Exception item ex1: fields and values lists must have equal length
|
||||
---
|
||||
- rule: My Rule
|
||||
desc: Some desc
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: Some output
|
||||
exceptions:
|
||||
- name: ex1
|
||||
fields: [proc.name, fd.filename]
|
||||
priority: error
|
||||
|
||||
- rule: My Rule
|
||||
exceptions:
|
||||
- name: ex1
|
||||
values:
|
||||
- [nginx]
|
||||
append: true
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/exceptions/append_item_fields_values_len_mismatch.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_append_item_not_in_rule:
|
||||
exit_status: 0
|
||||
stderr_contains: |+
|
||||
1 warnings:
|
||||
Rule My Rule with append=true: no set of fields matching name ex2
|
||||
validate_rules_file:
|
||||
- rules/exceptions/append_item_not_in_rule.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_without_exception:
|
||||
exit_status: 0
|
||||
stderr_contains: |+
|
||||
1 warnings:
|
||||
Rule My Rule: consider adding an exceptions property to define supported exceptions fields
|
||||
validate_rules_file:
|
||||
- rules/exceptions/rule_without_exception.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_no_values:
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/exceptions/rule_exception_no_values.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_one_value:
|
||||
detect: False
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/exceptions/rule_exception_one_value.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_append_one_value:
|
||||
detect: False
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/exceptions/rule_exception_append_one_value.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_second_value:
|
||||
detect: False
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/exceptions/rule_exception_second_value.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_append_second_value:
|
||||
detect: False
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/exceptions/rule_exception_append_second_value.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_second_item:
|
||||
detect: False
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/exceptions/rule_exception_second_item.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_append_second_item:
|
||||
detect: False
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/exceptions/rule_exception_append_second_item.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_third_item:
|
||||
detect: False
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/exceptions/rule_exception_third_item.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_append_third_item:
|
||||
detect: False
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/exceptions/rule_exception_append_third_item.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_quoted:
|
||||
detect: False
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/exceptions/rule_exception_quoted.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_append_multiple_values:
|
||||
detect: False
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/exceptions/rule_exception_append_multiple.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_comp:
|
||||
detect: False
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/exceptions/rule_exception_comp.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_append_comp:
|
||||
detect: False
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/exceptions/rule_exception_append_comp.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_values_listref:
|
||||
detect: False
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/exceptions/rule_exception_values_listref.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_values_listref_noparens:
|
||||
detect: False
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/exceptions/rule_exception_values_listref_noparens.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_values_list:
|
||||
detect: False
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/exceptions/rule_exception_values_list.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_single_field:
|
||||
detect: False
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/exceptions/rule_exception_single_field.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_single_field_append:
|
||||
detect: False
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/exceptions/rule_exception_single_field_append.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
{"output":"2016-08-04T16:17:57.881781397+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.881781397Z", "output_fields": {"evt.time.iso8601":1470327477881781397,"proc.cmdline":"cat /dev/null"}}
|
||||
{"output":"2016-08-04T16:17:57.881785348+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.881785348Z", "output_fields": {"evt.time.iso8601":1470327477881785348,"proc.cmdline":"cat /dev/null"}}
|
||||
{"output":"2016-08-04T16:17:57.881796705+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.881796705Z", "output_fields": {"evt.time.iso8601":1470327477881796705,"proc.cmdline":"cat /dev/null"}}
|
||||
{"output":"2016-08-04T16:17:57.881799840+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.881799840Z", "output_fields": {"evt.time.iso8601":1470327477881799840,"proc.cmdline":"cat /dev/null"}}
|
||||
{"output":"2016-08-04T16:17:57.882003104+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.882003104Z", "output_fields": {"evt.time.iso8601":1470327477882003104,"proc.cmdline":"cat /dev/null"}}
|
||||
{"output":"2016-08-04T16:17:57.882008208+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.882008208Z", "output_fields": {"evt.time.iso8601":1470327477882008208,"proc.cmdline":"cat /dev/null"}}
|
||||
{"output":"2016-08-04T16:17:57.882045694+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.882045694Z", "output_fields": {"evt.time.iso8601":1470327477882045694,"proc.cmdline":"cat /dev/null"}}
|
||||
{"output":"2016-08-04T16:17:57.882054739+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.882054739Z", "output_fields": {"evt.time.iso8601":1470327477882054739,"proc.cmdline":"cat /dev/null"}}
|
||||
@@ -1,8 +0,0 @@
|
||||
2016-08-04T16:17:57.881781397+0000: Warning An open was seen (command=cat /dev/null)
|
||||
2016-08-04T16:17:57.881785348+0000: Warning An open was seen (command=cat /dev/null)
|
||||
2016-08-04T16:17:57.881796705+0000: Warning An open was seen (command=cat /dev/null)
|
||||
2016-08-04T16:17:57.881799840+0000: Warning An open was seen (command=cat /dev/null)
|
||||
2016-08-04T16:17:57.882003104+0000: Warning An open was seen (command=cat /dev/null)
|
||||
2016-08-04T16:17:57.882008208+0000: Warning An open was seen (command=cat /dev/null)
|
||||
2016-08-04T16:17:57.882045694+0000: Warning An open was seen (command=cat /dev/null)
|
||||
2016-08-04T16:17:57.882054739+0000: Warning An open was seen (command=cat /dev/null)
|
||||
@@ -0,0 +1,31 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
- rule: My Rule
|
||||
desc: Some desc
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: Some output
|
||||
exceptions:
|
||||
- name: ex1
|
||||
fields: [proc.name, fd.filename]
|
||||
priority: error
|
||||
|
||||
- rule: My Rule
|
||||
exceptions:
|
||||
- name: ex1
|
||||
values:
|
||||
- [nginx]
|
||||
append: true
|
||||
30
test/rules/exceptions/append_item_no_name.yaml
Normal file
30
test/rules/exceptions/append_item_no_name.yaml
Normal file
@@ -0,0 +1,30 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
- rule: My Rule
|
||||
desc: Some desc
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: Some output
|
||||
exceptions:
|
||||
- name: ex1
|
||||
fields: [proc.name, fd.filename]
|
||||
priority: error
|
||||
|
||||
- rule: My Rule
|
||||
exceptions:
|
||||
- values:
|
||||
- [nginx, /tmp/foo]
|
||||
append: true
|
||||
31
test/rules/exceptions/append_item_not_in_rule.yaml
Normal file
31
test/rules/exceptions/append_item_not_in_rule.yaml
Normal file
@@ -0,0 +1,31 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
- rule: My Rule
|
||||
desc: Some desc
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: Some output
|
||||
exceptions:
|
||||
- name: ex1
|
||||
fields: [proc.name, fd.filename]
|
||||
priority: error
|
||||
|
||||
- rule: My Rule
|
||||
exceptions:
|
||||
- name: ex2
|
||||
values:
|
||||
- [apache, /tmp]
|
||||
append: true
|
||||
25
test/rules/exceptions/item_comps_fields_len_mismatch.yaml
Normal file
25
test/rules/exceptions/item_comps_fields_len_mismatch.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
- rule: My Rule
|
||||
desc: Some desc
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: Some output
|
||||
exceptions:
|
||||
- name: ex1
|
||||
fields: [proc.name, fd.filename]
|
||||
comps: [=]
|
||||
priority: error
|
||||
26
test/rules/exceptions/item_fields_values_len_mismatch.yaml
Normal file
26
test/rules/exceptions/item_fields_values_len_mismatch.yaml
Normal file
@@ -0,0 +1,26 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
- rule: My Rule
|
||||
desc: Some desc
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: Some output
|
||||
exceptions:
|
||||
- name: ex1
|
||||
fields: [proc.name, fd.filename]
|
||||
values:
|
||||
- [nginx]
|
||||
priority: error
|
||||
23
test/rules/exceptions/item_no_fields.yaml
Normal file
23
test/rules/exceptions/item_no_fields.yaml
Normal file
@@ -0,0 +1,23 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
- rule: My Rule
|
||||
desc: Some desc
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: Some output
|
||||
exceptions:
|
||||
- name: ex1
|
||||
priority: error
|
||||
23
test/rules/exceptions/item_no_name.yaml
Normal file
23
test/rules/exceptions/item_no_name.yaml
Normal file
@@ -0,0 +1,23 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
- rule: My Rule
|
||||
desc: Some desc
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: Some output
|
||||
exceptions:
|
||||
- fields: [proc.name, fd.filename]
|
||||
priority: error
|
||||
25
test/rules/exceptions/item_unknown_comp.yaml
Normal file
25
test/rules/exceptions/item_unknown_comp.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
- rule: My Rule
|
||||
desc: Some desc
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: Some output
|
||||
exceptions:
|
||||
- name: ex1
|
||||
fields: [proc.name, fd.filename]
|
||||
comps: [=, no-comp]
|
||||
priority: error
|
||||
24
test/rules/exceptions/item_unknown_fields.yaml
Normal file
24
test/rules/exceptions/item_unknown_fields.yaml
Normal file
@@ -0,0 +1,24 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
- rule: My Rule
|
||||
desc: Some desc
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: Some output
|
||||
exceptions:
|
||||
- name: ex1
|
||||
fields: [not.exist]
|
||||
priority: error
|
||||
38
test/rules/exceptions/rule_exception_append_comp.yaml
Normal file
38
test/rules/exceptions/rule_exception_append_comp.yaml
Normal file
@@ -0,0 +1,38 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
- rule: Open From Cat
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: "An open was seen (command=%proc.cmdline)"
|
||||
exceptions:
|
||||
- name: proc_name
|
||||
fields: [proc.name]
|
||||
- name: proc_name_contains
|
||||
fields: [proc.name]
|
||||
comps: [contains]
|
||||
- name: proc_name_cmdline
|
||||
fields: [proc.name, proc.cmdline]
|
||||
- name: proc_name_cmdline_pname
|
||||
fields: [proc.name, proc.cmdline, proc.pname]
|
||||
priority: WARNING
|
||||
|
||||
- rule: Open From Cat
|
||||
exceptions:
|
||||
- name: proc_name_contains
|
||||
values:
|
||||
- [cat]
|
||||
append: true
|
||||
42
test/rules/exceptions/rule_exception_append_multiple.yaml
Normal file
42
test/rules/exceptions/rule_exception_append_multiple.yaml
Normal file
@@ -0,0 +1,42 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
- rule: Open From Cat
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: "An open was seen (command=%proc.cmdline)"
|
||||
exceptions:
|
||||
- name: proc_name
|
||||
fields: [proc.name]
|
||||
- name: proc_name_cmdline
|
||||
fields: [proc.name, proc.cmdline]
|
||||
- name: proc_name_cmdline_pname
|
||||
fields: [proc.name, proc.cmdline, proc.pname]
|
||||
priority: WARNING
|
||||
|
||||
- rule: Open From Cat
|
||||
exceptions:
|
||||
- name: proc_name
|
||||
values:
|
||||
- [not-cat]
|
||||
append: true
|
||||
|
||||
- rule: Open From Cat
|
||||
exceptions:
|
||||
- name: proc_name
|
||||
values:
|
||||
- [cat]
|
||||
append: true
|
||||
37
test/rules/exceptions/rule_exception_append_one_value.yaml
Normal file
37
test/rules/exceptions/rule_exception_append_one_value.yaml
Normal file
@@ -0,0 +1,37 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
- rule: Open From Cat
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: "An open was seen (command=%proc.cmdline)"
|
||||
exceptions:
|
||||
- name: proc_name
|
||||
fields: [proc.name]
|
||||
values:
|
||||
- [cat]
|
||||
- name: proc_name_cmdline
|
||||
fields: [proc.name, proc.cmdline]
|
||||
- name: proc_name_cmdline_pname
|
||||
fields: [proc.name, proc.cmdline, proc.pname]
|
||||
priority: WARNING
|
||||
|
||||
- rule: Open From Cat
|
||||
exceptions:
|
||||
- name: proc_name
|
||||
values:
|
||||
- [cat]
|
||||
append: true
|
||||
41
test/rules/exceptions/rule_exception_append_second_item.yaml
Normal file
41
test/rules/exceptions/rule_exception_append_second_item.yaml
Normal file
@@ -0,0 +1,41 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
- rule: Open From Cat
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: "An open was seen (command=%proc.cmdline)"
|
||||
exceptions:
|
||||
- name: proc_name
|
||||
fields: [proc.name]
|
||||
- name: proc_name_cmdline
|
||||
fields: [proc.name, proc.cmdline]
|
||||
- name: proc_name_cmdline_pname
|
||||
fields: [proc.name, proc.cmdline, proc.pname]
|
||||
priority: WARNING
|
||||
|
||||
- rule: Open From Cat
|
||||
exceptions:
|
||||
- name: proc_name
|
||||
values:
|
||||
- [not-cat]
|
||||
- name: proc_name_cmdline
|
||||
values:
|
||||
- [cat, "cat /dev/null"]
|
||||
- name: proc_name_cmdline_pname
|
||||
values:
|
||||
- [not-cat, "cat /dev/null", bash]
|
||||
append: true
|
||||
@@ -0,0 +1,36 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
- rule: Open From Cat
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: "An open was seen (command=%proc.cmdline)"
|
||||
exceptions:
|
||||
- name: proc_name
|
||||
fields: [proc.name]
|
||||
- name: proc_name_cmdline
|
||||
fields: [proc.name, proc.cmdline]
|
||||
- name: proc_name_cmdline_pname
|
||||
fields: [proc.name, proc.cmdline, proc.pname]
|
||||
priority: WARNING
|
||||
|
||||
- rule: Open From Cat
|
||||
exceptions:
|
||||
- name: proc_name_cmdline
|
||||
values:
|
||||
- [not-cat, not-cat]
|
||||
- [cat, "cat /dev/null"]
|
||||
append: true
|
||||
41
test/rules/exceptions/rule_exception_append_third_item.yaml
Normal file
41
test/rules/exceptions/rule_exception_append_third_item.yaml
Normal file
@@ -0,0 +1,41 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
- rule: Open From Cat
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: "An open was seen (command=%proc.cmdline)"
|
||||
exceptions:
|
||||
- name: proc_name
|
||||
fields: [proc.name]
|
||||
- name: proc_name_cmdline
|
||||
fields: [proc.name, proc.cmdline]
|
||||
- name: proc_name_cmdline_pname
|
||||
fields: [proc.name, proc.cmdline, proc.pname]
|
||||
priority: WARNING
|
||||
|
||||
- rule: Open From Cat
|
||||
exceptions:
|
||||
- name: proc_name
|
||||
values:
|
||||
- [not-cat]
|
||||
- name: proc_name_cmdline
|
||||
values:
|
||||
- [not-cat, "cat /dev/null"]
|
||||
- name: proc_name_cmdline_pname
|
||||
values:
|
||||
- [cat, "cat /dev/null", bash]
|
||||
append: true
|
||||
34
test/rules/exceptions/rule_exception_comp.yaml
Normal file
34
test/rules/exceptions/rule_exception_comp.yaml
Normal file
@@ -0,0 +1,34 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
- rule: Open From Cat
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: "An open was seen (command=%proc.cmdline)"
|
||||
exceptions:
|
||||
- name: proc_name
|
||||
fields: [proc.name]
|
||||
- name: proc_name_contains
|
||||
fields: [proc.name]
|
||||
comps: [contains]
|
||||
values:
|
||||
- [cat]
|
||||
- name: proc_name_cmdline
|
||||
fields: [proc.name, proc.cmdline]
|
||||
- name: proc_name_cmdline_pname
|
||||
fields: [proc.name, proc.cmdline, proc.pname]
|
||||
priority: WARNING
|
||||
|
||||
28
test/rules/exceptions/rule_exception_no_values.yaml
Normal file
28
test/rules/exceptions/rule_exception_no_values.yaml
Normal file
@@ -0,0 +1,28 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
- rule: Open From Cat
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: "An open was seen (command=%proc.cmdline)"
|
||||
exceptions:
|
||||
- name: proc_name
|
||||
fields: [proc.name]
|
||||
- name: proc_name_cmdline
|
||||
fields: [proc.name, proc.cmdline]
|
||||
- name: proc_name_cmdline_pname
|
||||
fields: [proc.name, proc.cmdline, proc.pname]
|
||||
priority: WARNING
|
||||
30
test/rules/exceptions/rule_exception_one_value.yaml
Normal file
30
test/rules/exceptions/rule_exception_one_value.yaml
Normal file
@@ -0,0 +1,30 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
- rule: Open From Cat
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: "An open was seen (command=%proc.cmdline)"
|
||||
exceptions:
|
||||
- name: proc_name
|
||||
fields: [proc.name]
|
||||
values:
|
||||
- [cat]
|
||||
- name: proc_name_cmdline
|
||||
fields: [proc.name, proc.cmdline]
|
||||
- name: proc_name_cmdline_pname
|
||||
fields: [proc.name, proc.cmdline, proc.pname]
|
||||
priority: WARNING
|
||||
36
test/rules/exceptions/rule_exception_quoted.yaml
Normal file
36
test/rules/exceptions/rule_exception_quoted.yaml
Normal file
@@ -0,0 +1,36 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
- rule: Open From Cat
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: "An open was seen (command=%proc.cmdline)"
|
||||
exceptions:
|
||||
- name: proc_name
|
||||
fields: [proc.name]
|
||||
- name: proc_name_cmdline
|
||||
fields: [proc.name, proc.cmdline]
|
||||
- name: proc_name_cmdline_pname
|
||||
fields: [proc.name, proc.cmdline, proc.pname]
|
||||
priority: WARNING
|
||||
|
||||
- rule: Open From Cat
|
||||
exceptions:
|
||||
- name: proc_name_cmdline
|
||||
values:
|
||||
- [not-cat, not-cat]
|
||||
- [cat, '"cat /dev/null"']
|
||||
append: true
|
||||
34
test/rules/exceptions/rule_exception_second_item.yaml
Normal file
34
test/rules/exceptions/rule_exception_second_item.yaml
Normal file
@@ -0,0 +1,34 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
- rule: Open From Cat
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: "An open was seen (command=%proc.cmdline)"
|
||||
exceptions:
|
||||
- name: proc_name
|
||||
fields: [proc.name]
|
||||
values:
|
||||
- [not-cat]
|
||||
- name: proc_name_cmdline
|
||||
fields: [proc.name, proc.cmdline]
|
||||
values:
|
||||
- [cat, "cat /dev/null"]
|
||||
- name: proc_name_cmdline_pname
|
||||
fields: [proc.name, proc.cmdline, proc.pname]
|
||||
values:
|
||||
- [not-cat, "cat /dev/null", bash]
|
||||
priority: WARNING
|
||||
32
test/rules/exceptions/rule_exception_second_value.yaml
Normal file
32
test/rules/exceptions/rule_exception_second_value.yaml
Normal file
@@ -0,0 +1,32 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
- rule: Open From Cat
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: "An open was seen (command=%proc.cmdline)"
|
||||
exceptions:
|
||||
- name: proc_name
|
||||
fields: [proc.name]
|
||||
- name: proc_name_cmdline
|
||||
fields: [proc.name, proc.cmdline]
|
||||
values:
|
||||
- [not-cat, not-cat]
|
||||
- [cat, "cat /dev/null"]
|
||||
- name: proc_name_cmdline_pname
|
||||
fields: [proc.name, proc.cmdline, proc.pname]
|
||||
priority: WARNING
|
||||
|
||||
30
test/rules/exceptions/rule_exception_single_field.yaml
Normal file
30
test/rules/exceptions/rule_exception_single_field.yaml
Normal file
@@ -0,0 +1,30 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
- rule: Open From Cat
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: "An open was seen (command=%proc.cmdline)"
|
||||
exceptions:
|
||||
- name: proc_cmdline
|
||||
fields: proc.cmdline
|
||||
comps: in
|
||||
values:
|
||||
- cat /dev/zero
|
||||
- "cat /dev/null"
|
||||
priority: WARNING
|
||||
|
||||
@@ -15,28 +15,23 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
# File containing Falco rules, loaded at startup.
|
||||
rules_file: /etc/falco_rules.yaml
|
||||
- rule: Open From Cat
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: "An open was seen (command=%proc.cmdline)"
|
||||
exceptions:
|
||||
- name: proc_cmdline
|
||||
fields: proc.cmdline
|
||||
comps: in
|
||||
values:
|
||||
- cat /dev/zero
|
||||
priority: WARNING
|
||||
|
||||
# Whether to output events in json or text
|
||||
json_output: false
|
||||
- rule: Open From Cat
|
||||
exceptions:
|
||||
- name: proc_cmdline
|
||||
values:
|
||||
- "cat /dev/null"
|
||||
append: true
|
||||
|
||||
# Send information logs to stderr and/or syslog Note these are *not* security
|
||||
# notification logs! These are just Falco lifecycle (and possibly error) logs.
|
||||
log_stderr: false
|
||||
log_syslog: false
|
||||
|
||||
# Where security notifications should go.
|
||||
# Multiple outputs can be enabled.
|
||||
|
||||
syslog_output:
|
||||
enabled: false
|
||||
|
||||
file_output:
|
||||
enabled: false
|
||||
|
||||
stdout_output:
|
||||
enabled: true
|
||||
|
||||
program_output:
|
||||
enabled: false
|
||||
34
test/rules/exceptions/rule_exception_third_item.yaml
Normal file
34
test/rules/exceptions/rule_exception_third_item.yaml
Normal file
@@ -0,0 +1,34 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
- rule: Open From Cat
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: "An open was seen (command=%proc.cmdline)"
|
||||
exceptions:
|
||||
- name: proc_name
|
||||
fields: [proc.name]
|
||||
values:
|
||||
- [not-cat]
|
||||
- name: proc_name_cmdline
|
||||
fields: [proc.name, proc.cmdline]
|
||||
values:
|
||||
- [not-cat, "cat /dev/null"]
|
||||
- name: proc_name_cmdline_pname
|
||||
fields: [proc.name, proc.cmdline, proc.pname]
|
||||
values:
|
||||
- [cat, "cat /dev/null", bash]
|
||||
priority: WARNING
|
||||
29
test/rules/exceptions/rule_exception_values_list.yaml
Normal file
29
test/rules/exceptions/rule_exception_values_list.yaml
Normal file
@@ -0,0 +1,29 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
- rule: Open From Cat
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: "An open was seen (command=%proc.cmdline)"
|
||||
exceptions:
|
||||
- name: proc_name_cmdline
|
||||
fields: [proc.name, proc.cmdline]
|
||||
comps: [=, in]
|
||||
values:
|
||||
- [cat, [cat /dev/zero, "cat /dev/null"]]
|
||||
priority: WARNING
|
||||
|
||||
32
test/rules/exceptions/rule_exception_values_listref.yaml
Normal file
32
test/rules/exceptions/rule_exception_values_listref.yaml
Normal file
@@ -0,0 +1,32 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
- list: cat_cmdlines
|
||||
items: [cat /dev/zero, "cat /dev/null"]
|
||||
|
||||
- rule: Open From Cat
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: "An open was seen (command=%proc.cmdline)"
|
||||
exceptions:
|
||||
- name: proc_name_cmdline
|
||||
fields: [proc.name, proc.cmdline]
|
||||
comps: [=, in]
|
||||
values:
|
||||
- [cat, (cat_cmdlines)]
|
||||
priority: WARNING
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
- list: cat_cmdlines
|
||||
items: [cat /dev/zero, "cat /dev/null"]
|
||||
|
||||
- rule: Open From Cat
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: "An open was seen (command=%proc.cmdline)"
|
||||
exceptions:
|
||||
- name: proc_name_cmdline
|
||||
fields: [proc.name, proc.cmdline]
|
||||
comps: [=, in]
|
||||
values:
|
||||
- [cat, cat_cmdlines]
|
||||
priority: WARNING
|
||||
|
||||
21
test/rules/exceptions/rule_without_exception.yaml
Normal file
21
test/rules/exceptions/rule_without_exception.yaml
Normal file
@@ -0,0 +1,21 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
- rule: My Rule
|
||||
desc: Some desc
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: Some output
|
||||
priority: error
|
||||
@@ -98,18 +98,14 @@ function run_tests() {
|
||||
# as we're watching the return status when running avocado.
|
||||
set +e
|
||||
TEST_RC=0
|
||||
suites=($SCRIPTDIR/falco_traces.yaml $SCRIPTDIR/falco_tests.yaml $SCRIPTDIR/falco_k8s_audit_tests.yaml $SCRIPTDIR/falco_tests_psp.yaml)
|
||||
suites=($SCRIPTDIR/falco_traces.yaml $SCRIPTDIR/falco_tests.yaml $SCRIPTDIR/falco_k8s_audit_tests.yaml $SCRIPTDIR/falco_tests_psp.yaml $SCRIPTDIR/falco_tests_exceptions.yaml)
|
||||
|
||||
if [ "$SKIP_PACKAGES_TESTS" = false ] ; then
|
||||
suites+=($SCRIPTDIR/falco_tests_package.yaml)
|
||||
fi
|
||||
|
||||
XUNIT_DIR="${OPT_BUILD_DIR}/integration-tests-xunit"
|
||||
mkdir -p "${XUNIT_DIR}"
|
||||
|
||||
for mult in "${suites[@]}"; do
|
||||
XUNIT_FILE_NAME="${XUNIT_DIR}/$(basename "${mult}").xml"
|
||||
CMD="avocado run --xunit ${XUNIT_FILE_NAME} --mux-yaml $mult --job-results-dir $SCRIPTDIR/job-results -- $SCRIPTDIR/falco_test.py"
|
||||
CMD="avocado run --mux-yaml $mult --job-results-dir $SCRIPTDIR/job-results -- $SCRIPTDIR/falco_test.py"
|
||||
echo "Running $CMD"
|
||||
BUILD_DIR=${OPT_BUILD_DIR} $CMD
|
||||
RC=$?
|
||||
|
||||
@@ -171,8 +171,9 @@ void falco_engine::load_rules(const string &rules_content, bool verbose, bool al
|
||||
m_ls);
|
||||
}
|
||||
|
||||
// Note that falco_formats is added to the lua state used
|
||||
// by the falco engine only. Within the engine, only
|
||||
// Note that falco_formats is added to both the lua state used
|
||||
// by the falco engine as well as the separate lua state used
|
||||
// by falco outputs. Within the engine, only
|
||||
// formats.formatter is used, so we can unconditionally set
|
||||
// json_output to false.
|
||||
bool json_output = false;
|
||||
|
||||
@@ -16,7 +16,7 @@ limitations under the License.
|
||||
|
||||
// The version of rules/filter fields/etc supported by this falco
|
||||
// engine.
|
||||
#define FALCO_ENGINE_VERSION (7)
|
||||
#define FALCO_ENGINE_VERSION (8)
|
||||
|
||||
// This is the result of running "falco --list -N | sha256sum" and
|
||||
// represents the fields supported by this version of falco. It's used
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors.
|
||||
Copyright (C) 2019 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -20,19 +20,24 @@ limitations under the License.
|
||||
#include "falco_engine.h"
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
sinsp *falco_formats::s_inspector = NULL;
|
||||
|
||||
sinsp* falco_formats::s_inspector = NULL;
|
||||
falco_engine *falco_formats::s_engine = NULL;
|
||||
bool falco_formats::s_json_output = false;
|
||||
bool falco_formats::s_json_include_output_property = true;
|
||||
std::unique_ptr<sinsp_evt_formatter_cache> falco_formats::s_formatters = NULL;
|
||||
sinsp_evt_formatter_cache *falco_formats::s_formatters = NULL;
|
||||
|
||||
const static struct luaL_Reg ll_falco[] =
|
||||
{
|
||||
{"formatter", &falco_formats::lua_formatter},
|
||||
{"free_formatter", &falco_formats::lua_free_formatter},
|
||||
{NULL, NULL}};
|
||||
const static struct luaL_reg ll_falco [] =
|
||||
{
|
||||
{"formatter", &falco_formats::formatter},
|
||||
{"free_formatter", &falco_formats::free_formatter},
|
||||
{"free_formatters", &falco_formats::free_formatters},
|
||||
{"format_event", &falco_formats::format_event},
|
||||
{"resolve_tokens", &falco_formats::resolve_tokens},
|
||||
{NULL,NULL}
|
||||
};
|
||||
|
||||
void falco_formats::init(sinsp *inspector,
|
||||
void falco_formats::init(sinsp* inspector,
|
||||
falco_engine *engine,
|
||||
lua_State *ls,
|
||||
bool json_output,
|
||||
@@ -42,14 +47,15 @@ void falco_formats::init(sinsp *inspector,
|
||||
s_engine = engine;
|
||||
s_json_output = json_output;
|
||||
s_json_include_output_property = json_include_output_property;
|
||||
|
||||
// todo(leogr): we should have used std::make_unique, but we cannot since it's not C++14
|
||||
s_formatters = std::unique_ptr<sinsp_evt_formatter_cache>(new sinsp_evt_formatter_cache(s_inspector));
|
||||
if(!s_formatters)
|
||||
{
|
||||
s_formatters = new sinsp_evt_formatter_cache(s_inspector);
|
||||
}
|
||||
|
||||
luaL_openlib(ls, "formats", ll_falco, 0);
|
||||
}
|
||||
|
||||
int falco_formats::lua_formatter(lua_State *ls)
|
||||
int falco_formats::formatter(lua_State *ls)
|
||||
{
|
||||
string source = luaL_checkstring(ls, -2);
|
||||
string format = luaL_checkstring(ls, -1);
|
||||
@@ -58,7 +64,7 @@ int falco_formats::lua_formatter(lua_State *ls)
|
||||
{
|
||||
if(source == "syscall")
|
||||
{
|
||||
sinsp_evt_formatter *formatter;
|
||||
sinsp_evt_formatter* formatter;
|
||||
formatter = new sinsp_evt_formatter(s_inspector, format);
|
||||
lua_pushlightuserdata(ls, formatter);
|
||||
}
|
||||
@@ -69,11 +75,11 @@ int falco_formats::lua_formatter(lua_State *ls)
|
||||
lua_pushlightuserdata(ls, formatter);
|
||||
}
|
||||
}
|
||||
catch(sinsp_exception &e)
|
||||
catch(sinsp_exception& e)
|
||||
{
|
||||
luaL_error(ls, "Invalid output format '%s': '%s'", format.c_str(), e.what());
|
||||
}
|
||||
catch(falco_exception &e)
|
||||
catch(falco_exception& e)
|
||||
{
|
||||
luaL_error(ls, "Invalid output format '%s': '%s'", format.c_str(), e.what());
|
||||
}
|
||||
@@ -81,10 +87,10 @@ int falco_formats::lua_formatter(lua_State *ls)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int falco_formats::lua_free_formatter(lua_State *ls)
|
||||
int falco_formats::free_formatter(lua_State *ls)
|
||||
{
|
||||
if(!lua_islightuserdata(ls, -1) ||
|
||||
!lua_isstring(ls, -2))
|
||||
if (!lua_islightuserdata(ls, -1) ||
|
||||
!lua_isstring(ls, -2))
|
||||
|
||||
{
|
||||
luaL_error(ls, "Invalid argument passed to free_formatter");
|
||||
@@ -94,75 +100,115 @@ int falco_formats::lua_free_formatter(lua_State *ls)
|
||||
|
||||
if(source == "syscall")
|
||||
{
|
||||
sinsp_evt_formatter *formatter = (sinsp_evt_formatter *)lua_topointer(ls, -1);
|
||||
sinsp_evt_formatter *formatter = (sinsp_evt_formatter *) lua_topointer(ls, -1);
|
||||
delete(formatter);
|
||||
}
|
||||
else
|
||||
{
|
||||
json_event_formatter *formatter = (json_event_formatter *)lua_topointer(ls, -1);
|
||||
json_event_formatter *formatter = (json_event_formatter *) lua_topointer(ls, -1);
|
||||
delete(formatter);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
string falco_formats::format_event(const gen_event *evt, const std::string &rule, const std::string &source,
|
||||
const std::string &level, const std::string &format)
|
||||
int falco_formats::free_formatters(lua_State *ls)
|
||||
{
|
||||
if(s_formatters)
|
||||
{
|
||||
delete(s_formatters);
|
||||
s_formatters = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int falco_formats::format_event (lua_State *ls)
|
||||
{
|
||||
string line;
|
||||
string json_line;
|
||||
|
||||
if (!lua_isstring(ls, -1) ||
|
||||
!lua_isstring(ls, -2) ||
|
||||
!lua_isstring(ls, -3) ||
|
||||
!lua_isstring(ls, -4) ||
|
||||
!lua_islightuserdata(ls, -5)) {
|
||||
lua_pushstring(ls, "Invalid arguments passed to format_event()");
|
||||
lua_error(ls);
|
||||
}
|
||||
gen_event* evt = (gen_event*)lua_topointer(ls, 1);
|
||||
const char *rule = (char *) lua_tostring(ls, 2);
|
||||
const char *source = (char *) lua_tostring(ls, 3);
|
||||
const char *level = (char *) lua_tostring(ls, 4);
|
||||
const char *format = (char *) lua_tostring(ls, 5);
|
||||
|
||||
string sformat = format;
|
||||
|
||||
if(strcmp(source.c_str(), "syscall") == 0)
|
||||
if(strcmp(source, "syscall") == 0)
|
||||
{
|
||||
// This is "output"
|
||||
s_formatters->tostring((sinsp_evt *)evt, sformat, &line);
|
||||
try {
|
||||
// This is "output"
|
||||
s_formatters->tostring((sinsp_evt *) evt, sformat, &line);
|
||||
|
||||
if(s_json_output)
|
||||
if(s_json_output)
|
||||
{
|
||||
sinsp_evt::param_fmt cur_fmt = s_inspector->get_buffer_format();
|
||||
switch(cur_fmt)
|
||||
{
|
||||
case sinsp_evt::PF_NORMAL:
|
||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSON);
|
||||
break;
|
||||
case sinsp_evt::PF_EOLS:
|
||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSONEOLS);
|
||||
break;
|
||||
case sinsp_evt::PF_HEX:
|
||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSONHEX);
|
||||
break;
|
||||
case sinsp_evt::PF_HEXASCII:
|
||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSONHEXASCII);
|
||||
break;
|
||||
case sinsp_evt::PF_BASE64:
|
||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSONBASE64);
|
||||
break;
|
||||
default:
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
// This is output fields
|
||||
s_formatters->tostring((sinsp_evt *) evt, sformat, &json_line);
|
||||
|
||||
// The formatted string might have a leading newline. If it does, remove it.
|
||||
if (json_line[0] == '\n')
|
||||
{
|
||||
json_line.erase(0, 1);
|
||||
}
|
||||
s_inspector->set_buffer_format(cur_fmt);
|
||||
}
|
||||
}
|
||||
catch (sinsp_exception& e)
|
||||
{
|
||||
sinsp_evt::param_fmt cur_fmt = s_inspector->get_buffer_format();
|
||||
switch(cur_fmt)
|
||||
{
|
||||
case sinsp_evt::PF_NORMAL:
|
||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSON);
|
||||
break;
|
||||
case sinsp_evt::PF_EOLS:
|
||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSONEOLS);
|
||||
break;
|
||||
case sinsp_evt::PF_HEX:
|
||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSONHEX);
|
||||
break;
|
||||
case sinsp_evt::PF_HEXASCII:
|
||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSONHEXASCII);
|
||||
break;
|
||||
case sinsp_evt::PF_BASE64:
|
||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSONBASE64);
|
||||
break;
|
||||
default:
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
// This is output fields
|
||||
s_formatters->tostring((sinsp_evt *)evt, sformat, &json_line);
|
||||
|
||||
// The formatted string might have a leading newline. If it does, remove it.
|
||||
if(json_line[0] == '\n')
|
||||
{
|
||||
json_line.erase(0, 1);
|
||||
}
|
||||
s_inspector->set_buffer_format(cur_fmt);
|
||||
string err = "Invalid output format '" + sformat + "': '" + string(e.what()) + "'";
|
||||
lua_pushstring(ls, err.c_str());
|
||||
lua_error(ls);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
json_event_formatter formatter(s_engine->json_factory(), sformat);
|
||||
try {
|
||||
|
||||
line = formatter.tostring((json_event *)evt);
|
||||
json_event_formatter formatter(s_engine->json_factory(), sformat);
|
||||
|
||||
if(s_json_output)
|
||||
line = formatter.tostring((json_event *) evt);
|
||||
|
||||
if(s_json_output)
|
||||
{
|
||||
json_line = formatter.tojson((json_event *) evt);
|
||||
}
|
||||
}
|
||||
catch (exception &e)
|
||||
{
|
||||
json_line = formatter.tojson((json_event *)evt);
|
||||
string err = "Invalid output format '" + sformat + "': '" + string(e.what()) + "'";
|
||||
lua_pushstring(ls, err.c_str());
|
||||
lua_error(ls);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,16 +217,15 @@ string falco_formats::format_event(const gen_event *evt, const std::string &rule
|
||||
// message as well as the event time in ns. Use this to build
|
||||
// a more detailed object containing the event time, rule,
|
||||
// severity, full output, and fields.
|
||||
if(s_json_output)
|
||||
{
|
||||
if (s_json_output) {
|
||||
Json::Value event;
|
||||
Json::FastWriter writer;
|
||||
string full_line;
|
||||
|
||||
// Convert the time-as-nanoseconds to a more json-friendly ISO8601.
|
||||
time_t evttime = evt->get_ts() / 1000000000;
|
||||
time_t evttime = evt->get_ts()/1000000000;
|
||||
char time_sec[20]; // sizeof "YYYY-MM-DDTHH:MM:SS"
|
||||
char time_ns[12]; // sizeof ".sssssssssZ"
|
||||
char time_ns[12]; // sizeof ".sssssssssZ"
|
||||
string iso8601evttime;
|
||||
|
||||
strftime(time_sec, sizeof(time_sec), "%FT%T", gmtime(&evttime));
|
||||
@@ -201,9 +246,9 @@ string falco_formats::format_event(const gen_event *evt, const std::string &rule
|
||||
|
||||
// Json::FastWriter may add a trailing newline. If it
|
||||
// does, remove it.
|
||||
if(full_line[full_line.length() - 1] == '\n')
|
||||
if (full_line[full_line.length()-1] == '\n')
|
||||
{
|
||||
full_line.resize(full_line.length() - 1);
|
||||
full_line.resize(full_line.length()-1);
|
||||
}
|
||||
|
||||
// Cheat-graft the output from the formatter into this
|
||||
@@ -216,12 +261,24 @@ string falco_formats::format_event(const gen_event *evt, const std::string &rule
|
||||
line = full_line;
|
||||
}
|
||||
|
||||
return line.c_str();
|
||||
lua_pushstring(ls, line.c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
map<string, string> falco_formats::resolve_tokens(const gen_event *evt, const std::string &source, const std::string &format)
|
||||
int falco_formats::resolve_tokens(lua_State *ls)
|
||||
{
|
||||
if(!lua_isstring(ls, -1) ||
|
||||
!lua_isstring(ls, -2) ||
|
||||
!lua_islightuserdata(ls, -3))
|
||||
{
|
||||
lua_pushstring(ls, "Invalid arguments passed to resolve_tokens()");
|
||||
lua_error(ls);
|
||||
}
|
||||
gen_event *evt = (gen_event *)lua_topointer(ls, 1);
|
||||
string source = luaL_checkstring(ls, 2);
|
||||
const char *format = (char *)lua_tostring(ls, 3);
|
||||
string sformat = format;
|
||||
|
||||
map<string, string> values;
|
||||
if(source == "syscall")
|
||||
{
|
||||
@@ -231,7 +288,16 @@ map<string, string> falco_formats::resolve_tokens(const gen_event *evt, const st
|
||||
else
|
||||
{
|
||||
json_event_formatter json_formatter(s_engine->json_factory(), sformat);
|
||||
values = json_formatter.tomap((json_event *)evt);
|
||||
values = json_formatter.tomap((json_event*) evt);
|
||||
}
|
||||
return values;
|
||||
|
||||
lua_newtable(ls);
|
||||
for(auto const& v : values)
|
||||
{
|
||||
lua_pushstring(ls, v.first.c_str());
|
||||
lua_pushstring(ls, v.second.c_str());
|
||||
lua_settable(ls, -3);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors.
|
||||
Copyright (C) 2019 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -18,8 +18,7 @@ limitations under the License.
|
||||
|
||||
#include "sinsp.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
extern "C" {
|
||||
#include "lua.h"
|
||||
#include "lualib.h"
|
||||
#include "lauxlib.h"
|
||||
@@ -32,28 +31,31 @@ class sinsp_evt_formatter;
|
||||
|
||||
class falco_formats
|
||||
{
|
||||
public:
|
||||
static void init(sinsp *inspector,
|
||||
public:
|
||||
static void init(sinsp* inspector,
|
||||
falco_engine *engine,
|
||||
lua_State *ls,
|
||||
bool json_output,
|
||||
bool json_include_output_property);
|
||||
|
||||
// formatter = falco.formatter(format_string)
|
||||
static int lua_formatter(lua_State *ls);
|
||||
static int formatter(lua_State *ls);
|
||||
|
||||
// falco.free_formatter(formatter)
|
||||
static int lua_free_formatter(lua_State *ls);
|
||||
static int free_formatter(lua_State *ls);
|
||||
|
||||
static string format_event(const gen_event *evt, const std::string &rule, const std::string &source,
|
||||
const std::string &level, const std::string &format);
|
||||
// falco.free_formatters()
|
||||
static int free_formatters(lua_State *ls);
|
||||
|
||||
static map<string, string> resolve_tokens(const gen_event *evt, const std::string &source,
|
||||
const std::string &format);
|
||||
// formatted_string = falco.format_event(evt, formatter)
|
||||
static int format_event(lua_State *ls);
|
||||
|
||||
static sinsp *s_inspector;
|
||||
// resolve_tokens = falco.resolve_tokens(evt, formatter)
|
||||
static int resolve_tokens(lua_State *ls);
|
||||
|
||||
static sinsp* s_inspector;
|
||||
static falco_engine *s_engine;
|
||||
static std::unique_ptr<sinsp_evt_formatter_cache> s_formatters;
|
||||
static sinsp_evt_formatter_cache *s_formatters;
|
||||
static bool s_json_output;
|
||||
static bool s_json_include_output_property;
|
||||
};
|
||||
|
||||
@@ -126,6 +126,31 @@ function set_output(output_format, state)
|
||||
end
|
||||
end
|
||||
|
||||
-- This should be keep in sync with parser.lua
|
||||
defined_comp_operators = {
|
||||
["="]=1,
|
||||
["=="] = 1,
|
||||
["!"] = 1,
|
||||
["<="] = 1,
|
||||
[">="] = 1,
|
||||
["<"] = 1,
|
||||
[">"] = 1,
|
||||
["contains"] = 1,
|
||||
["icontains"] = 1,
|
||||
["glob"] = 1,
|
||||
["startswith"] = 1,
|
||||
["endswith"] = 1,
|
||||
["in"] = 1,
|
||||
["intersects"] = 1,
|
||||
["pmatch"] = 1
|
||||
}
|
||||
|
||||
defined_list_comp_operators = {
|
||||
["in"] = 1,
|
||||
["intersects"] = 1,
|
||||
["pmatch"] = 1
|
||||
}
|
||||
|
||||
-- Note that the rules_by_name and rules_by_idx refer to the same rule
|
||||
-- object. The by_name index is used for things like describing rules,
|
||||
-- and the by_idx index is used to map the relational node index back
|
||||
@@ -253,19 +278,89 @@ function get_lines(rules_lines, row, num_lines)
|
||||
return ret
|
||||
end
|
||||
|
||||
function quote_item(item)
|
||||
if string.sub(item, 1, 1) ~= "'" and string.sub(item, 1, 1) ~= '"' then
|
||||
item = "\""..item.."\""
|
||||
end
|
||||
|
||||
return item
|
||||
end
|
||||
|
||||
function paren_item(item)
|
||||
if string.sub(item, 1, 1) ~= "(" then
|
||||
item = "("..item..")"
|
||||
end
|
||||
|
||||
return item
|
||||
end
|
||||
|
||||
function build_error(rules_lines, row, num_lines, err)
|
||||
local ret = err.."\n---\n"..get_lines(rules_lines, row, num_lines).."---"
|
||||
|
||||
return ret
|
||||
return {ret}
|
||||
end
|
||||
|
||||
function build_error_with_context(ctx, err)
|
||||
local ret = err.."\n---\n"..ctx.."---"
|
||||
return ret
|
||||
return {ret}
|
||||
end
|
||||
|
||||
function validate_exception_item_multi_fields(eitem, context)
|
||||
|
||||
local name = eitem['name']
|
||||
local fields = eitem['fields']
|
||||
local values = eitem['values']
|
||||
local comps = eitem['comps']
|
||||
|
||||
if comps == nil then
|
||||
comps = {}
|
||||
for c=1,#fields do
|
||||
table.insert(comps, "=")
|
||||
end
|
||||
eitem['comps'] = comps
|
||||
else
|
||||
if #fields ~= #comps then
|
||||
return false, build_error_with_context(context, "Rule exception item "..name..": fields and comps lists must have equal length"), warnings
|
||||
end
|
||||
end
|
||||
for k, fname in ipairs(fields) do
|
||||
if defined_noarg_filters[fname] == nil then
|
||||
return false, build_error_with_context(context, "Rule exception item "..name..": field name "..fname.." is not a supported filter field"), warnings
|
||||
end
|
||||
end
|
||||
for k, comp in ipairs(comps) do
|
||||
if defined_comp_operators[comp] == nil then
|
||||
return false, build_error_with_context(context, "Rule exception item "..name..": comparison operator "..comp.." is not a supported comparison operator"), warnings
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function validate_exception_item_single_field(eitem, context)
|
||||
|
||||
local name = eitem['name']
|
||||
local fields = eitem['fields']
|
||||
local values = eitem['values']
|
||||
local comps = eitem['comps']
|
||||
|
||||
if comps == nil then
|
||||
eitem['comps'] = "in"
|
||||
else
|
||||
if type(fields) ~= "string" or type(comps) ~= "string" then
|
||||
return false, build_error_with_context(context, "Rule exception item "..name..": fields and comps must both be strings"), warnings
|
||||
end
|
||||
end
|
||||
if defined_noarg_filters[fields] == nil then
|
||||
return false, build_error_with_context(context, "Rule exception item "..name..": field name "..fields.." is not a supported filter field"), warnings
|
||||
end
|
||||
if defined_comp_operators[comps] == nil then
|
||||
return false, build_error_with_context(context, "Rule exception item "..name..": comparison operator "..comps.." is not a supported comparison operator"), warnings
|
||||
end
|
||||
end
|
||||
|
||||
function load_rules_doc(rules_mgr, doc, load_state)
|
||||
|
||||
local warnings = {}
|
||||
|
||||
-- Iterate over yaml list. In this pass, all we're doing is
|
||||
-- populating the set of rules, macros, and lists. We're not
|
||||
-- expanding/compiling anything yet. All that will happen in a
|
||||
@@ -279,7 +374,7 @@ function load_rules_doc(rules_mgr, doc, load_state)
|
||||
load_state.indices[load_state.cur_item_idx])
|
||||
|
||||
if (not (type(v) == "table")) then
|
||||
return false, build_error_with_context(context, "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."), warnings
|
||||
end
|
||||
|
||||
v['context'] = context
|
||||
@@ -291,13 +386,13 @@ function load_rules_doc(rules_mgr, doc, load_state)
|
||||
end
|
||||
|
||||
if falco_rules.engine_version(rules_mgr) < v['required_engine_version'] then
|
||||
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))
|
||||
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)), warnings
|
||||
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")
|
||||
return false, build_error_with_context(v['context'], "Macro name is empty"), warnings
|
||||
end
|
||||
|
||||
if v['source'] == nil then
|
||||
@@ -310,7 +405,7 @@ function load_rules_doc(rules_mgr, doc, load_state)
|
||||
|
||||
for j, field in ipairs({'condition'}) do
|
||||
if (v[field] == nil) then
|
||||
return false, build_error_with_context(v['context'], "Macro must have property "..field)
|
||||
return false, build_error_with_context(v['context'], "Macro must have property "..field), warnings
|
||||
end
|
||||
end
|
||||
|
||||
@@ -323,7 +418,7 @@ function load_rules_doc(rules_mgr, doc, load_state)
|
||||
|
||||
if append then
|
||||
if state.macros_by_name[v['macro']] == nil then
|
||||
return false, build_error_with_context(v['context'], "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"), warnings
|
||||
end
|
||||
|
||||
state.macros_by_name[v['macro']]['condition'] = state.macros_by_name[v['macro']]['condition'] .. " " .. v['condition']
|
||||
@@ -338,7 +433,7 @@ function load_rules_doc(rules_mgr, doc, load_state)
|
||||
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")
|
||||
return false, build_error_with_context(v['context'], "List name is empty"), warnings
|
||||
end
|
||||
|
||||
if state.lists_by_name[v['list']] == nil then
|
||||
@@ -347,7 +442,7 @@ function load_rules_doc(rules_mgr, doc, load_state)
|
||||
|
||||
for j, field in ipairs({'items'}) do
|
||||
if (v[field] == nil) then
|
||||
return false, build_error_with_context(v['context'], "List must have property "..field)
|
||||
return false, build_error_with_context(v['context'], "List must have property "..field), warnings
|
||||
end
|
||||
end
|
||||
|
||||
@@ -360,7 +455,7 @@ function load_rules_doc(rules_mgr, doc, load_state)
|
||||
|
||||
if append then
|
||||
if state.lists_by_name[v['list']] == nil then
|
||||
return false, build_error_with_context(v['context'], "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"), warnings
|
||||
end
|
||||
|
||||
for j, elem in ipairs(v['items']) do
|
||||
@@ -373,7 +468,7 @@ function load_rules_doc(rules_mgr, doc, load_state)
|
||||
elseif (v['rule']) then
|
||||
|
||||
if (v['rule'] == nil or type(v['rule']) == "table") then
|
||||
return false, build_error_with_context(v['context'], "Rule name is empty")
|
||||
return false, build_error_with_context(v['context'], "Rule name is empty"), warnings
|
||||
end
|
||||
|
||||
-- By default, if a rule's condition refers to an unknown
|
||||
@@ -386,6 +481,13 @@ function load_rules_doc(rules_mgr, doc, load_state)
|
||||
v['source'] = "syscall"
|
||||
end
|
||||
|
||||
-- Add an empty exceptions property to the rule if not
|
||||
-- defined, but add a warning about defining one
|
||||
if v['exceptions'] == nil then
|
||||
warnings[#warnings + 1] = "Rule "..v['rule']..": consider adding an exceptions property to define supported exceptions fields"
|
||||
v['exceptions'] = {}
|
||||
end
|
||||
|
||||
-- Possibly append to the condition field of an existing rule
|
||||
append = false
|
||||
|
||||
@@ -393,21 +495,100 @@ function load_rules_doc(rules_mgr, doc, load_state)
|
||||
append = v['append']
|
||||
end
|
||||
|
||||
-- Validate the contents of the rule exception
|
||||
if next(v['exceptions']) ~= nil then
|
||||
|
||||
-- This validation only applies if append=false. append=true validation is handled below
|
||||
if append == false then
|
||||
|
||||
for _, eitem in ipairs(v['exceptions']) do
|
||||
|
||||
if eitem['name'] == nil then
|
||||
return false, build_error_with_context(v['context'], "Rule exception item must have name property"), warnings
|
||||
end
|
||||
|
||||
if eitem['fields'] == nil then
|
||||
return false, build_error_with_context(v['context'], "Rule exception item "..eitem['name']..": must have fields property with a list of fields"), warnings
|
||||
end
|
||||
|
||||
if eitem['values'] == nil then
|
||||
-- An empty values array is okay
|
||||
eitem['values'] = {}
|
||||
end
|
||||
|
||||
-- Different handling if the fields property is a single item vs a list
|
||||
local valid, err
|
||||
if type(eitem['fields']) == "table" then
|
||||
valid, err = validate_exception_item_multi_fields(eitem, v['context'])
|
||||
else
|
||||
valid, err = validate_exception_item_single_field(eitem, v['context'])
|
||||
end
|
||||
|
||||
if valid == false then
|
||||
return valid, err
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if append then
|
||||
|
||||
-- For append rules, all you need is the condition
|
||||
for j, field in ipairs({'condition'}) do
|
||||
if (v[field] == nil) then
|
||||
return false, build_error_with_context(v['context'], "Rule must have property "..field)
|
||||
end
|
||||
-- For append rules, either condition or exceptions must be specified
|
||||
if (v['condition'] == nil and v['exceptions'] == nil) then
|
||||
return false, build_error_with_context(v['context'], "Rule must have exceptions or condition property"), warnings
|
||||
end
|
||||
|
||||
if state.rules_by_name[v['rule']] == nil then
|
||||
if state.skipped_rules_by_name[v['rule']] == nil then
|
||||
return false, build_error_with_context(v['context'], "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"), warnings
|
||||
end
|
||||
else
|
||||
state.rules_by_name[v['rule']]['condition'] = state.rules_by_name[v['rule']]['condition'] .. " " .. v['condition']
|
||||
|
||||
if next(v['exceptions']) ~= nil then
|
||||
|
||||
for _, eitem in ipairs(v['exceptions']) do
|
||||
local name = eitem['name']
|
||||
local fields = eitem['fields']
|
||||
local comps = eitem['comps']
|
||||
|
||||
if name == nil then
|
||||
return false, build_error_with_context(v['context'], "Rule exception item must have name property"), warnings
|
||||
end
|
||||
|
||||
-- You can't append exception fields or comps to a rule
|
||||
if fields ~= nil then
|
||||
return false, build_error_with_context(v['context'], "Can not append exception fields to existing rule, only values"), warnings
|
||||
end
|
||||
|
||||
if comps ~= nil then
|
||||
return false, build_error_with_context(v['context'], "Can not append exception comps to existing rule, only values"), warnings
|
||||
end
|
||||
|
||||
-- You can append values. They are added to the
|
||||
-- corresponding name, if it exists. If no
|
||||
-- exception with that name exists, add a
|
||||
-- warning.
|
||||
if eitem['values'] ~= nil then
|
||||
local found=false
|
||||
for _, reitem in ipairs(state.rules_by_name[v['rule']]['exceptions']) do
|
||||
if reitem['name'] == eitem['name'] then
|
||||
found=true
|
||||
for _, values in ipairs(eitem['values']) do
|
||||
reitem['values'][#reitem['values'] + 1] = values
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if found == false then
|
||||
warnings[#warnings + 1] = "Rule "..v['rule'].." with append=true: no set of fields matching name "..eitem['name']
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if v['condition'] ~= nil then
|
||||
state.rules_by_name[v['rule']]['condition'] = state.rules_by_name[v['rule']]['condition'] .. " " .. v['condition']
|
||||
end
|
||||
|
||||
-- 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']
|
||||
@@ -417,7 +598,7 @@ function load_rules_doc(rules_mgr, doc, load_state)
|
||||
|
||||
for j, field in ipairs({'condition', 'output', 'desc', 'priority'}) do
|
||||
if (v[field] == nil) then
|
||||
return false, build_error_with_context(v['context'], "Rule must have property "..field)
|
||||
return false, build_error_with_context(v['context'], "Rule must have property "..field), warnings
|
||||
end
|
||||
end
|
||||
|
||||
@@ -446,16 +627,99 @@ function load_rules_doc(rules_mgr, doc, load_state)
|
||||
end
|
||||
end
|
||||
else
|
||||
-- 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))
|
||||
|
||||
arr = build_error_with_context(context, "Unknown top level object: "..table.tostring(v))
|
||||
warnings[#warnings + 1] = arr[1]
|
||||
end
|
||||
end
|
||||
|
||||
return true, ""
|
||||
return true, {}, warnings
|
||||
end
|
||||
|
||||
-- cond and not ((proc.name=apk and fd.directory=/usr/lib/alpine) or (proc.name=npm and fd.directory=/usr/node/bin) or ...)
|
||||
function build_exception_condition_string_multi_fields(eitem)
|
||||
|
||||
local fields = eitem['fields']
|
||||
local comps = eitem['comps']
|
||||
|
||||
local icond = ""
|
||||
|
||||
for i, values in ipairs(eitem['values']) do
|
||||
|
||||
if #fields ~= #values then
|
||||
return nil, "Exception item "..eitem['name']..": fields and values lists must have equal length"
|
||||
end
|
||||
|
||||
if icond ~= "" then
|
||||
icond=icond.." or "
|
||||
end
|
||||
|
||||
icond=icond.."("
|
||||
|
||||
for k=1,#fields do
|
||||
if k > 1 then
|
||||
icond=icond.." and "
|
||||
end
|
||||
local ival = values[k]
|
||||
local istr = ""
|
||||
|
||||
-- If ival is a table, express it as (titem1, titem2, etc)
|
||||
if type(ival) == "table" then
|
||||
istr = "("
|
||||
for _, item in ipairs(ival) do
|
||||
if istr ~= "(" then
|
||||
istr = istr..", "
|
||||
end
|
||||
istr = istr..quote_item(item)
|
||||
end
|
||||
istr = istr..")"
|
||||
else
|
||||
-- If the corresponding operator is one that works on lists, possibly add surrounding parentheses.
|
||||
if defined_list_comp_operators[comps[k]] then
|
||||
istr = paren_item(ival)
|
||||
else
|
||||
-- Quote the value if not already quoted
|
||||
istr = quote_item(ival)
|
||||
end
|
||||
end
|
||||
|
||||
icond = icond..fields[k].." "..comps[k].." "..istr
|
||||
end
|
||||
|
||||
icond=icond..")"
|
||||
end
|
||||
|
||||
return icond, nil
|
||||
|
||||
end
|
||||
|
||||
function build_exception_condition_string_single_field(eitem)
|
||||
|
||||
local icond = ""
|
||||
|
||||
for i, value in ipairs(eitem['values']) do
|
||||
|
||||
if icond == "" then
|
||||
icond = "("..eitem['fields'].." "..eitem['comps'].." ("
|
||||
else
|
||||
icond = icond..", "
|
||||
end
|
||||
|
||||
icond = icond..quote_item(value)
|
||||
end
|
||||
|
||||
icond = icond.."))"
|
||||
|
||||
return icond, nil
|
||||
|
||||
end
|
||||
|
||||
-- Returns:
|
||||
-- - Load Result: bool
|
||||
-- - required engine version. will be nil when load result is false
|
||||
-- - List of Errors
|
||||
-- - List of Warnings
|
||||
function load_rules(sinsp_lua_parser,
|
||||
json_lua_parser,
|
||||
rules_content,
|
||||
@@ -466,6 +730,8 @@ function load_rules(sinsp_lua_parser,
|
||||
replace_container_info,
|
||||
min_priority)
|
||||
|
||||
local warnings = {}
|
||||
|
||||
local load_state = {lines={}, indices={}, cur_item_idx=0, min_priority=min_priority, required_engine_version=0}
|
||||
|
||||
load_state.lines, load_state.indices = split_lines(rules_content)
|
||||
@@ -487,36 +753,42 @@ function load_rules(sinsp_lua_parser,
|
||||
row = tonumber(row)
|
||||
col = tonumber(col)
|
||||
|
||||
return false, build_error(load_state.lines, row, 3, docs)
|
||||
return false, nil, build_error(load_state.lines, row, 3, docs), warnings
|
||||
end
|
||||
|
||||
if docs == nil then
|
||||
-- An empty rules file is acceptable
|
||||
return true, load_state.required_engine_version
|
||||
return true, load_state.required_engine_version, {}, warnings
|
||||
end
|
||||
|
||||
if type(docs) ~= "table" then
|
||||
return false, build_error(load_state.lines, 1, 1, "Rules content is not yaml")
|
||||
return false, nil, build_error(load_state.lines, 1, 1, "Rules content is not yaml"), warnings
|
||||
end
|
||||
|
||||
for docidx, doc in ipairs(docs) do
|
||||
|
||||
if type(doc) ~= "table" then
|
||||
return false, build_error(load_state.lines, 1, 1, "Rules content is not yaml")
|
||||
return false, nil, build_error(load_state.lines, 1, 1, "Rules content is not yaml"), warnings
|
||||
end
|
||||
|
||||
-- Look for non-numeric indices--implies that document is not array
|
||||
-- of objects.
|
||||
for key, val in pairs(doc) do
|
||||
if type(key) ~= "number" then
|
||||
return false, build_error(load_state.lines, 1, 1, "Rules content is not yaml array of objects")
|
||||
return false, nil, build_error(load_state.lines, 1, 1, "Rules content is not yaml array of objects"), warnings
|
||||
end
|
||||
end
|
||||
|
||||
res, errstr = load_rules_doc(rules_mgr, doc, load_state)
|
||||
res, errors, doc_warnings = load_rules_doc(rules_mgr, doc, load_state)
|
||||
|
||||
if (doc_warnings ~= nil) then
|
||||
for idx, warning in pairs(doc_warnings) do
|
||||
table.insert(warnings, warning)
|
||||
end
|
||||
end
|
||||
|
||||
if not res then
|
||||
return res, errstr
|
||||
return res, nil, errors, warnings
|
||||
end
|
||||
end
|
||||
|
||||
@@ -538,7 +810,7 @@ function load_rules(sinsp_lua_parser,
|
||||
-- the items and expand any references to the items in the list
|
||||
for i, item in ipairs(v['items']) do
|
||||
if (state.lists[item] == nil) then
|
||||
items[#items+1] = item
|
||||
items[#items+1] = quote_item(item)
|
||||
else
|
||||
for i, exp_item in ipairs(state.lists[item].items) do
|
||||
items[#items+1] = exp_item
|
||||
@@ -556,7 +828,7 @@ function load_rules(sinsp_lua_parser,
|
||||
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)
|
||||
return false, nil, build_error_with_context(v['context'], ast), warnings
|
||||
end
|
||||
|
||||
if v['source'] == "syscall" then
|
||||
@@ -572,6 +844,38 @@ function load_rules(sinsp_lua_parser,
|
||||
|
||||
local v = state.rules_by_name[name]
|
||||
|
||||
local econd = ""
|
||||
|
||||
-- Turn exceptions into condition strings and add them to each
|
||||
-- rule's condition
|
||||
for _, eitem in ipairs(v['exceptions']) do
|
||||
|
||||
local icond, err
|
||||
if type(eitem['fields']) == "table" then
|
||||
icond, err = build_exception_condition_string_multi_fields(eitem)
|
||||
else
|
||||
icond, err = build_exception_condition_string_single_field(eitem)
|
||||
end
|
||||
|
||||
if err ~= nil then
|
||||
return false, nil, build_error_with_context(v['context'], err), warnings
|
||||
end
|
||||
|
||||
if icond ~= "" then
|
||||
if econd == "" then
|
||||
econd = econd.." and not ("..icond
|
||||
else
|
||||
econd = econd.." or "..icond
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if econd ~= "" then
|
||||
econd=econd..")"
|
||||
|
||||
state.rules_by_name[name]['condition'] = "("..state.rules_by_name[name]['condition']..") "..econd
|
||||
end
|
||||
|
||||
warn_evttypes = true
|
||||
if v['warn_evttypes'] ~= nil then
|
||||
warn_evttypes = v['warn_evttypes']
|
||||
@@ -581,7 +885,7 @@ function load_rules(sinsp_lua_parser,
|
||||
state.macros, state.lists)
|
||||
|
||||
if status == false then
|
||||
return false, build_error_with_context(v['context'], filter_ast)
|
||||
return false, nil, build_error_with_context(v['context'], filter_ast), warnings
|
||||
end
|
||||
|
||||
local evtttypes = {}
|
||||
@@ -631,12 +935,10 @@ function load_rules(sinsp_lua_parser,
|
||||
end
|
||||
|
||||
if not found then
|
||||
if v['skip-if-unknown-filter'] then
|
||||
if verbose then
|
||||
print("Skipping rule \""..v['rule'].."\" that contains unknown filter "..filter)
|
||||
end
|
||||
goto next_rule
|
||||
else
|
||||
msg = "rule \""..v['rule'].."\" contains unknown filter "..filter
|
||||
warnings[#warnings + 1] = msg
|
||||
|
||||
if not v['skip-if-unknown-filter'] then
|
||||
error("Rule \""..v['rule'].."\" contains unknown filter "..filter)
|
||||
end
|
||||
end
|
||||
@@ -719,30 +1021,30 @@ function load_rules(sinsp_lua_parser,
|
||||
formatter = formats.formatter(v['source'], v['output'])
|
||||
formats.free_formatter(v['source'], formatter)
|
||||
else
|
||||
return false, build_error_with_context(v['context'], "Unexpected type in load_rule: "..filter_ast.type)
|
||||
return false, nil, build_error_with_context(v['context'], "Unexpected type in load_rule: "..filter_ast.type), warnings
|
||||
end
|
||||
|
||||
::next_rule::
|
||||
end
|
||||
|
||||
if verbose then
|
||||
-- Print info on any dangling lists or macros that were not used anywhere
|
||||
for name, macro in pairs(state.macros) do
|
||||
if macro.used == false then
|
||||
print("Warning: macro "..name.." not refered to by any rule/macro")
|
||||
end
|
||||
-- Print info on any dangling lists or macros that were not used anywhere
|
||||
for name, macro in pairs(state.macros) do
|
||||
if macro.used == false then
|
||||
msg = "macro "..name.." not refered to by any rule/macro"
|
||||
warnings[#warnings + 1] = msg
|
||||
end
|
||||
end
|
||||
|
||||
for name, list in pairs(state.lists) do
|
||||
if list.used == false then
|
||||
print("Warning: list "..name.." not refered to by any rule/macro/list")
|
||||
end
|
||||
for name, list in pairs(state.lists) do
|
||||
if list.used == false then
|
||||
msg = "list "..name.." not refered to by any rule/macro/list"
|
||||
warnings[#warnings + 1] = msg
|
||||
end
|
||||
end
|
||||
|
||||
io.flush()
|
||||
|
||||
return true, load_state.required_engine_version
|
||||
return true, load_state.required_engine_version, {}, warnings
|
||||
end
|
||||
|
||||
local rule_fmt = "%-50s %s"
|
||||
|
||||
@@ -14,8 +14,9 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "rules.h"
|
||||
#include "logger.h"
|
||||
|
||||
extern "C" {
|
||||
#include "lua.h"
|
||||
@@ -26,14 +27,15 @@ extern "C" {
|
||||
#include "falco_engine.h"
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
const static struct luaL_Reg ll_falco_rules[] =
|
||||
{
|
||||
{"clear_filters", &falco_rules::clear_filters},
|
||||
{"add_filter", &falco_rules::add_filter},
|
||||
{"add_k8s_audit_filter", &falco_rules::add_k8s_audit_filter},
|
||||
{"enable_rule", &falco_rules::enable_rule},
|
||||
{"engine_version", &falco_rules::engine_version},
|
||||
{NULL, NULL}};
|
||||
const static struct luaL_reg ll_falco_rules [] =
|
||||
{
|
||||
{"clear_filters", &falco_rules::clear_filters},
|
||||
{"add_filter", &falco_rules::add_filter},
|
||||
{"add_k8s_audit_filter", &falco_rules::add_k8s_audit_filter},
|
||||
{"enable_rule", &falco_rules::enable_rule},
|
||||
{"engine_version", &falco_rules::engine_version},
|
||||
{NULL,NULL}
|
||||
};
|
||||
|
||||
falco_rules::falco_rules(sinsp* inspector,
|
||||
falco_engine *engine,
|
||||
@@ -218,6 +220,31 @@ int falco_rules::engine_version(lua_State *ls)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static std::list<std::string> get_lua_table_values(lua_State *ls, int idx)
|
||||
{
|
||||
std::list<std::string> ret;
|
||||
|
||||
if (lua_isnil(ls, idx)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
lua_pushnil(ls); /* first key */
|
||||
while (lua_next(ls, idx-1) != 0) {
|
||||
// key is at index -2, value is at index
|
||||
// -1. We want the values.
|
||||
if (! lua_isstring(ls, -1)) {
|
||||
std::string err = "Non-string value in table of strings";
|
||||
throw falco_exception(err);
|
||||
}
|
||||
ret.push_back(string(lua_tostring(ls, -1)));
|
||||
|
||||
// Remove value, keep key for next iteration
|
||||
lua_pop(ls, 1);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void falco_rules::load_rules(const string &rules_content,
|
||||
bool verbose, bool all_events,
|
||||
string &extra, bool replace_container_info,
|
||||
@@ -423,7 +450,7 @@ 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, 2, 0) != 0)
|
||||
if(lua_pcall(m_ls, 9, 4, 0) != 0)
|
||||
{
|
||||
const char* lerr = lua_tostring(m_ls, -1);
|
||||
|
||||
@@ -432,20 +459,49 @@ void falco_rules::load_rules(const string &rules_content,
|
||||
throw falco_exception(err);
|
||||
}
|
||||
|
||||
// Either returns (true, required_engine_version), or (false, error string)
|
||||
bool successful = lua_toboolean(m_ls, -2);
|
||||
// Returns:
|
||||
// Load result: bool
|
||||
// required engine version: will be nil when load result is false
|
||||
// array of errors
|
||||
// array of warnings
|
||||
bool successful = lua_toboolean(m_ls, -4);
|
||||
required_engine_version = lua_tonumber(m_ls, -3);
|
||||
std::list<std::string> errors = get_lua_table_values(m_ls, -2);
|
||||
std::list<std::string> warnings = get_lua_table_values(m_ls, -1);
|
||||
|
||||
if(successful)
|
||||
// Concatenate errors/warnings
|
||||
std::ostringstream os;
|
||||
if (errors.size() > 0)
|
||||
{
|
||||
required_engine_version = lua_tonumber(m_ls, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string err = lua_tostring(m_ls, -1);
|
||||
throw falco_exception(err);
|
||||
os << errors.size() << " errors:" << std::endl;
|
||||
for(auto err : errors)
|
||||
{
|
||||
os << err << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
lua_pop(m_ls, 2);
|
||||
if (warnings.size() > 0)
|
||||
{
|
||||
os << warnings.size() << " warnings:" << std::endl;
|
||||
for(auto warn : warnings)
|
||||
{
|
||||
os << warn << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if(!successful)
|
||||
{
|
||||
throw falco_exception(os.str());
|
||||
}
|
||||
|
||||
if (verbose && os.str() != "") {
|
||||
// We don't really have a logging callback
|
||||
// from the falco engine, but this would be a
|
||||
// good place to use it.
|
||||
fprintf(stderr, "When reading rules content: %s", os.str().c_str());
|
||||
}
|
||||
|
||||
lua_pop(m_ls, 4);
|
||||
|
||||
} else {
|
||||
throw falco_exception("No function " + m_lua_load_rules + " found in lua rule module");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
# Copyright (C) 2019 The Falco Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
@@ -11,91 +11,117 @@
|
||||
# specific language governing permissions and limitations under the License.
|
||||
#
|
||||
|
||||
configure_file(config_falco.h.in config_falco.h)
|
||||
configure_file("${SYSDIG_SOURCE_DIR}/userspace/sysdig/config_sysdig.h.in" config_sysdig.h)
|
||||
|
||||
set(
|
||||
FALCO_SOURCES
|
||||
cli.cpp
|
||||
if(NOT MINIMAL_BUILD)
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
${CMAKE_CURRENT_BINARY_DIR}/version.grpc.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/version.grpc.pb.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/version.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/version.pb.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/outputs.grpc.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/outputs.grpc.pb.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/outputs.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/outputs.pb.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/schema.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/schema.pb.h
|
||||
COMMENT "Generate gRPC API"
|
||||
# Falco gRPC Version API
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/version.proto
|
||||
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --cpp_out=. ${CMAKE_CURRENT_SOURCE_DIR}/version.proto
|
||||
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --grpc_out=. --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/version.proto
|
||||
# Falco gRPC Outputs API
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/outputs.proto
|
||||
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --cpp_out=. ${CMAKE_CURRENT_SOURCE_DIR}/outputs.proto
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/schema.proto
|
||||
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --grpc_out=. --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/outputs.proto
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
endif()
|
||||
|
||||
if(MINIMAL_BUILD)
|
||||
add_executable(
|
||||
falco
|
||||
configuration.cpp
|
||||
logger.cpp
|
||||
falco_outputs.cpp
|
||||
outputs_file.cpp
|
||||
outputs_program.cpp
|
||||
outputs_stdout.cpp
|
||||
outputs_syslog.cpp
|
||||
event_drops.cpp
|
||||
statsfilewriter.cpp
|
||||
falco.cpp
|
||||
"${SYSDIG_SOURCE_DIR}/userspace/libsinsp/fields_info.cpp"
|
||||
)
|
||||
|
||||
set(
|
||||
FALCO_INCLUDE_DIRECTORIES
|
||||
"${PROJECT_SOURCE_DIR}/userspace/engine"
|
||||
"${PROJECT_BINARY_DIR}/userspace/falco"
|
||||
"${PROJECT_BINARY_DIR}/driver/src"
|
||||
"${STRING_VIEW_LITE_INCLUDE}"
|
||||
"${CXXOPTS_INCLUDE}"
|
||||
"${YAMLCPP_INCLUDE_DIR}"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
"${DRAIOS_DEPENDENCIES_DIR}/yaml-${DRAIOS_YAML_VERSION}/target/include"
|
||||
)
|
||||
|
||||
set(
|
||||
FALCO_DEPENDENCIES
|
||||
cxxopts
|
||||
string-view-lite
|
||||
libyaml
|
||||
b64
|
||||
luajit
|
||||
lpeg
|
||||
lyaml
|
||||
)
|
||||
|
||||
set(
|
||||
FALCO_LIBRARIES
|
||||
falco_engine
|
||||
sinsp
|
||||
"${LIBYAML_LIB}"
|
||||
"${YAMLCPP_LIB}"
|
||||
)
|
||||
|
||||
if(USE_BUNDLED_DEPS)
|
||||
list(APPEND FALCO_DEPENDENCIES yamlcpp)
|
||||
endif()
|
||||
|
||||
if(NOT MINIMAL_BUILD)
|
||||
list(
|
||||
APPEND FALCO_SOURCES
|
||||
outputs_grpc.cpp
|
||||
outputs_http.cpp
|
||||
"${SYSDIG_SOURCE_DIR}/userspace/sysdig/fields_info.cpp")
|
||||
else()
|
||||
add_executable(
|
||||
falco
|
||||
configuration.cpp
|
||||
logger.cpp
|
||||
falco_outputs.cpp
|
||||
event_drops.cpp
|
||||
statsfilewriter.cpp
|
||||
falco.cpp
|
||||
"${SYSDIG_SOURCE_DIR}/userspace/sysdig/fields_info.cpp"
|
||||
webserver.cpp
|
||||
grpc_context.cpp
|
||||
grpc_server_impl.cpp
|
||||
grpc_request_context.cpp
|
||||
grpc_server.cpp
|
||||
grpc_context.cpp
|
||||
grpc_server_impl.cpp
|
||||
${CMAKE_CURRENT_BINARY_DIR}/version.grpc.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/version.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/outputs.grpc.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/outputs.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/schema.pb.cc
|
||||
)
|
||||
${CMAKE_CURRENT_BINARY_DIR}/schema.pb.cc)
|
||||
|
||||
list(
|
||||
APPEND FALCO_INCLUDE_DIRECTORIES
|
||||
"${CIVETWEB_INCLUDE_DIR}"
|
||||
"${OPENSSL_INCLUDE_DIR}"
|
||||
"${GRPC_INCLUDE}"
|
||||
"${GRPCPP_INCLUDE}"
|
||||
"${PROTOBUF_INCLUDE}"
|
||||
)
|
||||
add_dependencies(falco civetweb)
|
||||
endif()
|
||||
|
||||
list(APPEND FALCO_DEPENDENCIES civetweb)
|
||||
add_dependencies(falco string-view-lite)
|
||||
|
||||
list(
|
||||
APPEND FALCO_LIBRARIES
|
||||
if(USE_BUNDLED_DEPS)
|
||||
add_dependencies(falco yamlcpp)
|
||||
endif()
|
||||
|
||||
if(MINIMAL_BUILD)
|
||||
target_include_directories(
|
||||
falco
|
||||
PUBLIC
|
||||
"${SYSDIG_SOURCE_DIR}/userspace/sysdig"
|
||||
"${PROJECT_SOURCE_DIR}/userspace/engine"
|
||||
"${PROJECT_BINARY_DIR}/userspace/falco"
|
||||
"${PROJECT_BINARY_DIR}/driver/src"
|
||||
"${STRING_VIEW_LITE_INCLUDE}"
|
||||
"${YAMLCPP_INCLUDE_DIR}"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
"${DRAIOS_DEPENDENCIES_DIR}/yaml-${DRAIOS_YAML_VERSION}/target/include")
|
||||
|
||||
target_link_libraries(
|
||||
falco
|
||||
falco_engine
|
||||
sinsp
|
||||
"${LIBYAML_LIB}"
|
||||
"${YAMLCPP_LIB}")
|
||||
else()
|
||||
target_include_directories(
|
||||
falco
|
||||
PUBLIC
|
||||
"${SYSDIG_SOURCE_DIR}/userspace/sysdig"
|
||||
"${PROJECT_SOURCE_DIR}/userspace/engine"
|
||||
"${PROJECT_BINARY_DIR}/userspace/falco"
|
||||
"${PROJECT_BINARY_DIR}/driver/src"
|
||||
"${STRING_VIEW_LITE_INCLUDE}"
|
||||
"${YAMLCPP_INCLUDE_DIR}"
|
||||
"${CIVETWEB_INCLUDE_DIR}"
|
||||
"${OPENSSL_INCLUDE_DIR}"
|
||||
"${GRPC_INCLUDE}"
|
||||
"${GRPCPP_INCLUDE}"
|
||||
"${PROTOBUF_INCLUDE}"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
"${DRAIOS_DEPENDENCIES_DIR}/yaml-${DRAIOS_YAML_VERSION}/target/include")
|
||||
|
||||
target_link_libraries(
|
||||
falco
|
||||
falco_engine
|
||||
sinsp
|
||||
"${GPR_LIB}"
|
||||
"${GRPC_LIB}"
|
||||
"${GRPCPP_LIB}"
|
||||
@@ -104,66 +130,19 @@ if(NOT MINIMAL_BUILD)
|
||||
"${OPENSSL_LIBRARY_CRYPTO}"
|
||||
"${LIBYAML_LIB}"
|
||||
"${YAMLCPP_LIB}"
|
||||
"${CIVETWEB_LIB}"
|
||||
)
|
||||
"${CIVETWEB_LIB}")
|
||||
endif()
|
||||
|
||||
add_executable(
|
||||
falco
|
||||
${FALCO_SOURCES}
|
||||
)
|
||||
|
||||
add_dependencies(falco ${FALCO_DEPENDENCIES})
|
||||
|
||||
target_link_libraries(
|
||||
falco
|
||||
${FALCO_LIBRARIES}
|
||||
)
|
||||
|
||||
target_include_directories(
|
||||
falco
|
||||
PUBLIC
|
||||
${FALCO_INCLUDE_DIRECTORIES}
|
||||
)
|
||||
|
||||
# if(NOT MINIMAL_BUILD)
|
||||
# add_custom_command(
|
||||
# TARGET falco
|
||||
# COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/verify_engine_fields.sh ${CMAKE_SOURCE_DIR}
|
||||
# WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
# COMMENT "Comparing engine fields checksum in falco_engine.h to actual fields"
|
||||
# )
|
||||
# else()
|
||||
# message(STATUS "Skipping engine fields checksum when building the minimal Falco.")
|
||||
# endif()
|
||||
configure_file(config_falco.h.in config_falco.h)
|
||||
|
||||
if(NOT MINIMAL_BUILD)
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
${CMAKE_CURRENT_BINARY_DIR}/version.grpc.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/version.grpc.pb.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/version.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/version.pb.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/outputs.grpc.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/outputs.grpc.pb.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/outputs.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/outputs.pb.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/schema.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/schema.pb.h
|
||||
COMMENT "Generate gRPC API"
|
||||
# Falco gRPC Version API
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/version.proto
|
||||
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --cpp_out=. ${CMAKE_CURRENT_SOURCE_DIR}/version.proto
|
||||
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --grpc_out=. --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/version.proto
|
||||
# Falco gRPC Outputs API
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/outputs.proto
|
||||
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --cpp_out=. ${CMAKE_CURRENT_SOURCE_DIR}/outputs.proto
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/schema.proto
|
||||
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --grpc_out=. --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/outputs.proto
|
||||
TARGET falco
|
||||
COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/verify_engine_fields.sh ${CMAKE_SOURCE_DIR}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
COMMENT "Comparing engine fields checksum in falco_engine.h to actual fields")
|
||||
else()
|
||||
MESSAGE(STATUS "Skipping engine fields checksum when building the minimal Falco.")
|
||||
endif()
|
||||
|
||||
# strip the Falco binary when releasing using musl
|
||||
@@ -172,8 +151,12 @@ if(MUSL_OPTIMIZED_BUILD AND CMAKE_BUILD_TYPE STREQUAL "release")
|
||||
TARGET falco
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_STRIP} --strip-unneeded falco
|
||||
COMMENT "Strip the Falco binary when releasing the musl build"
|
||||
)
|
||||
COMMENT "Strip the Falco binary when releasing the musl build")
|
||||
endif()
|
||||
|
||||
install(TARGETS falco DESTINATION ${FALCO_BIN_DIR})
|
||||
install(
|
||||
DIRECTORY lua
|
||||
DESTINATION ${FALCO_SHARE_DIR}
|
||||
FILES_MATCHING
|
||||
PATTERN *.lua)
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "cli.h"
|
||||
|
||||
namespace falco
|
||||
{
|
||||
|
||||
} // namespace falco
|
||||
@@ -1,188 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include <cxxopts.hpp>
|
||||
|
||||
namespace falco
|
||||
{
|
||||
|
||||
class option_requires_specific_argument_exception : public cxxopts::OptionParseException
|
||||
{
|
||||
public:
|
||||
explicit option_requires_specific_argument_exception(const std::string& option, const std::string& values):
|
||||
OptionParseException("Option " + cxxopts::LQUOTE + option + cxxopts::RQUOTE + " requires an argument equal to " + values)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class option_cannot_be_specified_exception : public cxxopts::OptionParseException
|
||||
{
|
||||
public:
|
||||
explicit option_cannot_be_specified_exception(const std::string& option1, const std::string& option2):
|
||||
OptionParseException("Options " + cxxopts::LQUOTE + option1 + cxxopts::RQUOTE + " and " + cxxopts::LQUOTE + option2 + cxxopts::RQUOTE + " can not be specified together")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class cli
|
||||
{
|
||||
public:
|
||||
cli(int argc, const char** argv):
|
||||
m_argc(argc), m_argv(argv), m_options("falco", "Cloud-Native Runtime Security")
|
||||
{
|
||||
}
|
||||
virtual ~cli()
|
||||
{
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
// These options give some info about Falco (Falco exits).
|
||||
m_options.add_options(
|
||||
"help",
|
||||
{
|
||||
{"h,help", "Print help page."},
|
||||
{"support", "Print support information (version, rules files, etc.)."},
|
||||
{"version", "Print version info."},
|
||||
});
|
||||
|
||||
// These are options responsible for listing Falco elements (Falco exits).
|
||||
m_options.add_options(
|
||||
"list",
|
||||
{
|
||||
{"L", "Show name and description of all rules."},
|
||||
{"l", "Show name and description of a specific rule.", cxxopts::value<std::string>(), "rule name"},
|
||||
{"list", "Show all fields.", cxxopts::value<std::string>()->implicit_value("all"), "sycall|k8s_audit"},
|
||||
{"N", "Show field names only."},
|
||||
});
|
||||
|
||||
// m_options.add_options(
|
||||
// "output",
|
||||
// {
|
||||
// {},
|
||||
// });
|
||||
|
||||
// m_options.add_options(
|
||||
// "input",
|
||||
// {
|
||||
// {},
|
||||
// });
|
||||
|
||||
m_options.add_options(
|
||||
"filtering",
|
||||
{
|
||||
{"D", "Disable any rules with names having the given substring. Can be specified multiple times. Can not be specified with -t.", cxxopts::value<std::vector<std::string>>(), "substring"},
|
||||
{"T", "Disable any rules with a specific tag. Can be specified several times. Can not be specified with -t.", cxxopts::value<std::vector<std::string>>(), "tag"},
|
||||
{"t", "Only run those rules with a specific tag. Can be specified several times. Can not be specified with -T or -D.", cxxopts::value<std::vector<std::string>>(), "tag"},
|
||||
});
|
||||
|
||||
m_result = m_options.parse(m_argc, m_argv);
|
||||
|
||||
process();
|
||||
}
|
||||
|
||||
private:
|
||||
void process()
|
||||
{
|
||||
if(m_result.count("help") && m_result["help"].as<bool>())
|
||||
{
|
||||
std::cout << m_options.help() << std::endl;
|
||||
// todo: print > exit
|
||||
}
|
||||
|
||||
if(m_result.count("support") && m_result["support"].as<bool>())
|
||||
{
|
||||
// todo: argv + config rule filenames > cmdline > print > exit
|
||||
}
|
||||
|
||||
if(m_result.count("version") && m_result["version"].as<bool>())
|
||||
{
|
||||
// todo: print > exit
|
||||
}
|
||||
|
||||
if(m_result.count("L") && m_result["L"].as<bool>())
|
||||
{
|
||||
// todo: engine > print > exit
|
||||
// engine->describe_rule(NULL)
|
||||
}
|
||||
|
||||
if(m_result.count("l"))
|
||||
{
|
||||
// todo: engine > print > exit
|
||||
// engine->describe_rule(m_result["l"].as<string>());
|
||||
}
|
||||
|
||||
if(m_result.count("list"))
|
||||
{
|
||||
auto source = m_result["list"].as<std::string>();
|
||||
// todo: retrieve implicit value
|
||||
if(source.empty() || (source != "syscall" && source != "k8s_audit" && source != "all"))
|
||||
{
|
||||
throw falco::option_requires_specific_argument_exception(
|
||||
"list",
|
||||
cxxopts::LQUOTE + "syscall" + cxxopts::RQUOTE + " or " + cxxopts::LQUOTE + "k8s_audit" + cxxopts::RQUOTE);
|
||||
}
|
||||
|
||||
bool names_only = false;
|
||||
if(m_result.count("N"))
|
||||
{
|
||||
names_only = m_result["N"].as<bool>();
|
||||
}
|
||||
|
||||
// todo: engine + names_only + source
|
||||
// se valore == syscall ==> + [-V]
|
||||
}
|
||||
|
||||
bool count_D = m_result.count("D");
|
||||
bool count_t = m_result.count("t");
|
||||
bool count_T = m_result.count("T");
|
||||
if(count_D > 0)
|
||||
{
|
||||
if(count_t > 0)
|
||||
{
|
||||
throw falco::option_cannot_be_specified_exception("D", "t");
|
||||
}
|
||||
// todo
|
||||
// engine > not exit
|
||||
}
|
||||
if(count_T > 0)
|
||||
{
|
||||
if(count_t > 0)
|
||||
{
|
||||
throw falco::option_cannot_be_specified_exception("T", "t");
|
||||
}
|
||||
// todo
|
||||
// engine > not exit
|
||||
}
|
||||
if(count_t > 0)
|
||||
{
|
||||
// todo
|
||||
// engine > not exit
|
||||
}
|
||||
}
|
||||
|
||||
int m_argc;
|
||||
const char** m_argv;
|
||||
cxxopts::Options m_options;
|
||||
cxxopts::ParseResult m_result;
|
||||
};
|
||||
|
||||
} // namespace falco
|
||||
|
||||
// 3 tipi di azioni
|
||||
// quelle che una volta date devono farlo uscire e non hanno bisogno di nessuna istanza
|
||||
// quelle che hanno bisogno di inspector e/o engine e poi falco esce
|
||||
// quelle che hanno bisogno di inspector e/o engine e poi falco esegue
|
||||
@@ -25,9 +25,11 @@ limitations under the License.
|
||||
#define FALCO_VERSION_PRERELEASE "@FALCO_VERSION_PRERELEASE@"
|
||||
#define FALCO_VERSION_BUILD "@FALCO_VERSION_BUILD@"
|
||||
|
||||
#define FALCO_LUA_DIR "${CMAKE_INSTALL_PREFIX}/${FALCO_SHARE_DIR}/lua/"
|
||||
#define FALCO_SOURCE_DIR "${PROJECT_SOURCE_DIR}"
|
||||
#define FALCO_SOURCE_CONF_FILE "${PROJECT_SOURCE_DIR}/falco.yaml"
|
||||
#define FALCO_INSTALL_CONF_FILE "/etc/falco/falco.yaml"
|
||||
#define FALCO_SOURCE_LUA_DIR "${PROJECT_SOURCE_DIR}/userspace/falco/lua/"
|
||||
|
||||
#define PROBE_NAME "@PROBE_NAME@"
|
||||
#define DRIVER_VERSION "@PROBE_VERSION@"
|
||||
@@ -52,7 +52,7 @@ void falco_configuration::init(list<string> &cmdline_options)
|
||||
{
|
||||
init_cmdline_options(cmdline_options);
|
||||
|
||||
falco::outputs::config stdout_output;
|
||||
falco_outputs::output_config stdout_output;
|
||||
stdout_output.name = "stdout";
|
||||
m_outputs.push_back(stdout_output);
|
||||
}
|
||||
@@ -81,7 +81,7 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
|
||||
m_json_output = m_config->get_scalar<bool>("json_output", false);
|
||||
m_json_include_output_property = m_config->get_scalar<bool>("json_include_output_property", true);
|
||||
|
||||
falco::outputs::config file_output;
|
||||
falco_outputs::output_config file_output;
|
||||
file_output.name = "file";
|
||||
if(m_config->get_scalar<bool>("file_output", "enabled", false))
|
||||
{
|
||||
@@ -99,21 +99,21 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
|
||||
m_outputs.push_back(file_output);
|
||||
}
|
||||
|
||||
falco::outputs::config stdout_output;
|
||||
falco_outputs::output_config stdout_output;
|
||||
stdout_output.name = "stdout";
|
||||
if(m_config->get_scalar<bool>("stdout_output", "enabled", false))
|
||||
{
|
||||
m_outputs.push_back(stdout_output);
|
||||
}
|
||||
|
||||
falco::outputs::config syslog_output;
|
||||
falco_outputs::output_config syslog_output;
|
||||
syslog_output.name = "syslog";
|
||||
if(m_config->get_scalar<bool>("syslog_output", "enabled", false))
|
||||
{
|
||||
m_outputs.push_back(syslog_output);
|
||||
}
|
||||
|
||||
falco::outputs::config program_output;
|
||||
falco_outputs::output_config program_output;
|
||||
program_output.name = "program";
|
||||
if(m_config->get_scalar<bool>("program_output", "enabled", false))
|
||||
{
|
||||
@@ -131,7 +131,7 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
|
||||
m_outputs.push_back(program_output);
|
||||
}
|
||||
|
||||
falco::outputs::config http_output;
|
||||
falco_outputs::output_config http_output;
|
||||
http_output.name = "http";
|
||||
if(m_config->get_scalar<bool>("http_output", "enabled", false))
|
||||
{
|
||||
@@ -159,7 +159,7 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
|
||||
m_grpc_cert_chain = m_config->get_scalar<string>("grpc", "cert_chain", "/etc/falco/certs/server.crt");
|
||||
m_grpc_root_certs = m_config->get_scalar<string>("grpc", "root_certs", "/etc/falco/certs/ca.crt");
|
||||
|
||||
falco::outputs::config grpc_output;
|
||||
falco_outputs::output_config grpc_output;
|
||||
grpc_output.name = "grpc";
|
||||
// gRPC output is enabled only if gRPC server is enabled too
|
||||
if(m_config->get_scalar<bool>("grpc_output", "enabled", true) && m_grpc_enabled)
|
||||
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
{
|
||||
m_path = path;
|
||||
YAML::Node config;
|
||||
std::vector<falco::outputs::config> outputs;
|
||||
std::vector<falco_outputs::output_config> outputs;
|
||||
try
|
||||
{
|
||||
m_root = YAML::LoadFile(path);
|
||||
@@ -196,7 +196,7 @@ public:
|
||||
bool m_json_output;
|
||||
bool m_json_include_output_property;
|
||||
std::string m_log_level;
|
||||
std::vector<falco::outputs::config> m_outputs;
|
||||
std::vector<falco_outputs::output_config> m_outputs;
|
||||
uint32_t m_notifications_rate;
|
||||
uint32_t m_notifications_max_burst;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors.
|
||||
Copyright (C) 2019 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -15,7 +15,6 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
#include "event_drops.h"
|
||||
#include "falco_common.h"
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
syscall_evt_drop_mgr::syscall_evt_drop_mgr():
|
||||
@@ -138,7 +137,7 @@ bool syscall_evt_drop_mgr::perform_actions(uint64_t now, scap_stats &delta, bool
|
||||
|
||||
case ACT_ALERT:
|
||||
m_outputs->handle_msg(now,
|
||||
falco_common::PRIORITY_CRITICAL,
|
||||
falco_outputs::PRIORITY_CRITICAL,
|
||||
msg,
|
||||
rule,
|
||||
output_fields);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors.
|
||||
Copyright (C) 2019 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -36,14 +36,13 @@ limitations under the License.
|
||||
#include "logger.h"
|
||||
#include "utils.h"
|
||||
#include "chisel.h"
|
||||
#include "fields_info.h"
|
||||
#include "sysdig.h"
|
||||
|
||||
#include "event_drops.h"
|
||||
#include "configuration.h"
|
||||
#include "falco_engine.h"
|
||||
#include "config_falco.h"
|
||||
#include "statsfilewriter.h"
|
||||
#include "cli.h"
|
||||
#ifndef MINIMAL_BUILD
|
||||
#include "webserver.h"
|
||||
#include "grpc_server.h"
|
||||
@@ -75,102 +74,106 @@ static void restart_falco(int signal)
|
||||
g_restart = true;
|
||||
}
|
||||
|
||||
// //
|
||||
// // Program help
|
||||
// //
|
||||
// static void usage()
|
||||
// {
|
||||
// printf(
|
||||
// "Falco version: " FALCO_VERSION "\n"
|
||||
// "Usage: falco [options]\n\n"
|
||||
// "Options:\n"
|
||||
|
||||
// " -c Configuration file (default " FALCO_SOURCE_CONF_FILE ", " FALCO_INSTALL_CONF_FILE ")\n"
|
||||
// " -A Monitor all events, including those with EF_DROP_SIMPLE_CONS flag.\n"
|
||||
// " --alternate-lua-dir <path> Specify an alternate path for loading Falco lua files\n"
|
||||
// " -b, --print-base64 Print data buffers in base64.\n"
|
||||
// " This is useful for encoding binary data that needs to be used over media designed to.\n"
|
||||
// " --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"
|
||||
// " --disable-cri-async Disable asynchronous CRI metadata fetching.\n"
|
||||
// " This is useful to let the input event wait for the container metadata fetch\n"
|
||||
// " to finish before moving forward. Async fetching, in some environments leads\n"
|
||||
// " to empty fields for container metadata when the fetch is not fast enough to be\n"
|
||||
// " completed asynchronously. This can have a performance penalty on your environment\n"
|
||||
// " depending on the number of containers and the frequency at which they are created/started/stopped\n"
|
||||
// " --disable-source <event_source>\n"
|
||||
// " Disable a specific event source.\n"
|
||||
// " Available event sources are: syscall, k8s_audit.\n"
|
||||
// " It can be passed multiple times.\n"
|
||||
// " Can not disable both the event sources.\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"
|
||||
// #ifndef MINIMAL_BUILD
|
||||
// " -k <url>, --k8s-api <url>\n"
|
||||
// " Enable Kubernetes support by connecting to the API server specified as argument.\n"
|
||||
// " E.g. \"http://admin:password@127.0.0.1:8080\".\n"
|
||||
// " The API server can also be specified via the environment variable FALCO_K8S_API.\n"
|
||||
// " -K <bt_file> | <cert_file>:<key_file[#password]>[:<ca_cert_file>], --k8s-api-cert <bt_file> | <cert_file>:<key_file[#password]>[:<ca_cert_file>]\n"
|
||||
// " Use the provided files names to authenticate user and (optionally) verify the K8S API server identity.\n"
|
||||
// " Each entry must specify full (absolute, or relative to the current directory) path to the respective file.\n"
|
||||
// " Private key password is optional (needed only if key is password protected).\n"
|
||||
// " CA certificate is optional. For all files, only PEM file format is supported. \n"
|
||||
// " Specifying CA certificate only is obsoleted - when single entry is provided \n"
|
||||
// " for this option, it will be interpreted as the name of a file containing bearer token.\n"
|
||||
// " Note that the format of this command-line option prohibits use of files whose names contain\n"
|
||||
// " ':' or '#' characters in the file name.\n"
|
||||
// #endif
|
||||
|
||||
|
||||
|
||||
|
||||
// #ifndef MINIMAL_BUILD
|
||||
// " -m <url[,marathon_url]>, --mesos-api <url[,marathon_url]>\n"
|
||||
// " Enable Mesos support by connecting to the API server\n"
|
||||
// " specified as argument. E.g. \"http://admin:password@127.0.0.1:5050\".\n"
|
||||
// " Marathon url is optional and defaults to Mesos address, port 8080.\n"
|
||||
// " The API servers can also be specified via the environment variable FALCO_MESOS_API.\n"
|
||||
// #endif
|
||||
// " -M <num_seconds> Stop collecting after <num_seconds> reached.\n"
|
||||
|
||||
// " -o, --option <key>=<val> Set the value of option <key> to <val>. Overrides values in configuration file.\n"
|
||||
// " <key> can be a two-part <key>.<subkey>\n"
|
||||
// " -p <output_format>, --print <output_format>\n"
|
||||
// " Add additional information to each falco notification's output.\n"
|
||||
// " With -pc or -pcontainer will use a container-friendly format.\n"
|
||||
// " With -pk or -pkubernetes will use a kubernetes-friendly format.\n"
|
||||
// " With -pm or -pmesos will use a mesos-friendly format.\n"
|
||||
// " Additionally, specifying -pc/-pk/-pm will change the interpretation\n"
|
||||
// " of %%container.info in rule output fields.\n"
|
||||
// " -P, --pidfile <pid_file> When run as a daemon, write pid to specified file\n"
|
||||
// " -r <rules_file> Rules file/directory (defaults to value set in configuration file, or /etc/falco_rules.yaml).\n"
|
||||
// " Can be specified multiple times to read from multiple files/directories.\n"
|
||||
// " -s <stats_file> If specified, append statistics related to Falco's reading/processing of events\n"
|
||||
// " to this file (only useful in live mode).\n"
|
||||
// " --stats-interval <msec> When using -s <stats_file>, write statistics every <msec> ms.\n"
|
||||
// " This uses signals, so don't recommend intervals below 200 ms.\n"
|
||||
// " Defaults to 5000 (5 seconds).\n"
|
||||
// " -S <len>, --snaplen <len>\n"
|
||||
// " Capture the first <len> bytes of each I/O buffer.\n"
|
||||
// " By default, the first 80 bytes are captured. Use this\n"
|
||||
// " option with caution, it can generate huge trace files.\n"
|
||||
|
||||
|
||||
// " -U,--unbuffered Turn off output buffering to configured outputs.\n"
|
||||
// " This causes every single line emitted by falco to be flushed,\n"
|
||||
// " which generates higher CPU usage but is useful when piping those outputs\n"
|
||||
// " into another process or into a script.\n"
|
||||
// " -u, --userspace Parse events from userspace.\n"
|
||||
// " To be used in conjunction with the ptrace(2) based driver (pdig).\n"
|
||||
// " -V, --validate <rules_file> Read the contents of the specified rules(s) file and exit.\n"
|
||||
// " Can be specified multiple times to validate multiple files.\n"
|
||||
// " -v Verbose output.\n"
|
||||
|
||||
// "\n"
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// Program help
|
||||
//
|
||||
static void usage()
|
||||
{
|
||||
printf(
|
||||
"Falco version: " FALCO_VERSION "\n"
|
||||
"Usage: falco [options]\n\n"
|
||||
"Options:\n"
|
||||
" -h, --help Print this page\n"
|
||||
" -c Configuration file (default " FALCO_SOURCE_CONF_FILE ", " FALCO_INSTALL_CONF_FILE ")\n"
|
||||
" -A Monitor all events, including those with EF_DROP_SIMPLE_CONS flag.\n"
|
||||
" --alternate-lua-dir <path> Specify an alternate path for loading Falco lua files\n"
|
||||
" -b, --print-base64 Print data buffers in base64.\n"
|
||||
" This is useful for encoding binary data that needs to be used over media designed to.\n"
|
||||
" --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"
|
||||
" --disable-cri-async Disable asynchronous CRI metadata fetching.\n"
|
||||
" This is useful to let the input event wait for the container metadata fetch\n"
|
||||
" to finish before moving forward. Async fetching, in some environments leads\n"
|
||||
" to empty fields for container metadata when the fetch is not fast enough to be\n"
|
||||
" completed asynchronously. This can have a performance penalty on your environment\n"
|
||||
" depending on the number of containers and the frequency at which they are created/started/stopped\n"
|
||||
" --disable-source <event_source>\n"
|
||||
" Disable a specific event source.\n"
|
||||
" Available event sources are: syscall, k8s_audit.\n"
|
||||
" It can be passed multiple times.\n"
|
||||
" Can not disable both the event sources.\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"
|
||||
#ifndef MINIMAL_BUILD
|
||||
" -k <url>, --k8s-api <url>\n"
|
||||
" Enable Kubernetes support by connecting to the API server specified as argument.\n"
|
||||
" E.g. \"http://admin:password@127.0.0.1:8080\".\n"
|
||||
" The API server can also be specified via the environment variable FALCO_K8S_API.\n"
|
||||
" -K <bt_file> | <cert_file>:<key_file[#password]>[:<ca_cert_file>], --k8s-api-cert <bt_file> | <cert_file>:<key_file[#password]>[:<ca_cert_file>]\n"
|
||||
" Use the provided files names to authenticate user and (optionally) verify the K8S API server identity.\n"
|
||||
" Each entry must specify full (absolute, or relative to the current directory) path to the respective file.\n"
|
||||
" Private key password is optional (needed only if key is password protected).\n"
|
||||
" CA certificate is optional. For all files, only PEM file format is supported. \n"
|
||||
" Specifying CA certificate only is obsoleted - when single entry is provided \n"
|
||||
" for this option, it will be interpreted as the name of a file containing bearer token.\n"
|
||||
" Note that the format of this command-line option prohibits use of files whose names contain\n"
|
||||
" ':' or '#' characters in the file name.\n"
|
||||
#endif
|
||||
" -L Show the name and description of all rules and exit.\n"
|
||||
" -l <rule> Show the name and description of the rule with name <rule> and exit.\n"
|
||||
" --list [<source>] List all defined fields. If <source> is provided, only list those fields for\n"
|
||||
" the source <source>. Current values for <source> are \"syscall\", \"k8s_audit\"\n"
|
||||
#ifndef MINIMAL_BUILD
|
||||
" -m <url[,marathon_url]>, --mesos-api <url[,marathon_url]>\n"
|
||||
" Enable Mesos support by connecting to the API server\n"
|
||||
" specified as argument. E.g. \"http://admin:password@127.0.0.1:5050\".\n"
|
||||
" Marathon url is optional and defaults to Mesos address, port 8080.\n"
|
||||
" The API servers can also be specified via the environment variable FALCO_MESOS_API.\n"
|
||||
#endif
|
||||
" -M <num_seconds> Stop collecting after <num_seconds> reached.\n"
|
||||
" -N When used with --list, only print field names.\n"
|
||||
" -o, --option <key>=<val> Set the value of option <key> to <val>. Overrides values in configuration file.\n"
|
||||
" <key> can be a two-part <key>.<subkey>\n"
|
||||
" -p <output_format>, --print <output_format>\n"
|
||||
" Add additional information to each falco notification's output.\n"
|
||||
" With -pc or -pcontainer will use a container-friendly format.\n"
|
||||
" With -pk or -pkubernetes will use a kubernetes-friendly format.\n"
|
||||
" With -pm or -pmesos will use a mesos-friendly format.\n"
|
||||
" Additionally, specifying -pc/-pk/-pm will change the interpretation\n"
|
||||
" of %%container.info in rule output fields.\n"
|
||||
" -P, --pidfile <pid_file> When run as a daemon, write pid to specified file\n"
|
||||
" -r <rules_file> Rules file/directory (defaults to value set in configuration file, or /etc/falco_rules.yaml).\n"
|
||||
" Can be specified multiple times to read from multiple files/directories.\n"
|
||||
" -s <stats_file> If specified, append statistics related to Falco's reading/processing of events\n"
|
||||
" to this file (only useful in live mode).\n"
|
||||
" --stats-interval <msec> When using -s <stats_file>, write statistics every <msec> ms.\n"
|
||||
" This uses signals, so don't recommend intervals below 200 ms.\n"
|
||||
" Defaults to 5000 (5 seconds).\n"
|
||||
" -S <len>, --snaplen <len>\n"
|
||||
" Capture the first <len> bytes of each I/O buffer.\n"
|
||||
" By default, the first 80 bytes are captured. Use this\n"
|
||||
" option with caution, it can generate huge trace files.\n"
|
||||
" --support Print support information including version, rules files used, etc. and exit.\n"
|
||||
" -T <tag> Disable any rules with a tag=<tag>. Can be specified multiple times.\n"
|
||||
" Can not be specified with -t.\n"
|
||||
" -t <tag> Only run those rules with a tag=<tag>. Can be specified multiple times.\n"
|
||||
" Can not be specified with -T/-D.\n"
|
||||
" -U,--unbuffered Turn off output buffering to configured outputs.\n"
|
||||
" This causes every single line emitted by falco to be flushed,\n"
|
||||
" which generates higher CPU usage but is useful when piping those outputs\n"
|
||||
" into another process or into a script.\n"
|
||||
" -u, --userspace Parse events from userspace.\n"
|
||||
" To be used in conjunction with the ptrace(2) based driver (pdig).\n"
|
||||
" -V, --validate <rules_file> Read the contents of the specified rules(s) file and exit.\n"
|
||||
" Can be specified multiple times to validate multiple files.\n"
|
||||
" -v Verbose output.\n"
|
||||
" --version Print version number.\n"
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
|
||||
static void display_fatal_err(const string &msg)
|
||||
{
|
||||
@@ -392,7 +395,8 @@ static void print_all_ignored_events(sinsp *inspector)
|
||||
|
||||
static void list_source_fields(falco_engine *engine, bool verbose, bool names_only, std::string &source)
|
||||
{
|
||||
if(!source.empty() && !(source == "syscall" || source == "k8s_audit"))
|
||||
if(source.size() > 0 &&
|
||||
!(source == "syscall" || source == "k8s_audit"))
|
||||
{
|
||||
throw std::invalid_argument("Value for --list must be \"syscall\" or \"k8s_audit\"");
|
||||
}
|
||||
@@ -409,7 +413,7 @@ static void list_source_fields(falco_engine *engine, bool verbose, bool names_on
|
||||
//
|
||||
// ARGUMENT PARSING AND PROGRAM SETUP
|
||||
//
|
||||
int falco_init()
|
||||
int falco_init(int argc, char **argv)
|
||||
{
|
||||
int result = EXIT_SUCCESS;
|
||||
sinsp* inspector = NULL;
|
||||
@@ -510,197 +514,198 @@ int falco_init()
|
||||
set<string> disabled_rule_tags;
|
||||
set<string> enabled_rule_tags;
|
||||
|
||||
// //
|
||||
// // Parse the args
|
||||
// //
|
||||
// while((op = getopt_long(argc, argv,
|
||||
// "hc:AbdD:e:F:ik:K:Ll:m:M:No:P:p:r:S:s:T:t:UuvV:w:",
|
||||
// long_options, &long_index)) != -1)
|
||||
// {
|
||||
// switch(op)
|
||||
// {
|
||||
// case 'h':
|
||||
// usage();
|
||||
// goto exit;
|
||||
// case 'c':
|
||||
// conf_filename = optarg;
|
||||
// break;
|
||||
// case 'A':
|
||||
// all_events = true;
|
||||
// break;
|
||||
// case 'b':
|
||||
// event_buffer_format = sinsp_evt::PF_BASE64;
|
||||
// break;
|
||||
// case 'd':
|
||||
// daemon = true;
|
||||
// break;
|
||||
// case 'D':
|
||||
// substring = optarg;
|
||||
// disabled_rule_substrings.insert(substring);
|
||||
// break;
|
||||
// case 'e':
|
||||
// trace_filename = optarg;
|
||||
// #ifndef MINIMAL_BUILD
|
||||
// k8s_api = new string();
|
||||
// mesos_api = new string();
|
||||
// #endif
|
||||
// break;
|
||||
// case 'F':
|
||||
// list_flds = optarg;
|
||||
// break;
|
||||
// case 'i':
|
||||
// print_ignored_events = true;
|
||||
// break;
|
||||
// #ifndef MINIMAL_BUILD
|
||||
// case 'k':
|
||||
// k8s_api = new string(optarg);
|
||||
// break;
|
||||
// case 'K':
|
||||
// k8s_api_cert = new string(optarg);
|
||||
// break;
|
||||
// #endif
|
||||
// case 'L':
|
||||
// describe_all_rules = true;
|
||||
// break;
|
||||
// case 'l':
|
||||
// describe_rule = optarg;
|
||||
// break;
|
||||
// #ifndef MINIMAL_BUILD
|
||||
// case 'm':
|
||||
// mesos_api = new string(optarg);
|
||||
// break;
|
||||
// #endif
|
||||
// case 'M':
|
||||
// duration_to_tot = atoi(optarg);
|
||||
// if(duration_to_tot <= 0)
|
||||
// {
|
||||
// throw sinsp_exception(string("invalid duration") + optarg);
|
||||
// }
|
||||
// break;
|
||||
// case 'N':
|
||||
// names_only = true;
|
||||
// break;
|
||||
// case 'o':
|
||||
// cmdline_options.push_back(optarg);
|
||||
// break;
|
||||
// case 'P':
|
||||
// pidfilename = optarg;
|
||||
// break;
|
||||
// case 'p':
|
||||
// if(string(optarg) == "c" || string(optarg) == "container")
|
||||
// {
|
||||
// output_format = "container=%container.name (id=%container.id)";
|
||||
// replace_container_info = true;
|
||||
// }
|
||||
// else if(string(optarg) == "k" || string(optarg) == "kubernetes")
|
||||
// {
|
||||
// output_format = "k8s.ns=%k8s.ns.name k8s.pod=%k8s.pod.name container=%container.id";
|
||||
// replace_container_info = true;
|
||||
// }
|
||||
// else if(string(optarg) == "m" || string(optarg) == "mesos")
|
||||
// {
|
||||
// output_format = "task=%mesos.task.name container=%container.id";
|
||||
// replace_container_info = true;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// output_format = optarg;
|
||||
// replace_container_info = false;
|
||||
// }
|
||||
// break;
|
||||
// case 'r':
|
||||
// falco_configuration::read_rules_file_directory(string(optarg), rules_filenames);
|
||||
// break;
|
||||
// case 'S':
|
||||
// snaplen = atoi(optarg);
|
||||
// break;
|
||||
// case 's':
|
||||
// stats_filename = optarg;
|
||||
// break;
|
||||
// case 'T':
|
||||
// disabled_rule_tags.insert(optarg);
|
||||
// break;
|
||||
// case 't':
|
||||
// enabled_rule_tags.insert(optarg);
|
||||
// break;
|
||||
// case 'U':
|
||||
// buffered_outputs = false;
|
||||
// buffered_cmdline = true;
|
||||
// break;
|
||||
// case 'u':
|
||||
// userspace = true;
|
||||
// break;
|
||||
// case 'v':
|
||||
// verbose = true;
|
||||
// break;
|
||||
// case 'V':
|
||||
// validate_rules_filenames.push_back(optarg);
|
||||
// break;
|
||||
// case 'w':
|
||||
// outfile = optarg;
|
||||
// break;
|
||||
// case '?':
|
||||
// result = EXIT_FAILURE;
|
||||
// goto exit;
|
||||
//
|
||||
// Parse the args
|
||||
//
|
||||
while((op = getopt_long(argc, argv,
|
||||
"hc:AbdD:e:F:ik:K:Ll:m:M:No:P:p:r:S:s:T:t:UuvV:w:",
|
||||
long_options, &long_index)) != -1)
|
||||
{
|
||||
switch(op)
|
||||
{
|
||||
case 'h':
|
||||
usage();
|
||||
goto exit;
|
||||
case 'c':
|
||||
conf_filename = optarg;
|
||||
break;
|
||||
case 'A':
|
||||
all_events = true;
|
||||
break;
|
||||
case 'b':
|
||||
event_buffer_format = sinsp_evt::PF_BASE64;
|
||||
break;
|
||||
case 'd':
|
||||
daemon = true;
|
||||
break;
|
||||
case 'D':
|
||||
substring = optarg;
|
||||
disabled_rule_substrings.insert(substring);
|
||||
break;
|
||||
case 'e':
|
||||
trace_filename = optarg;
|
||||
#ifndef MINIMAL_BUILD
|
||||
k8s_api = new string();
|
||||
mesos_api = new string();
|
||||
#endif
|
||||
break;
|
||||
case 'F':
|
||||
list_flds = optarg;
|
||||
break;
|
||||
case 'i':
|
||||
print_ignored_events = true;
|
||||
break;
|
||||
#ifndef MINIMAL_BUILD
|
||||
case 'k':
|
||||
k8s_api = new string(optarg);
|
||||
break;
|
||||
case 'K':
|
||||
k8s_api_cert = new string(optarg);
|
||||
break;
|
||||
#endif
|
||||
case 'L':
|
||||
describe_all_rules = true;
|
||||
break;
|
||||
case 'l':
|
||||
describe_rule = optarg;
|
||||
break;
|
||||
#ifndef MINIMAL_BUILD
|
||||
case 'm':
|
||||
mesos_api = new string(optarg);
|
||||
break;
|
||||
#endif
|
||||
case 'M':
|
||||
duration_to_tot = atoi(optarg);
|
||||
if(duration_to_tot <= 0)
|
||||
{
|
||||
throw sinsp_exception(string("invalid duration") + optarg);
|
||||
}
|
||||
break;
|
||||
case 'N':
|
||||
names_only = true;
|
||||
break;
|
||||
case 'o':
|
||||
cmdline_options.push_back(optarg);
|
||||
break;
|
||||
case 'P':
|
||||
pidfilename = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
if(string(optarg) == "c" || string(optarg) == "container")
|
||||
{
|
||||
output_format = "container=%container.name (id=%container.id)";
|
||||
replace_container_info = true;
|
||||
}
|
||||
else if(string(optarg) == "k" || string(optarg) == "kubernetes")
|
||||
{
|
||||
output_format = "k8s.ns=%k8s.ns.name k8s.pod=%k8s.pod.name container=%container.id";
|
||||
replace_container_info = true;
|
||||
}
|
||||
else if(string(optarg) == "m" || string(optarg) == "mesos")
|
||||
{
|
||||
output_format = "task=%mesos.task.name container=%container.id";
|
||||
replace_container_info = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
output_format = optarg;
|
||||
replace_container_info = false;
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
falco_configuration::read_rules_file_directory(string(optarg), rules_filenames);
|
||||
break;
|
||||
case 'S':
|
||||
snaplen = atoi(optarg);
|
||||
break;
|
||||
case 's':
|
||||
stats_filename = optarg;
|
||||
break;
|
||||
case 'T':
|
||||
disabled_rule_tags.insert(optarg);
|
||||
break;
|
||||
case 't':
|
||||
enabled_rule_tags.insert(optarg);
|
||||
break;
|
||||
case 'U':
|
||||
buffered_outputs = false;
|
||||
buffered_cmdline = true;
|
||||
break;
|
||||
case 'u':
|
||||
userspace = true;
|
||||
break;
|
||||
case 'v':
|
||||
verbose = true;
|
||||
break;
|
||||
case 'V':
|
||||
validate_rules_filenames.push_back(optarg);
|
||||
break;
|
||||
case 'w':
|
||||
outfile = optarg;
|
||||
break;
|
||||
case '?':
|
||||
result = EXIT_FAILURE;
|
||||
goto exit;
|
||||
|
||||
// case 0:
|
||||
// if(string(long_options[long_index].name) == "version")
|
||||
// {
|
||||
// printf("Falco version: %s\n", FALCO_VERSION);
|
||||
// printf("Driver version: %s\n", DRIVER_VERSION);
|
||||
// return EXIT_SUCCESS;
|
||||
// }
|
||||
// else if (string(long_options[long_index].name) == "cri")
|
||||
// {
|
||||
// if(optarg != NULL)
|
||||
// {
|
||||
// cri_socket_path = optarg;
|
||||
// }
|
||||
// }
|
||||
// else if (string(long_options[long_index].name) == "disable-cri-async")
|
||||
// {
|
||||
// cri_async = false;
|
||||
// }
|
||||
// else if (string(long_options[long_index].name) == "list")
|
||||
// {
|
||||
// list_flds = true;
|
||||
// if(optarg != NULL)
|
||||
// {
|
||||
// list_flds_source = optarg;
|
||||
// }
|
||||
// }
|
||||
// else if (string(long_options[long_index].name) == "stats-interval")
|
||||
// {
|
||||
// stats_interval = atoi(optarg);
|
||||
// }
|
||||
// else if (string(long_options[long_index].name) == "support")
|
||||
// {
|
||||
// print_support = true;
|
||||
// }
|
||||
// else if (string(long_options[long_index].name) == "disable-source")
|
||||
// {
|
||||
// if(optarg != NULL)
|
||||
// {
|
||||
// disable_sources.insert(optarg);
|
||||
// }
|
||||
// }
|
||||
// else if (string(long_options[long_index].name)== "alternate-lua-dir")
|
||||
// {
|
||||
// if(optarg != NULL)
|
||||
// {
|
||||
// alternate_lua_dir = optarg;
|
||||
// if (alternate_lua_dir.back() != '/') {
|
||||
// alternate_lua_dir += '/';
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// break;
|
||||
case 0:
|
||||
if(string(long_options[long_index].name) == "version")
|
||||
{
|
||||
printf("Falco version: %s\n", FALCO_VERSION);
|
||||
printf("Driver version: %s\n", DRIVER_VERSION);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
else if (string(long_options[long_index].name) == "cri")
|
||||
{
|
||||
if(optarg != NULL)
|
||||
{
|
||||
cri_socket_path = optarg;
|
||||
}
|
||||
}
|
||||
else if (string(long_options[long_index].name) == "disable-cri-async")
|
||||
{
|
||||
cri_async = false;
|
||||
}
|
||||
else if (string(long_options[long_index].name) == "list")
|
||||
{
|
||||
list_flds = true;
|
||||
if(optarg != NULL)
|
||||
{
|
||||
list_flds_source = optarg;
|
||||
}
|
||||
}
|
||||
else if (string(long_options[long_index].name) == "stats-interval")
|
||||
{
|
||||
stats_interval = atoi(optarg);
|
||||
}
|
||||
else if (string(long_options[long_index].name) == "support")
|
||||
{
|
||||
print_support = true;
|
||||
}
|
||||
else if (string(long_options[long_index].name) == "disable-source")
|
||||
{
|
||||
if(optarg != NULL)
|
||||
{
|
||||
disable_sources.insert(optarg);
|
||||
}
|
||||
}
|
||||
else if (string(long_options[long_index].name)== "alternate-lua-dir")
|
||||
{
|
||||
if(optarg != NULL)
|
||||
{
|
||||
alternate_lua_dir = optarg;
|
||||
if (alternate_lua_dir.back() != '/') {
|
||||
alternate_lua_dir += '/';
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// }
|
||||
inspector = new sinsp();
|
||||
inspector->set_buffer_format(event_buffer_format);
|
||||
|
||||
@@ -757,7 +762,8 @@ int falco_init()
|
||||
}
|
||||
}
|
||||
|
||||
outputs = new falco_outputs();
|
||||
outputs = new falco_outputs(engine);
|
||||
outputs->set_inspector(inspector);
|
||||
|
||||
// Some combinations of arguments are not allowed.
|
||||
if (daemon && pidfilename == "") {
|
||||
@@ -810,7 +816,7 @@ int falco_init()
|
||||
}
|
||||
catch(falco_exception &e)
|
||||
{
|
||||
printf("%s%s\n", prefix.c_str(), e.what());
|
||||
printf("%s%s", prefix.c_str(), e.what());
|
||||
throw;
|
||||
}
|
||||
printf("%sOk\n", prefix.c_str());
|
||||
@@ -867,7 +873,15 @@ int falco_init()
|
||||
falco_logger::log(LOG_INFO, "Loading rules from file " + filename + ":\n");
|
||||
uint64_t required_engine_version;
|
||||
|
||||
engine->load_rules_file(filename, verbose, all_events, required_engine_version);
|
||||
try {
|
||||
engine->load_rules_file(filename, verbose, all_events, required_engine_version);
|
||||
}
|
||||
catch(falco_exception &e)
|
||||
{
|
||||
std::string prefix = "Could not load rules file " + filename + ": ";
|
||||
|
||||
throw falco_exception(prefix + e.what());
|
||||
}
|
||||
required_engine_versions[filename] = required_engine_version;
|
||||
}
|
||||
|
||||
@@ -916,14 +930,14 @@ int falco_init()
|
||||
throw std::runtime_error(string("Could not uname() to find system info: %s\n") + strerror(errno));
|
||||
}
|
||||
|
||||
// for(char **arg = argv; *arg; arg++)
|
||||
// {
|
||||
// if(cmdline.size() > 0)
|
||||
// {
|
||||
// cmdline += " ";
|
||||
// }
|
||||
// cmdline += *arg;
|
||||
// }
|
||||
for(char **arg = argv; *arg; arg++)
|
||||
{
|
||||
if(cmdline.size() > 0)
|
||||
{
|
||||
cmdline += " ";
|
||||
}
|
||||
cmdline += *arg;
|
||||
}
|
||||
|
||||
support["version"] = FALCO_VERSION;
|
||||
support["system_info"]["sysname"] = sysinfo.sysname;
|
||||
@@ -965,12 +979,14 @@ int falco_init()
|
||||
hostname = c_hostname;
|
||||
}
|
||||
|
||||
|
||||
outputs->init(config.m_json_output,
|
||||
config.m_json_include_output_property,
|
||||
config.m_notifications_rate, config.m_notifications_max_burst,
|
||||
config.m_buffered_outputs,
|
||||
config.m_time_format_iso_8601,
|
||||
hostname);
|
||||
hostname,
|
||||
alternate_lua_dir);
|
||||
|
||||
if(!all_events)
|
||||
{
|
||||
@@ -1373,23 +1389,13 @@ exit:
|
||||
//
|
||||
// MAIN
|
||||
//
|
||||
int main(int argc, const char **argv)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto cli = new falco::cli(argc, argv);
|
||||
cli->run();
|
||||
}
|
||||
catch(const cxxopts::OptionException &e)
|
||||
{
|
||||
display_fatal_err("Error parsing options: " + string(e.what()) + "\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
int rc;
|
||||
|
||||
// g_restart will cause the falco loop to exit, but we
|
||||
// should reload everything and start over.
|
||||
while((rc = falco_init()) == EXIT_SUCCESS && g_restart)
|
||||
while((rc = falco_init(argc, argv)) == EXIT_SUCCESS && g_restart)
|
||||
{
|
||||
g_restart = false;
|
||||
optind = 1;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors.
|
||||
Copyright (C) 2019 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -24,21 +24,24 @@ limitations under the License.
|
||||
|
||||
#include "formats.h"
|
||||
#include "logger.h"
|
||||
|
||||
#include "outputs_file.h"
|
||||
#include "outputs_program.h"
|
||||
#include "outputs_stdout.h"
|
||||
#include "outputs_syslog.h"
|
||||
#ifndef MINIMAL_BUILD
|
||||
#include "outputs_http.h"
|
||||
#include "outputs_grpc.h"
|
||||
#include "falco_outputs_queue.h"
|
||||
#endif
|
||||
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
using namespace std;
|
||||
|
||||
falco_outputs::falco_outputs():
|
||||
const static struct luaL_reg ll_falco_outputs [] =
|
||||
{
|
||||
#ifndef MINIMAL_BUILD
|
||||
{"handle_http", &falco_outputs::handle_http},
|
||||
{"handle_grpc", &falco_outputs::handle_grpc},
|
||||
#endif
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
falco_outputs::falco_outputs(falco_engine *engine):
|
||||
m_falco_engine(engine),
|
||||
m_initialized(false),
|
||||
m_buffered(true),
|
||||
m_json_output(false),
|
||||
@@ -49,11 +52,25 @@ falco_outputs::falco_outputs():
|
||||
|
||||
falco_outputs::~falco_outputs()
|
||||
{
|
||||
// Note: The assert()s in this destructor were previously places where
|
||||
// exceptions were thrown. C++11 doesn't allow destructors to
|
||||
// emit exceptions; if they're thrown, they'll trigger a call
|
||||
// to 'terminate()'. To maintain similar behavior, the exceptions
|
||||
// were replace with calls to 'assert()'
|
||||
if(m_initialized)
|
||||
{
|
||||
for(auto it = m_outputs.cbegin(); it != m_outputs.cend(); ++it)
|
||||
lua_getglobal(m_ls, m_lua_output_cleanup.c_str());
|
||||
if(!lua_isfunction(m_ls, -1))
|
||||
{
|
||||
(*it)->cleanup();
|
||||
falco_logger::log(LOG_ERR, std::string("No function ") + m_lua_output_cleanup + " found. ");
|
||||
assert(nullptr == "Missing lua cleanup function in ~falco_outputs");
|
||||
}
|
||||
|
||||
if(lua_pcall(m_ls, 0, 0, 0) != 0)
|
||||
{
|
||||
const char *lerr = lua_tostring(m_ls, -1);
|
||||
falco_logger::log(LOG_ERR, std::string("lua_pcall failed, err: ") + lerr);
|
||||
assert(nullptr == "lua_pcall failed in ~falco_outputs");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,15 +78,27 @@ falco_outputs::~falco_outputs()
|
||||
void falco_outputs::init(bool json_output,
|
||||
bool json_include_output_property,
|
||||
uint32_t rate, uint32_t max_burst, bool buffered,
|
||||
bool time_format_iso_8601, string hostname)
|
||||
bool time_format_iso_8601, string hostname,
|
||||
const string& alternate_lua_dir)
|
||||
{
|
||||
// The engine must have been given an inspector by now.
|
||||
if(!m_inspector)
|
||||
{
|
||||
throw falco_exception("No inspector provided");
|
||||
}
|
||||
|
||||
m_json_output = json_output;
|
||||
|
||||
// Note that falco_formats is already initialized by the engine,
|
||||
// and the following json options are not used within the engine.
|
||||
// So we can safely update them.
|
||||
falco_formats::s_json_output = json_output;
|
||||
falco_formats::s_json_include_output_property = json_include_output_property;
|
||||
falco_common::init(m_lua_main_filename.c_str(), alternate_lua_dir.c_str());
|
||||
|
||||
// Note that falco_formats is added to both the lua state used
|
||||
// by the falco engine as well as the separate lua state used
|
||||
// by falco outputs.
|
||||
falco_formats::init(m_inspector, m_falco_engine, m_ls, json_output, json_include_output_property);
|
||||
|
||||
falco_logger::init(m_ls);
|
||||
|
||||
luaL_openlib(m_ls, "c_outputs", ll_falco_outputs, 0);
|
||||
|
||||
m_notifications_tb.init(rate, max_burst);
|
||||
|
||||
@@ -80,47 +109,40 @@ void falco_outputs::init(bool json_output,
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
void falco_outputs::add_output(falco::outputs::config oc)
|
||||
void falco_outputs::add_output(output_config oc)
|
||||
{
|
||||
uint8_t nargs = 3;
|
||||
lua_getglobal(m_ls, m_lua_add_output.c_str());
|
||||
|
||||
falco::outputs::abstract_output *oo;
|
||||
if(!lua_isfunction(m_ls, -1))
|
||||
{
|
||||
throw falco_exception("No function " + m_lua_add_output + " found. ");
|
||||
}
|
||||
lua_pushstring(m_ls, oc.name.c_str());
|
||||
lua_pushnumber(m_ls, (m_buffered ? 1 : 0));
|
||||
lua_pushnumber(m_ls, (m_time_format_iso_8601 ? 1 : 0));
|
||||
|
||||
if(oc.name == "file")
|
||||
// If we have options, build up a lua table containing them
|
||||
if(oc.options.size())
|
||||
{
|
||||
oo = new falco::outputs::output_file();
|
||||
}
|
||||
else if(oc.name == "program")
|
||||
{
|
||||
oo = new falco::outputs::output_program();
|
||||
}
|
||||
else if(oc.name == "stdout")
|
||||
{
|
||||
oo = new falco::outputs::output_stdout();
|
||||
}
|
||||
else if(oc.name == "syslog")
|
||||
{
|
||||
oo = new falco::outputs::output_syslog();
|
||||
}
|
||||
#ifndef MINIMAL_BUILD
|
||||
else if(oc.name == "http")
|
||||
{
|
||||
oo = new falco::outputs::output_http();
|
||||
}
|
||||
else if(oc.name == "grpc")
|
||||
{
|
||||
oo = new falco::outputs::output_grpc();
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
throw falco_exception("Output not supported: " + oc.name);
|
||||
nargs = 4;
|
||||
lua_createtable(m_ls, 0, oc.options.size());
|
||||
|
||||
for(auto it = oc.options.cbegin(); it != oc.options.cend(); ++it)
|
||||
{
|
||||
lua_pushstring(m_ls, (*it).second.c_str());
|
||||
lua_setfield(m_ls, -2, (*it).first.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
oo->init(oc, m_buffered, m_hostname);
|
||||
m_outputs.push_back(oo);
|
||||
if(lua_pcall(m_ls, nargs, 0, 0) != 0)
|
||||
{
|
||||
const char *lerr = lua_tostring(m_ls, -1);
|
||||
throw falco_exception(string(lerr));
|
||||
}
|
||||
}
|
||||
|
||||
void falco_outputs::handle_event(gen_event *evt, string &rule, string &source,
|
||||
void falco_outputs::handle_event(gen_event *ev, string &rule, string &source,
|
||||
falco_common::priority_type priority, string &format)
|
||||
{
|
||||
if(!m_notifications_tb.claim())
|
||||
@@ -129,46 +151,29 @@ void falco_outputs::handle_event(gen_event *evt, string &rule, string &source,
|
||||
return;
|
||||
}
|
||||
|
||||
string sformat;
|
||||
if(source == "syscall")
|
||||
std::lock_guard<std::mutex> guard(m_ls_semaphore);
|
||||
lua_getglobal(m_ls, m_lua_output_event.c_str());
|
||||
|
||||
if(lua_isfunction(m_ls, -1))
|
||||
{
|
||||
if(m_time_format_iso_8601)
|
||||
lua_pushlightuserdata(m_ls, ev);
|
||||
lua_pushstring(m_ls, rule.c_str());
|
||||
lua_pushstring(m_ls, source.c_str());
|
||||
lua_pushstring(m_ls, falco_common::priority_names[priority].c_str());
|
||||
lua_pushnumber(m_ls, priority);
|
||||
lua_pushstring(m_ls, format.c_str());
|
||||
lua_pushstring(m_ls, m_hostname.c_str());
|
||||
|
||||
if(lua_pcall(m_ls, 7, 0, 0) != 0)
|
||||
{
|
||||
sformat = "*%evt.time.iso8601: " + falco_common::priority_names[priority];
|
||||
}
|
||||
else
|
||||
{
|
||||
sformat = "*%evt.time: " + falco_common::priority_names[priority];
|
||||
const char *lerr = lua_tostring(m_ls, -1);
|
||||
string err = "Error invoking function output: " + string(lerr);
|
||||
throw falco_exception(err);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_time_format_iso_8601)
|
||||
{
|
||||
sformat = "*%jevt.time.iso8601: " + falco_common::priority_names[priority];
|
||||
}
|
||||
else
|
||||
{
|
||||
sformat = "*%jevt.time: " + falco_common::priority_names[priority];
|
||||
}
|
||||
}
|
||||
|
||||
// if format starts with a *, remove it, as we added our own prefix
|
||||
if(format[0] == '*')
|
||||
{
|
||||
sformat += " " + format.substr(1, format.length() - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
sformat += " " + format;
|
||||
}
|
||||
|
||||
string msg;
|
||||
msg = falco_formats::format_event(evt, rule, source, falco_common::priority_names[priority], sformat);
|
||||
|
||||
for(auto it = m_outputs.cbegin(); it != m_outputs.cend(); ++it)
|
||||
{
|
||||
(*it)->output_event(evt, rule, source, priority, sformat, msg);
|
||||
throw falco_exception("No function " + m_lua_output_event + " found in lua compiler module");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,7 +201,7 @@ void falco_outputs::handle_msg(uint64_t now,
|
||||
iso8601evttime += time_ns;
|
||||
|
||||
jmsg["output"] = msg;
|
||||
jmsg["priority"] = falco_common::priority_names[priority];
|
||||
jmsg["priority"] = "Critical";
|
||||
jmsg["rule"] = rule;
|
||||
jmsg["time"] = iso8601evttime;
|
||||
jmsg["output_fields"] = output_fields;
|
||||
@@ -209,7 +214,7 @@ void falco_outputs::handle_msg(uint64_t now,
|
||||
bool first = true;
|
||||
|
||||
sinsp_utils::ts_to_string(now, ×tr, false, true);
|
||||
full_msg = timestr + ": " + falco_common::priority_names[priority] + " " + msg + " (";
|
||||
full_msg = timestr + ": " + falco_common::priority_names[LOG_CRIT] + " " + msg + " (";
|
||||
for(auto &pair : output_fields)
|
||||
{
|
||||
if(first)
|
||||
@@ -225,16 +230,151 @@ void falco_outputs::handle_msg(uint64_t now,
|
||||
full_msg += ")";
|
||||
}
|
||||
|
||||
for(auto it = m_outputs.cbegin(); it != m_outputs.cend(); ++it)
|
||||
std::lock_guard<std::mutex> guard(m_ls_semaphore);
|
||||
lua_getglobal(m_ls, m_lua_output_msg.c_str());
|
||||
if(lua_isfunction(m_ls, -1))
|
||||
{
|
||||
(*it)->output_msg(priority, full_msg);
|
||||
lua_pushstring(m_ls, full_msg.c_str());
|
||||
lua_pushstring(m_ls, falco_common::priority_names[priority].c_str());
|
||||
lua_pushnumber(m_ls, priority);
|
||||
|
||||
if(lua_pcall(m_ls, 3, 0, 0) != 0)
|
||||
{
|
||||
const char *lerr = lua_tostring(m_ls, -1);
|
||||
string err = "Error invoking function output: " + string(lerr);
|
||||
throw falco_exception(err);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw falco_exception("No function " + m_lua_output_msg + " found in lua compiler module");
|
||||
}
|
||||
}
|
||||
|
||||
void falco_outputs::reopen_outputs()
|
||||
{
|
||||
for(auto it = m_outputs.cbegin(); it != m_outputs.cend(); ++it)
|
||||
lua_getglobal(m_ls, m_lua_output_reopen.c_str());
|
||||
if(!lua_isfunction(m_ls, -1))
|
||||
{
|
||||
(*it)->reopen();
|
||||
throw falco_exception("No function " + m_lua_output_reopen + " found. ");
|
||||
}
|
||||
|
||||
if(lua_pcall(m_ls, 0, 0, 0) != 0)
|
||||
{
|
||||
const char *lerr = lua_tostring(m_ls, -1);
|
||||
throw falco_exception(string(lerr));
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef MINIMAL_BUILD
|
||||
int falco_outputs::handle_http(lua_State *ls)
|
||||
{
|
||||
CURL *curl = NULL;
|
||||
CURLcode res = CURLE_FAILED_INIT;
|
||||
struct curl_slist *slist1;
|
||||
slist1 = NULL;
|
||||
|
||||
if(!lua_isstring(ls, -1) ||
|
||||
!lua_isstring(ls, -2))
|
||||
{
|
||||
lua_pushstring(ls, "Invalid arguments passed to handle_http()");
|
||||
lua_error(ls);
|
||||
}
|
||||
|
||||
string url = (char *)lua_tostring(ls, 1);
|
||||
string msg = (char *)lua_tostring(ls, 2);
|
||||
|
||||
curl = curl_easy_init();
|
||||
if(curl)
|
||||
{
|
||||
slist1 = curl_slist_append(slist1, "Content-Type: application/json");
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, msg.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, -1L);
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
if(res != CURLE_OK)
|
||||
{
|
||||
falco_logger::log(LOG_ERR, "libcurl error: " + string(curl_easy_strerror(res)));
|
||||
}
|
||||
curl_easy_cleanup(curl);
|
||||
curl = NULL;
|
||||
curl_slist_free_all(slist1);
|
||||
slist1 = NULL;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int falco_outputs::handle_grpc(lua_State *ls)
|
||||
{
|
||||
// check parameters
|
||||
if(!lua_islightuserdata(ls, -8) ||
|
||||
!lua_isstring(ls, -7) ||
|
||||
!lua_isstring(ls, -6) ||
|
||||
!lua_isstring(ls, -5) ||
|
||||
!lua_isstring(ls, -4) ||
|
||||
!lua_istable(ls, -3) ||
|
||||
!lua_isstring(ls, -2) ||
|
||||
!lua_istable(ls, -1))
|
||||
{
|
||||
lua_pushstring(ls, "Invalid arguments passed to handle_grpc()");
|
||||
lua_error(ls);
|
||||
}
|
||||
|
||||
falco::outputs::response grpc_res;
|
||||
|
||||
// time
|
||||
gen_event *evt = (gen_event *)lua_topointer(ls, 1);
|
||||
auto timestamp = grpc_res.mutable_time();
|
||||
*timestamp = google::protobuf::util::TimeUtil::NanosecondsToTimestamp(evt->get_ts());
|
||||
|
||||
// rule
|
||||
auto rule = grpc_res.mutable_rule();
|
||||
*rule = (char *)lua_tostring(ls, 2);
|
||||
|
||||
// source
|
||||
falco::schema::source s = falco::schema::source::SYSCALL;
|
||||
string sstr = (char *)lua_tostring(ls, 3);
|
||||
if(!falco::schema::source_Parse(sstr, &s))
|
||||
{
|
||||
lua_pushstring(ls, "Unknown source passed to to handle_grpc()");
|
||||
lua_error(ls);
|
||||
}
|
||||
grpc_res.set_source(s);
|
||||
|
||||
// priority
|
||||
falco::schema::priority p = falco::schema::priority::EMERGENCY;
|
||||
string pstr = (char *)lua_tostring(ls, 4);
|
||||
if(!falco::schema::priority_Parse(pstr, &p))
|
||||
{
|
||||
lua_pushstring(ls, "Unknown priority passed to to handle_grpc()");
|
||||
lua_error(ls);
|
||||
}
|
||||
grpc_res.set_priority(p);
|
||||
|
||||
// output
|
||||
auto output = grpc_res.mutable_output();
|
||||
*output = (char *)lua_tostring(ls, 5);
|
||||
|
||||
// output fields
|
||||
auto &fields = *grpc_res.mutable_output_fields();
|
||||
|
||||
lua_pushnil(ls); // so that lua_next removes it from stack and puts (k, v) on it
|
||||
while(lua_next(ls, 6) != 0)
|
||||
{
|
||||
fields[lua_tostring(ls, -2)] = lua_tostring(ls, -1);
|
||||
lua_pop(ls, 1); // remove value, keep key for lua_next
|
||||
}
|
||||
lua_pop(ls, 1); // pop table
|
||||
|
||||
// hostname
|
||||
auto host = grpc_res.mutable_hostname();
|
||||
*host = (char *)lua_tostring(ls, 7);
|
||||
|
||||
falco::outputs::queue::get().push(grpc_res);
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors.
|
||||
Copyright (C) 2019 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -19,36 +19,51 @@ limitations under the License.
|
||||
#include <memory>
|
||||
#include <map>
|
||||
|
||||
extern "C" {
|
||||
#include "lua.h"
|
||||
#include "lualib.h"
|
||||
#include "lauxlib.h"
|
||||
}
|
||||
|
||||
#include "gen_filter.h"
|
||||
#include "json_evt.h"
|
||||
#include "falco_common.h"
|
||||
#include "token_bucket.h"
|
||||
#include "falco_engine.h"
|
||||
#include "outputs.h"
|
||||
|
||||
//
|
||||
// This class acts as the primary interface between a program and the
|
||||
// falco output engine. The falco rules engine is implemented by a
|
||||
// separate class falco_engine.
|
||||
//
|
||||
class falco_outputs
|
||||
|
||||
class falco_outputs : public falco_common
|
||||
{
|
||||
public:
|
||||
falco_outputs();
|
||||
falco_outputs(falco_engine *engine);
|
||||
virtual ~falco_outputs();
|
||||
|
||||
// The way to refer to an output (file, syslog, stdout, etc.)
|
||||
// An output has a name and set of options.
|
||||
struct output_config
|
||||
{
|
||||
std::string name;
|
||||
std::map<std::string, std::string> options;
|
||||
};
|
||||
|
||||
void init(bool json_output,
|
||||
bool json_include_output_property,
|
||||
uint32_t rate, uint32_t max_burst, bool buffered,
|
||||
bool time_format_iso_8601, std::string hostname);
|
||||
bool time_format_iso_8601, std::string hostname,
|
||||
const std::string& alternate_lua_dir);
|
||||
|
||||
void add_output(falco::outputs::config oc);
|
||||
void add_output(output_config oc);
|
||||
|
||||
//
|
||||
// evt is an event that has matched some rule. Pass the event
|
||||
// ev is an event that has matched some rule. Pass the event
|
||||
// to all configured outputs.
|
||||
//
|
||||
void handle_event(gen_event *evt, std::string &rule, std::string &source,
|
||||
void handle_event(gen_event *ev, std::string &rule, std::string &source,
|
||||
falco_common::priority_type priority, std::string &format);
|
||||
|
||||
// Send a generic message to all outputs. Not necessarily associated with any event.
|
||||
@@ -56,14 +71,20 @@ public:
|
||||
falco_common::priority_type priority,
|
||||
std::string &msg,
|
||||
std::string &rule,
|
||||
std::map<std::string, std::string> &output_fields);
|
||||
std::map<std::string,std::string> &output_fields);
|
||||
|
||||
void reopen_outputs();
|
||||
|
||||
private:
|
||||
bool m_initialized;
|
||||
#ifndef MINIMAL_BUILD
|
||||
static int handle_http(lua_State *ls);
|
||||
static int handle_grpc(lua_State *ls);
|
||||
#endif
|
||||
|
||||
std::vector<falco::outputs::abstract_output *> m_outputs;
|
||||
private:
|
||||
|
||||
falco_engine *m_falco_engine;
|
||||
|
||||
bool m_initialized;
|
||||
|
||||
// Rate limits notifications
|
||||
token_bucket m_notifications_tb;
|
||||
@@ -72,4 +93,11 @@ private:
|
||||
bool m_json_output;
|
||||
bool m_time_format_iso_8601;
|
||||
std::string m_hostname;
|
||||
|
||||
std::string m_lua_add_output = "add_output";
|
||||
std::string m_lua_output_event = "output_event";
|
||||
std::string m_lua_output_msg = "output_msg";
|
||||
std::string m_lua_output_cleanup = "output_cleanup";
|
||||
std::string m_lua_output_reopen = "output_reopen";
|
||||
std::string m_lua_main_filename = "output.lua";
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors
|
||||
Copyright (C) 2019 The Falco Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -21,9 +21,9 @@ limitations under the License.
|
||||
|
||||
namespace falco
|
||||
{
|
||||
namespace grpc
|
||||
namespace outputs
|
||||
{
|
||||
typedef tbb::concurrent_queue<outputs::response> response_cq;
|
||||
typedef tbb::concurrent_queue<response> response_cq;
|
||||
|
||||
class queue
|
||||
{
|
||||
@@ -34,12 +34,12 @@ public:
|
||||
return instance;
|
||||
}
|
||||
|
||||
bool try_pop(outputs::response& res)
|
||||
bool try_pop(response& res)
|
||||
{
|
||||
return m_queue.try_pop(res);
|
||||
}
|
||||
|
||||
void push(outputs::response& res)
|
||||
void push(response& res)
|
||||
{
|
||||
m_queue.push(res);
|
||||
}
|
||||
@@ -56,5 +56,5 @@ public:
|
||||
queue(queue const&) = delete;
|
||||
void operator=(queue const&) = delete;
|
||||
};
|
||||
} // namespace grpc
|
||||
} // namespace output
|
||||
} // namespace falco
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors
|
||||
Copyright (C) 2019 The Falco Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -16,7 +16,7 @@ limitations under the License.
|
||||
|
||||
#include "config_falco.h"
|
||||
#include "grpc_server_impl.h"
|
||||
#include "grpc_queue.h"
|
||||
#include "falco_outputs_queue.h"
|
||||
#include "logger.h"
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
@@ -44,7 +44,7 @@ void falco::grpc::server_impl::get(const stream_context& ctx, const outputs::req
|
||||
// m_status == stream_context::STREAMING?
|
||||
// todo(leodido) > set m_stream
|
||||
|
||||
ctx.m_has_more = queue::get().try_pop(res);
|
||||
ctx.m_has_more = outputs::queue::get().try_pop(res);
|
||||
}
|
||||
|
||||
void falco::grpc::server_impl::sub(const bidi_context& ctx, const outputs::request& req, outputs::response& res)
|
||||
@@ -61,7 +61,7 @@ void falco::grpc::server_impl::sub(const bidi_context& ctx, const outputs::reque
|
||||
// m_status == stream_context::STREAMING?
|
||||
// todo(leodido) > set m_stream
|
||||
|
||||
ctx.m_has_more = queue::get().try_pop(res);
|
||||
ctx.m_has_more = outputs::queue::get().try_pop(res);
|
||||
}
|
||||
|
||||
void falco::grpc::server_impl::version(const context& ctx, const version::request&, version::response& res)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors.
|
||||
Copyright (C) 2019 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -16,13 +16,25 @@ limitations under the License.
|
||||
|
||||
#include <ctime>
|
||||
#include "logger.h"
|
||||
#include "chisel_api.h"
|
||||
|
||||
#include "falco_common.h"
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
const static struct luaL_reg ll_falco [] =
|
||||
{
|
||||
{"syslog", &falco_logger::syslog},
|
||||
{NULL,NULL}
|
||||
};
|
||||
|
||||
int falco_logger::level = LOG_INFO;
|
||||
bool falco_logger::time_format_iso_8601 = false;
|
||||
|
||||
void falco_logger::init(lua_State *ls)
|
||||
{
|
||||
luaL_openlib(ls, "falco", ll_falco, 0);
|
||||
}
|
||||
|
||||
void falco_logger::set_time_format_iso_8601(bool val)
|
||||
{
|
||||
falco_logger::time_format_iso_8601 = val;
|
||||
@@ -69,6 +81,19 @@ void falco_logger::set_level(string &level)
|
||||
}
|
||||
|
||||
|
||||
int falco_logger::syslog(lua_State *ls) {
|
||||
int priority = luaL_checknumber(ls, 1);
|
||||
|
||||
if (priority > LOG_DEBUG) {
|
||||
return luaL_argerror(ls, 1, "falco.syslog: priority must be a number between 0 and 7");
|
||||
}
|
||||
|
||||
const char *msg = luaL_checkstring(ls, 2);
|
||||
::syslog(priority, "%s", msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool falco_logger::log_stderr = true;
|
||||
bool falco_logger::log_syslog = true;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors.
|
||||
Copyright (C) 2019 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -19,15 +19,25 @@ limitations under the License.
|
||||
#include "sinsp.h"
|
||||
#include <syslog.h>
|
||||
|
||||
extern "C" {
|
||||
#include "lua.h"
|
||||
#include "lualib.h"
|
||||
#include "lauxlib.h"
|
||||
}
|
||||
|
||||
class falco_logger
|
||||
{
|
||||
public:
|
||||
static void init(lua_State *ls);
|
||||
|
||||
static void set_time_format_iso_8601(bool val);
|
||||
|
||||
// Will throw exception if level is unknown.
|
||||
static void set_level(string &level);
|
||||
|
||||
// value = falco.syslog(level, message)
|
||||
static int syslog(lua_State *ls);
|
||||
|
||||
static void log(int priority, const string msg);
|
||||
|
||||
static int level;
|
||||
|
||||
1
userspace/falco/lua/.gitignore
vendored
Normal file
1
userspace/falco/lua/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
lyaml*
|
||||
271
userspace/falco/lua/output.lua
Normal file
271
userspace/falco/lua/output.lua
Normal file
@@ -0,0 +1,271 @@
|
||||
-- Copyright (C) 2019 The Falco Authors.
|
||||
--
|
||||
-- Licensed under the Apache License, Version 2.0 (the "License");
|
||||
-- you may not use this file except in compliance with the License.
|
||||
-- You may obtain a copy of the License at
|
||||
--
|
||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
||||
--
|
||||
-- Unless required by applicable law or agreed to in writing, software
|
||||
-- distributed under the License is distributed on an "AS IS" BASIS,
|
||||
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
-- See the License for the specific language governing permissions and
|
||||
-- limitations under the License.
|
||||
--
|
||||
|
||||
local mod = {}
|
||||
|
||||
local outputs = {}
|
||||
|
||||
function mod.stdout(event, rule, source, priority, priority_num, msg, format, hostname, options)
|
||||
mod.stdout_message(priority, priority_num, msg, options)
|
||||
end
|
||||
|
||||
function mod.stdout_message(priority, priority_num, msg, options)
|
||||
if options.buffered == 0 then
|
||||
io.stdout:setvbuf "no"
|
||||
end
|
||||
print(msg)
|
||||
end
|
||||
|
||||
function mod.stdout_cleanup()
|
||||
io.stdout:flush()
|
||||
end
|
||||
|
||||
-- Note: not actually closing/reopening stdout
|
||||
function mod.stdout_reopen(options)
|
||||
end
|
||||
|
||||
function mod.file_validate(options)
|
||||
if (not type(options.filename) == "string") then
|
||||
error("File output needs to be configured with a valid filename")
|
||||
end
|
||||
|
||||
local file, err = io.open(options.filename, "a+")
|
||||
if file == nil then
|
||||
error("Error with file output: " .. err)
|
||||
end
|
||||
file:close()
|
||||
end
|
||||
|
||||
function mod.file_open(options)
|
||||
if ffile == nil then
|
||||
ffile = io.open(options.filename, "a+")
|
||||
if options.buffered == 0 then
|
||||
ffile:setvbuf "no"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function mod.file(event, rule, source, priority, priority_num, msg, format, hostname, options)
|
||||
mod.file_message(priority, priority_num, msg, options)
|
||||
end
|
||||
|
||||
function mod.file_message(priority, priority_num, msg, options)
|
||||
if options.keep_alive == "true" then
|
||||
mod.file_open(options)
|
||||
else
|
||||
ffile = io.open(options.filename, "a+")
|
||||
end
|
||||
|
||||
ffile:write(msg, "\n")
|
||||
|
||||
if options.keep_alive == nil or options.keep_alive ~= "true" then
|
||||
ffile:close()
|
||||
ffile = nil
|
||||
end
|
||||
end
|
||||
|
||||
function mod.file_cleanup()
|
||||
if ffile ~= nil then
|
||||
ffile:flush()
|
||||
ffile:close()
|
||||
ffile = nil
|
||||
end
|
||||
end
|
||||
|
||||
function mod.file_reopen(options)
|
||||
if options.keep_alive == "true" then
|
||||
mod.file_cleanup()
|
||||
mod.file_open(options)
|
||||
end
|
||||
end
|
||||
|
||||
function mod.syslog(event, rule, source, priority, priority_num, msg, format, hostname, options)
|
||||
mod.syslog_message(priority, priority_num, msg, options)
|
||||
end
|
||||
|
||||
function mod.syslog_message(priority, priority_num, msg, options)
|
||||
falco.syslog(priority_num, msg)
|
||||
end
|
||||
|
||||
function mod.syslog_cleanup()
|
||||
end
|
||||
|
||||
function mod.syslog_reopen()
|
||||
end
|
||||
|
||||
function mod.program_open(options)
|
||||
if pfile == nil then
|
||||
pfile = io.popen(options.program, "w")
|
||||
if options.buffered == 0 then
|
||||
pfile:setvbuf "no"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function mod.program(event, rule, source, priority, priority_num, msg, format, hostname, options)
|
||||
mod.program_message(priority, priority_num, msg, options)
|
||||
end
|
||||
|
||||
function mod.program_message(priority, priority_num, msg, options)
|
||||
-- XXX Ideally we'd check that the program ran
|
||||
-- successfully. However, the luajit we're using returns true even
|
||||
-- when the shell can't run the program.
|
||||
|
||||
-- Note: options are all strings
|
||||
if options.keep_alive == "true" then
|
||||
mod.program_open(options)
|
||||
else
|
||||
pfile = io.popen(options.program, "w")
|
||||
end
|
||||
|
||||
pfile:write(msg, "\n")
|
||||
|
||||
if options.keep_alive == nil or options.keep_alive ~= "true" then
|
||||
pfile:close()
|
||||
pfile = nil
|
||||
end
|
||||
end
|
||||
|
||||
function mod.program_cleanup()
|
||||
if pfile ~= nil then
|
||||
pfile:flush()
|
||||
pfile:close()
|
||||
pfile = nil
|
||||
end
|
||||
end
|
||||
|
||||
function mod.program_reopen(options)
|
||||
if options.keep_alive == "true" then
|
||||
mod.program_cleanup()
|
||||
mod.program_open(options)
|
||||
end
|
||||
end
|
||||
|
||||
function mod.http(event, rule, source, priority, priority_num, msg, format, hostname, options)
|
||||
mod.http_message(priority, priority_num, msg, options)
|
||||
end
|
||||
|
||||
function mod.http_message(priority, priority_num, msg, options)
|
||||
c_outputs.handle_http(options.url, msg)
|
||||
end
|
||||
|
||||
function mod.http_cleanup()
|
||||
end
|
||||
|
||||
function mod.http_reopen()
|
||||
end
|
||||
|
||||
function mod.grpc(event, rule, source, priority, priority_num, msg, format, hostname, options)
|
||||
fields = formats.resolve_tokens(event, source, format)
|
||||
c_outputs.handle_grpc(event, rule, source, priority, msg, fields, hostname, options)
|
||||
end
|
||||
|
||||
function mod.grpc_message(priority, priority_num, msg, options)
|
||||
-- todo(fntlnz, leodido) > gRPC does not support subscribing to dropped events yet
|
||||
end
|
||||
|
||||
|
||||
function mod.grpc_cleanup()
|
||||
end
|
||||
|
||||
function mod.grpc_reopen()
|
||||
end
|
||||
|
||||
function output_event(event, rule, source, priority, priority_num, format, hostname)
|
||||
-- If format starts with a *, remove it, as we're adding our own
|
||||
-- prefix here.
|
||||
if format:sub(1, 1) == "*" then
|
||||
format = format:sub(2)
|
||||
end
|
||||
|
||||
-- time_format_iso_8601 will be the same for all output channels
|
||||
time_format_iso_8601 = 0
|
||||
|
||||
for index, o in ipairs(outputs) do
|
||||
time_format_iso_8601 = o.options.time_format_iso_8601
|
||||
break
|
||||
end
|
||||
|
||||
if source == "syscall" then
|
||||
if time_format_iso_8601 == 1 then
|
||||
format = "*%evt.time.iso8601: " .. priority .. " " .. format
|
||||
else
|
||||
format = "*%evt.time: " .. priority .. " " .. format
|
||||
end
|
||||
else
|
||||
if time_format_iso_8601 == 1 then
|
||||
format = "*%jevt.time.iso8601: " .. priority .. " " .. format
|
||||
else
|
||||
format = "*%jevt.time: " .. priority .. " " .. format
|
||||
end
|
||||
end
|
||||
|
||||
msg = formats.format_event(event, rule, source, priority, format)
|
||||
|
||||
for index, o in ipairs(outputs) do
|
||||
o.output(event, rule, source, priority, priority_num, msg, format, hostname, o.options)
|
||||
end
|
||||
end
|
||||
|
||||
function output_msg(msg, priority, priority_num)
|
||||
for index, o in ipairs(outputs) do
|
||||
o.message(priority, priority_num, msg, o.options)
|
||||
end
|
||||
end
|
||||
|
||||
function output_cleanup()
|
||||
formats.free_formatters()
|
||||
for index, o in ipairs(outputs) do
|
||||
o.cleanup()
|
||||
end
|
||||
end
|
||||
|
||||
function output_reopen()
|
||||
for index, o in ipairs(outputs) do
|
||||
o.reopen(o.options)
|
||||
end
|
||||
end
|
||||
|
||||
function add_output(output_name, buffered, time_format_iso_8601, options)
|
||||
if not (type(mod[output_name]) == "function") then
|
||||
error("rule_loader.add_output(): invalid output_name: " .. output_name)
|
||||
end
|
||||
|
||||
-- outputs can optionally define a validation function so that we don't
|
||||
-- find out at runtime (when an event finally matches a rule!) that the options are invalid
|
||||
if (type(mod[output_name .. "_validate"]) == "function") then
|
||||
mod[output_name .. "_validate"](options)
|
||||
end
|
||||
|
||||
if options == nil then
|
||||
options = {}
|
||||
end
|
||||
|
||||
options.buffered = buffered
|
||||
options.time_format_iso_8601 = time_format_iso_8601
|
||||
|
||||
table.insert(
|
||||
outputs,
|
||||
{
|
||||
output = mod[output_name],
|
||||
cleanup = mod[output_name .. "_cleanup"],
|
||||
reopen = mod[output_name .. "_reopen"],
|
||||
message = mod[output_name .. "_message"],
|
||||
options = options
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
return mod
|
||||
44
userspace/falco/lua/test.lua
Normal file
44
userspace/falco/lua/test.lua
Normal file
@@ -0,0 +1,44 @@
|
||||
-- Copyright (C) 2019 The Falco Authors.
|
||||
--
|
||||
-- Licensed under the Apache License, Version 2.0 (the "License");
|
||||
-- you may not use this file except in compliance with the License.
|
||||
-- You may obtain a copy of the License at
|
||||
--
|
||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
||||
--
|
||||
-- Unless required by applicable law or agreed to in writing, software
|
||||
-- distributed under the License is distributed on an "AS IS" BASIS,
|
||||
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
-- See the License for the specific language governing permissions and
|
||||
-- limitations under the License.
|
||||
--
|
||||
|
||||
local parser = require "parser"
|
||||
|
||||
if #arg ~= 1 then
|
||||
print("Usage: test.lua <string>")
|
||||
os.exit(1)
|
||||
end
|
||||
|
||||
local macros = {}
|
||||
local ast
|
||||
|
||||
local function doit(line)
|
||||
ast = parser.parse_filter(line)
|
||||
|
||||
if not ast then
|
||||
print("error", error_msg)
|
||||
os.exit(1)
|
||||
end
|
||||
|
||||
end
|
||||
for str in string.gmatch(arg[1], "([^;]+)") do
|
||||
doit(str)
|
||||
end
|
||||
|
||||
if (ast and ast.type) then
|
||||
parser.print_ast(ast)
|
||||
end
|
||||
|
||||
os.exit(0)
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "falco_common.h"
|
||||
#include "gen_filter.h"
|
||||
|
||||
namespace falco
|
||||
{
|
||||
namespace outputs
|
||||
{
|
||||
|
||||
//
|
||||
// The way to refer to an output (file, syslog, stdout, etc.)
|
||||
// An output has a name and set of options.
|
||||
//
|
||||
struct config
|
||||
{
|
||||
std::string name;
|
||||
std::map<std::string, std::string> options;
|
||||
};
|
||||
|
||||
//
|
||||
// This class acts as the primary interface for implementing
|
||||
// a Falco output class.
|
||||
//
|
||||
|
||||
class abstract_output
|
||||
{
|
||||
public:
|
||||
void init(config oc, bool buffered, std::string hostname)
|
||||
{
|
||||
m_oc = oc;
|
||||
m_buffered = buffered;
|
||||
m_hostname = hostname;
|
||||
}
|
||||
|
||||
// Output an event that has matched some rule.
|
||||
virtual void output_event(gen_event *evt, std::string &rule, std::string &source,
|
||||
falco_common::priority_type priority, std::string &format, std::string &msg) = 0;
|
||||
|
||||
// Output a generic message. Not necessarily associated with any event.
|
||||
virtual void output_msg(falco_common::priority_type priority, std::string &msg) = 0;
|
||||
|
||||
virtual void reopen() {}
|
||||
|
||||
virtual void cleanup() {}
|
||||
|
||||
protected:
|
||||
config m_oc;
|
||||
bool m_buffered;
|
||||
std::string m_hostname;
|
||||
};
|
||||
|
||||
} // namespace outputs
|
||||
} // namespace falco
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "outputs_file.h"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
void falco::outputs::output_file::open_file()
|
||||
{
|
||||
if(!m_buffered)
|
||||
{
|
||||
m_outfile.rdbuf()->pubsetbuf(0, 0);
|
||||
}
|
||||
if(!m_outfile.is_open())
|
||||
{
|
||||
m_outfile.open(m_oc.options["filename"], fstream::app);
|
||||
}
|
||||
}
|
||||
|
||||
void falco::outputs::output_file::output_event(gen_event *evt, std::string &rule, std::string &source,
|
||||
falco_common::priority_type priority, std::string &format, std::string &msg)
|
||||
{
|
||||
output_msg(priority, msg);
|
||||
}
|
||||
|
||||
void falco::outputs::output_file::output_msg(falco_common::priority_type priority, std::string &msg)
|
||||
{
|
||||
open_file();
|
||||
m_outfile << msg + "\n";
|
||||
|
||||
if(m_oc.options["keep_alive"] != "true")
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
void falco::outputs::output_file::cleanup()
|
||||
{
|
||||
if(m_outfile.is_open())
|
||||
{
|
||||
m_outfile.close();
|
||||
}
|
||||
}
|
||||
|
||||
void falco::outputs::output_file::reopen()
|
||||
{
|
||||
cleanup();
|
||||
open_file();
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "outputs.h"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
namespace falco
|
||||
{
|
||||
namespace outputs
|
||||
{
|
||||
|
||||
class output_file : public abstract_output
|
||||
{
|
||||
void output_event(gen_event *evt, std::string &rule, std::string &source,
|
||||
falco_common::priority_type priority, std::string &format, std::string &msg);
|
||||
|
||||
void output_msg(falco_common::priority_type priority, std::string &msg);
|
||||
|
||||
void cleanup();
|
||||
|
||||
void reopen();
|
||||
|
||||
private:
|
||||
void open_file();
|
||||
|
||||
std::ofstream m_outfile;
|
||||
};
|
||||
|
||||
} // namespace outputs
|
||||
} // namespace falco
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include <google/protobuf/util/time_util.h>
|
||||
#include "outputs_grpc.h"
|
||||
#include "grpc_queue.h"
|
||||
#include "falco_common.h"
|
||||
#include "formats.h"
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
void falco::outputs::output_grpc::output_event(gen_event *evt, std::string &rule, std::string &source,
|
||||
falco_common::priority_type priority, std::string &format,
|
||||
std::string &msg)
|
||||
{
|
||||
falco::outputs::response grpc_res;
|
||||
|
||||
// time
|
||||
auto timestamp = grpc_res.mutable_time();
|
||||
*timestamp = google::protobuf::util::TimeUtil::NanosecondsToTimestamp(evt->get_ts());
|
||||
|
||||
// rule
|
||||
auto r = grpc_res.mutable_rule();
|
||||
*r = rule;
|
||||
|
||||
// source
|
||||
falco::schema::source s = falco::schema::source::SYSCALL;
|
||||
if(!falco::schema::source_Parse(source, &s))
|
||||
{
|
||||
throw falco_exception("Unknown source passed to output_grpc::output_event()");
|
||||
}
|
||||
grpc_res.set_source(s);
|
||||
|
||||
// priority
|
||||
falco::schema::priority p = falco::schema::priority::EMERGENCY;
|
||||
if(!falco::schema::priority_Parse(falco_common::priority_names[priority], &p))
|
||||
{
|
||||
throw falco_exception("Unknown priority passed to output_grpc::output_event()");
|
||||
}
|
||||
grpc_res.set_priority(p);
|
||||
|
||||
// output
|
||||
auto output = grpc_res.mutable_output();
|
||||
*output = msg;
|
||||
|
||||
// output fields
|
||||
auto &fields = *grpc_res.mutable_output_fields();
|
||||
auto resolvedTkns = falco_formats::resolve_tokens(evt, source, format);
|
||||
for(const auto &kv : resolvedTkns)
|
||||
{
|
||||
fields[kv.first] = kv.second;
|
||||
}
|
||||
|
||||
// hostname
|
||||
auto host = grpc_res.mutable_hostname();
|
||||
*host = m_hostname;
|
||||
|
||||
falco::grpc::queue::get().push(grpc_res);
|
||||
}
|
||||
|
||||
void falco::outputs::output_grpc::output_msg(falco_common::priority_type priority, std::string &msg)
|
||||
{
|
||||
// todo(fntlnz, leodido, leogr) > gRPC does not support subscribing to dropped events yet
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "outputs.h"
|
||||
|
||||
namespace falco
|
||||
{
|
||||
namespace outputs
|
||||
{
|
||||
|
||||
class output_grpc : public abstract_output
|
||||
{
|
||||
void output_event(gen_event *evt, std::string &rule, std::string &source,
|
||||
falco_common::priority_type priority, std::string &format, std::string &msg);
|
||||
|
||||
void output_msg(falco_common::priority_type priority, std::string &msg);
|
||||
};
|
||||
|
||||
} // namespace outputs
|
||||
} // namespace falco
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "outputs_http.h"
|
||||
#include "logger.h"
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
void falco::outputs::output_http::output_event(gen_event *evt, std::string &rule, std::string &source,
|
||||
falco_common::priority_type priority, std::string &format, std::string &msg)
|
||||
{
|
||||
output_msg(priority, msg);
|
||||
}
|
||||
|
||||
void falco::outputs::output_http::output_msg(falco_common::priority_type priority, std::string &msg)
|
||||
{
|
||||
CURL *curl = NULL;
|
||||
CURLcode res = CURLE_FAILED_INIT;
|
||||
struct curl_slist *slist1;
|
||||
slist1 = NULL;
|
||||
|
||||
curl = curl_easy_init();
|
||||
if(curl)
|
||||
{
|
||||
slist1 = curl_slist_append(slist1, "Content-Type: application/json");
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, m_oc.options["url"].c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, msg.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, -1L);
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
if(res != CURLE_OK)
|
||||
{
|
||||
falco_logger::log(LOG_ERR, "libcurl error: " + string(curl_easy_strerror(res)));
|
||||
}
|
||||
curl_easy_cleanup(curl);
|
||||
curl = NULL;
|
||||
curl_slist_free_all(slist1);
|
||||
slist1 = NULL;
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "outputs.h"
|
||||
|
||||
namespace falco
|
||||
{
|
||||
namespace outputs
|
||||
{
|
||||
|
||||
class output_http : public abstract_output
|
||||
{
|
||||
void output_event(gen_event *evt, std::string &rule, std::string &source,
|
||||
falco_common::priority_type priority, std::string &format, std::string &msg);
|
||||
|
||||
void output_msg(falco_common::priority_type priority, std::string &msg);
|
||||
};
|
||||
|
||||
} // namespace outputs
|
||||
} // namespace falco
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "outputs_program.h"
|
||||
#include <stdio.h>
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
void falco::outputs::output_program::open_pfile()
|
||||
{
|
||||
if(m_pfile == nullptr)
|
||||
{
|
||||
m_pfile = popen(m_oc.options["program"].c_str(), "w");
|
||||
|
||||
if(!m_buffered)
|
||||
{
|
||||
setvbuf(m_pfile, NULL, _IONBF, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void falco::outputs::output_program::output_event(gen_event *evt, std::string &rule, std::string &source,
|
||||
falco_common::priority_type priority, std::string &format, std::string &msg)
|
||||
{
|
||||
output_msg(priority, msg);
|
||||
}
|
||||
|
||||
void falco::outputs::output_program::output_msg(falco_common::priority_type priority, std::string &msg)
|
||||
{
|
||||
open_pfile();
|
||||
|
||||
fprintf(m_pfile, "%s\n", msg.c_str());
|
||||
|
||||
if(m_oc.options["keep_alive"] != "true")
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
void falco::outputs::output_program::cleanup()
|
||||
{
|
||||
if(m_pfile != nullptr)
|
||||
{
|
||||
pclose(m_pfile);
|
||||
m_pfile = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void falco::outputs::output_program::reopen()
|
||||
{
|
||||
cleanup();
|
||||
open_pfile();
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "outputs.h"
|
||||
|
||||
namespace falco
|
||||
{
|
||||
namespace outputs
|
||||
{
|
||||
|
||||
class output_program : public abstract_output
|
||||
{
|
||||
void output_event(gen_event *evt, std::string &rule, std::string &source,
|
||||
falco_common::priority_type priority, std::string &format, std::string &msg);
|
||||
|
||||
void output_msg(falco_common::priority_type priority, std::string &msg);
|
||||
|
||||
void cleanup();
|
||||
|
||||
void reopen();
|
||||
|
||||
private:
|
||||
void open_pfile();
|
||||
|
||||
FILE *m_pfile;
|
||||
};
|
||||
|
||||
} // namespace outputs
|
||||
} // namespace falco
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "outputs_stdout.h"
|
||||
#include <iostream>
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
void falco::outputs::output_stdout::output_event(gen_event *evt, std::string &rule, std::string &source,
|
||||
falco_common::priority_type priority, std::string &format, std::string &msg)
|
||||
{
|
||||
output_msg(priority, msg);
|
||||
}
|
||||
|
||||
void falco::outputs::output_stdout::output_msg(falco_common::priority_type priority, std::string &msg)
|
||||
{
|
||||
//
|
||||
// By default, the stdout stream is fully buffered or line buffered
|
||||
// (if the stream can be determined to refer to an interactive device, e.g. in a TTY).
|
||||
// Just enable automatic flushing when unbuffered output is desired.
|
||||
// Note that it is set every time since other writings to the stdout can disable it.
|
||||
//
|
||||
if(!m_buffered)
|
||||
{
|
||||
std::cout << std::unitbuf;
|
||||
}
|
||||
std::cout << msg + "\n";
|
||||
}
|
||||
|
||||
void falco::outputs::output_stdout::cleanup()
|
||||
{
|
||||
std::cout.flush();
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "outputs.h"
|
||||
|
||||
namespace falco
|
||||
{
|
||||
namespace outputs
|
||||
{
|
||||
|
||||
class output_stdout : public abstract_output
|
||||
{
|
||||
void output_event(gen_event *evt, std::string &rule, std::string &source,
|
||||
falco_common::priority_type priority, std::string &format, std::string &msg);
|
||||
|
||||
void output_msg(falco_common::priority_type priority, std::string &msg);
|
||||
|
||||
void cleanup();
|
||||
};
|
||||
|
||||
} // namespace outputs
|
||||
} // namespace falco
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "outputs_syslog.h"
|
||||
#include <syslog.h>
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
void falco::outputs::output_syslog::output_event(gen_event *evt, std::string &rule, std::string &source,
|
||||
falco_common::priority_type priority, std::string &format, std::string &msg)
|
||||
{
|
||||
output_msg(priority, msg);
|
||||
}
|
||||
|
||||
void falco::outputs::output_syslog::output_msg(falco_common::priority_type priority, std::string &msg)
|
||||
{
|
||||
// Syslog output should not have any trailing newline
|
||||
::syslog(priority, "%s", msg.c_str());
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "outputs.h"
|
||||
|
||||
namespace falco
|
||||
{
|
||||
namespace outputs
|
||||
{
|
||||
|
||||
class output_syslog : public abstract_output
|
||||
{
|
||||
void output_event(gen_event *evt, std::string &rule, std::string &source,
|
||||
falco_common::priority_type priority, std::string &format, std::string &msg);
|
||||
|
||||
void output_msg(falco_common::priority_type priority, std::string &msg);
|
||||
};
|
||||
|
||||
} // namespace outputs
|
||||
} // namespace falco
|
||||
Reference in New Issue
Block a user