mirror of
https://github.com/falcosecurity/falco.git
synced 2026-03-20 11:42:06 +00:00
Compare commits
36 Commits
fix/1272
...
fix/script
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7637ccd7a8 | ||
|
|
40635ab620 | ||
|
|
e0b66ecae9 | ||
|
|
a87913c822 | ||
|
|
7a2708de09 | ||
|
|
fbac5b77ff | ||
|
|
fc39c92048 | ||
|
|
32374e9d95 | ||
|
|
220274601c | ||
|
|
08f6ddb889 | ||
|
|
4166f02668 | ||
|
|
d6279bd474 | ||
|
|
a20e3267cd | ||
|
|
1362ad7c10 | ||
|
|
0324e8b610 | ||
|
|
feb39010bb | ||
|
|
59b2bdac9d | ||
|
|
f388d95591 | ||
|
|
8bfd6eaef7 | ||
|
|
4db3cc1f72 | ||
|
|
52a2c253ce | ||
|
|
1f1f7c16b6 | ||
|
|
ff77a36a03 | ||
|
|
213e4f6aaf | ||
|
|
5839e41093 | ||
|
|
974efadaee | ||
|
|
615313e8fa | ||
|
|
4c25135bf9 | ||
|
|
1bb0a9b44a | ||
|
|
ca3c4814fe | ||
|
|
50832c7990 | ||
|
|
4eba59c3f0 | ||
|
|
3e98c2efc0 | ||
|
|
938ece8f4e | ||
|
|
511ef52717 | ||
|
|
e2bf87d207 |
@@ -64,8 +64,72 @@ jobs:
|
||||
pushd build
|
||||
make tests
|
||||
popd
|
||||
# Build using Ubuntu Bionic Beaver (18.04)
|
||||
# This build is static, dependencies are bundled in the Falco binary
|
||||
"build/ubuntu-bionic":
|
||||
docker:
|
||||
- image: ubuntu:bionic
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Update base image
|
||||
command: apt update -y
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: DEBIAN_FRONTEND=noninteractive apt install cmake build-essential clang llvm git linux-headers-generic libncurses-dev pkg-config autoconf libtool libelf-dev -y
|
||||
- run:
|
||||
name: Prepare project
|
||||
command: |
|
||||
mkdir build
|
||||
pushd build
|
||||
cmake -DBUILD_BPF=On -DUSE_BUNDLED_DEPS=On ..
|
||||
popd
|
||||
- run:
|
||||
name: Build
|
||||
command: |
|
||||
pushd build
|
||||
KERNELDIR=/lib/modules/$(ls /lib/modules)/build make -j4 all
|
||||
popd
|
||||
- run:
|
||||
name: Run unit tests
|
||||
command: |
|
||||
pushd build
|
||||
make tests
|
||||
popd
|
||||
# Build using CentOS 8
|
||||
# This build is static, dependencies are bundled in the Falco binary
|
||||
"build/centos8":
|
||||
docker:
|
||||
- image: centos:8
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Update base image
|
||||
command: dnf update -y
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: dnf install gcc gcc-c++ git make cmake autoconf automake pkg-config patch ncurses-devel libtool elfutils-libelf-devel diffutils kernel-devel kernel-headers kernel-core clang llvm which -y
|
||||
- run:
|
||||
name: Prepare project
|
||||
command: |
|
||||
mkdir build
|
||||
pushd build
|
||||
cmake -DBUILD_BPF=On -DUSE_BUNDLED_DEPS=On ..
|
||||
popd
|
||||
- run:
|
||||
name: Build
|
||||
command: |
|
||||
pushd build
|
||||
KERNELDIR=/lib/modules/$(ls /lib/modules)/build make -j4 all
|
||||
popd
|
||||
- run:
|
||||
name: Run unit tests
|
||||
command: |
|
||||
pushd build
|
||||
make tests
|
||||
popd
|
||||
# Build using our own builder base image using centos 7
|
||||
# This build is static, dependencies are bundled in the falco binary
|
||||
# This build is static, dependencies are bundled in the Falco binary
|
||||
"build/centos7":
|
||||
docker:
|
||||
- image: falcosecurity/falco-builder:latest
|
||||
@@ -102,7 +166,7 @@ jobs:
|
||||
path: /tmp/packages
|
||||
destination: /packages
|
||||
# Debug build using our own builder base image using centos 7
|
||||
# This build is static, dependencies are bundled in the falco binary
|
||||
# This build is static, dependencies are bundled in the Falco binary
|
||||
"build/centos7-debug":
|
||||
docker:
|
||||
- image: falcosecurity/falco-builder:latest
|
||||
@@ -310,6 +374,8 @@ workflows:
|
||||
jobs:
|
||||
- "build/ubuntu-focal"
|
||||
- "build/ubuntu-focal-debug"
|
||||
- "build/ubuntu-bionic"
|
||||
- "build/centos8"
|
||||
- "build/centos7"
|
||||
- "build/centos7-debug"
|
||||
- "tests/integration":
|
||||
|
||||
@@ -166,16 +166,14 @@ include(libyaml)
|
||||
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}'")
|
||||
set(LYAML_DEPENDENCIES "")
|
||||
list(APPEND LYAML_DEPENDENCIES "luajit")
|
||||
ExternalProject_Add(
|
||||
lyaml
|
||||
DEPENDS ${LYAML_DEPENDENCIES}
|
||||
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 LIBS=-lyaml LUA_INCLUDE=-I${LUAJIT_INCLUDE} LUA=${LUAJIT_SRC}/luajit
|
||||
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,38 +0,0 @@
|
||||
# CNCF Community Code of Conduct v1.0
|
||||
|
||||
## Contributor Code of Conduct
|
||||
|
||||
As contributors and maintainers of this project, and in the interest of fostering
|
||||
an open and welcoming community, we pledge to respect all people who contribute
|
||||
through reporting issues, posting feature requests, updating documentation,
|
||||
submitting pull requests or patches, and other activities.
|
||||
|
||||
We are committed to making participation in this project a harassment-free experience for
|
||||
everyone, regardless of level of experience, gender, gender identity and expression,
|
||||
sexual orientation, disability, personal appearance, body size, race, ethnicity, age,
|
||||
religion, or nationality.
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery
|
||||
* Personal attacks
|
||||
* Trolling or insulting/derogatory comments
|
||||
* Public or private harassment
|
||||
* Publishing other's private information, such as physical or electronic addresses,
|
||||
without explicit permission
|
||||
* Other unethical or unprofessional conduct.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are not
|
||||
aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers
|
||||
commit themselves to fairly and consistently applying these principles to every aspect
|
||||
of managing this project. Project maintainers who do not follow or enforce the Code of
|
||||
Conduct may be permanently removed from the project team.
|
||||
|
||||
This code of conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community.
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting a CNCF project maintainer, [Sarah Novotny](mailto:sarahnovotny@google.com), and/or [Dan Kohn](mailto:dan@linuxfoundation.org).
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at
|
||||
http://contributor-covenant.org/version/1/2/0/
|
||||
150
CONTRIBUTING.md
150
CONTRIBUTING.md
@@ -1,150 +0,0 @@
|
||||
# Contributing to Falco
|
||||
|
||||
- [Contributing to Falco](#contributing-to-falco)
|
||||
- [Code of Conduct](#code-of-conduct)
|
||||
- [Issues](#issues)
|
||||
- [Triage issues](#triage-issues)
|
||||
- [More about labels](#more-about-labels)
|
||||
- [Slack](#slack)
|
||||
- [Pull Requests](#pull-requests)
|
||||
- [Commit convention](#commit-convention)
|
||||
- [Rule type](#rule-type)
|
||||
- [Coding Guidelines](#coding-guidelines)
|
||||
- [C++](#c)
|
||||
- [Unit testing](/tests/README.md)
|
||||
- [Developer Certificate Of Origin](#developer-certificate-of-origin)
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
Falco has a
|
||||
[Code of Conduct](CODE_OF_CONDUCT.md)
|
||||
to which all contributors must adhere, please read it before interacting with the repository or the community in any way.
|
||||
|
||||
## Issues
|
||||
|
||||
Issues are the heartbeat ❤️ of the Falco project, there are mainly three kinds of issues you can open:
|
||||
|
||||
- Bug report: you believe you found a problem in Falco and you want to discuss and get it fixed,
|
||||
creating an issue with the **bug report template** is the best way to do so.
|
||||
- Enhancement: any kind of new feature need to be discussed in this kind of issue, do you want a new rule or a new feature? This is the kind of issue you want to open. Be very good at explaining your intent, it's always important that others can understand what you mean in order to discuss, be open and collaborative in letting others help you getting this done!
|
||||
- Failing tests: you noticed a flaky test or a problem with a build? This is the kind of issue to triage that!
|
||||
|
||||
The best way to get **involved** in the project is through issues, you can help in many ways:
|
||||
|
||||
- Issues triaging: participating in the discussion and adding details to open issues is always a good thing,
|
||||
sometimes issues need to be verified, you could be the one writing a test case to fix a bug!
|
||||
- Helping to resolve the issue: you can help in getting it fixed in many ways, more often by opening a pull request.
|
||||
|
||||
### Triage issues
|
||||
|
||||
We need help in categorizing issues. Thus any help is welcome!
|
||||
|
||||
When you triage an issue, you:
|
||||
|
||||
* assess whether it has merit or not
|
||||
|
||||
* quickly close it by correctly answering a question
|
||||
|
||||
* point the reporter to a resource or documentation answering the issue
|
||||
|
||||
* tag it via labels, projects, or milestones
|
||||
|
||||
* take ownership submitting a PR for it, in case you want 😇
|
||||
|
||||
#### More about labels
|
||||
|
||||
These guidelines are not set in stone and are subject to change.
|
||||
|
||||
Anyway a `kind/*` label for any issue is mandatory.
|
||||
|
||||
This is the current [label set](https://github.com/falcosecurity/falco/labels) we have.
|
||||
|
||||
You can use commands - eg., `/label <some-label>` to add (or remove) labels or manually do it.
|
||||
|
||||
The commands available are the following ones:
|
||||
|
||||
```
|
||||
/[remove-](area|kind|priority|triage|label)
|
||||
```
|
||||
|
||||
Some examples:
|
||||
|
||||
* `/area rules`
|
||||
* `/remove-area rules`
|
||||
* `/kind kernel-module`
|
||||
* `/label good-first-issue`
|
||||
* `/triage duplicate`
|
||||
* `/triage unresolved`
|
||||
* `/triage not-reproducible`
|
||||
* `/triage support`
|
||||
* ...
|
||||
|
||||
### Slack
|
||||
|
||||
Other discussion, and **support requests** should go through the `#falco` channel in the Kubernetes slack, please join [here](https://slack.k8s.io/).
|
||||
|
||||
## Pull Requests
|
||||
|
||||
Thanks for taking time to make a [pull request](https://help.github.com/articles/about-pull-requests) (hereafter PR).
|
||||
|
||||
In the PR body, feel free to add an area label if appropriate by typing `/area <AREA>`, PRs will also
|
||||
need a kind, make sure to specify the appropriate one by typing `/kind <KIND>`.
|
||||
|
||||
The list of labels is [here](https://github.com/falcosecurity/falco/labels).
|
||||
|
||||
Also feel free to suggest a reviewer with `/cc @theirname`, or to assign an assignee using `/assign @nickname`.
|
||||
|
||||
Once your reviewer is happy, they will say `/lgtm` which will apply the
|
||||
`lgtm` label, and will apply the `approved` label if they are an
|
||||
[owner](/OWNERS).
|
||||
|
||||
Your PR will be automatically merged once it has the `lgtm` and `approved`
|
||||
labels, does not have any `do-not-merge/*` labels, and all status checks (eg., rebase, tests, DCO) are positive.
|
||||
|
||||
### Commit convention
|
||||
|
||||
As commit convention, we adopt [Conventional Commits v1.0.0](https://www.conventionalcommits.org/en/v1.0.0/), we have an history
|
||||
of commits that do not adopt the convention but any new commit must follow it to be eligible for merge.
|
||||
|
||||
#### Rule type
|
||||
|
||||
Besides the classic types, we adopt a type for rules, `rule(<scope>):`.
|
||||
Example:
|
||||
|
||||
```
|
||||
rule(Write below monitored dir): make sure monitored dirs are monitored.
|
||||
```
|
||||
|
||||
Each rule change must be on its own commit, if a change to a macro is done while changing a rule they can go together but only one rule per commit must happen.
|
||||
|
||||
If you are changing only a macro, the commit will look like this:
|
||||
|
||||
```
|
||||
rule(macro user_known_write_monitored_dir_conditions): make sure conditions are great
|
||||
```
|
||||
|
||||
## Coding Guidelines
|
||||
|
||||
### C++
|
||||
|
||||
* File `userspace/engine/banned.h` defines some functions as invalid tokens. These functions are not allowed to be used in the codebase. Whenever creating a new cpp file, include the `"banned.h"` headers. This ensures that the banned functions are not compiled.
|
||||
|
||||
A complete list of banned functions can be found [here](./userspace/engine/banned.h).
|
||||
|
||||
## Developer Certificate Of Origin
|
||||
|
||||
The [Developer Certificate of Origin (DCO)](https://developercertificate.org/) is a lightweight way for contributors to certify that they wrote or otherwise have the right to submit the code they are contributing to the project.
|
||||
|
||||
Contributors to the Falco project sign-off that they adhere to these requirements by adding a `Signed-off-by` line to commit messages.
|
||||
|
||||
```
|
||||
This is my commit message
|
||||
|
||||
Signed-off-by: John Poiana <jpoiana@falco.org>
|
||||
```
|
||||
|
||||
Git even has a `-s` command line option to append this automatically to your commit message:
|
||||
|
||||
```
|
||||
$ git commit -s -m 'This is my commit message'
|
||||
```
|
||||
81
README.md
81
README.md
@@ -3,8 +3,6 @@
|
||||
|
||||
<hr>
|
||||
|
||||
# The Falco Project
|
||||
|
||||
[](https://circleci.com/gh/falcosecurity/falco) [](https://bestpractices.coreinfrastructure.org/projects/2317) [](COPYING)
|
||||
|
||||
#### Latest releases
|
||||
@@ -19,63 +17,78 @@ Read the [change log](CHANGELOG.md).
|
||||
|
||||
---
|
||||
|
||||
Falco is a behavioral activity monitor designed to detect anomalous activity in your applications. Falco audits a system at the most fundamental level, the kernel. Falco then enriches this data with other input streams such as container runtime metrics, and Kubernetes metrics. Falco lets you continuously monitor and detect container, application, host, and network activity—all in one place—from one source of data, with one set of rules.
|
||||
The Falco Project, originally created by [Sysdig](https://sysdig.com), is an incubating [CNCF](https://cncf.io) open source cloud native runtime security tool.
|
||||
Falco makes it easy to consume kernel events, and enrich those events with information from Kubernetes and the rest of the cloud native stack.
|
||||
Falco has a rich rule set of security rules specifically built for Kubernetes, Linux, and cloud-native.
|
||||
If a rule is violated in a system, Falco will send an alert notifying the user of the violation and its severity.
|
||||
|
||||
Falco is hosted by the Cloud Native Computing Foundation (CNCF) as a sandbox level project. If you are an organization that wants to help shape the evolution of technologies that are container-packaged, dynamically-scheduled and microservices-oriented, consider joining the CNCF. For details read the [Falco CNCF project proposal](https://github.com/cncf/toc/tree/master/proposals/falco.adoc).
|
||||
### Installing Falco
|
||||
|
||||
#### What kind of behaviors can Falco detect?
|
||||
If you would like to run Falco in **production** please adhere to the [official installation guide](https://falco.org/docs/installation/).
|
||||
|
||||
Falco can detect and alert on any behavior that involves making Linux system calls. Falco alerts can be triggered by the use of specific system calls, their arguments, and by properties of the calling process. For example, Falco can easily detect incidents including but not limited to:
|
||||
##### Kubernetes
|
||||
|
||||
- A shell is running inside a container.
|
||||
| Tool | Link | Note |
|
||||
|----------|--------------------------------------------------------------------------------------------|--------------------------------------------------------------------|
|
||||
| Helm | [Chart Repository](https://github.com/falcosecurity/charts/tree/master/falco#introduction) | The Falco community offers regular helm chart releases. |
|
||||
| Minikube | [Tutorial](https://falco.org/docs/third-party/#minikube) | The Falco driver has been baked into minikube for easy deployment. |
|
||||
| Kind | [Tutorial](https://falco.org/docs/third-party/#kind) | Running Falco with kind requires a driver on the host system. |
|
||||
| GKE | [Tutorial](https://falco.org/docs/third-party/#gke) | We suggest using the eBPF driver for running Falco on GKE. |
|
||||
|
||||
### Developing
|
||||
|
||||
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/update-readme/userspace/falco/outputs.proto).
|
||||
The Falco Project supports various SDKs for this endpoint.
|
||||
|
||||
##### SDKs
|
||||
|
||||
| Language | Repository |
|
||||
|----------|---------------------------------------------------------|
|
||||
| Go | [client-go](https://github.com/falcosecurity/client-go) |
|
||||
| Rust | [client-rs](https://github.com/falcosecurity/client-rs) |
|
||||
| Python | [client-py](https://github.com/falcosecurity/client-py) |
|
||||
|
||||
|
||||
### What can Falco detect?
|
||||
|
||||
Falco can detect and alert on any behavior that involves making Linux system calls.
|
||||
Falco alerts can be triggered by the use of specific system calls, their arguments, and by properties of the calling process.
|
||||
For example, Falco can easily detect incidents including but not limited to:
|
||||
|
||||
- A shell is running inside a container or pod in Kubernetes.
|
||||
- A container is running in privileged mode, or is mounting a sensitive path, such as `/proc`, from the host.
|
||||
- A server process is spawning a child process of an unexpected type.
|
||||
- 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.
|
||||
|
||||
### Documentation
|
||||
|
||||
### Installing Falco
|
||||
The [Official Documentation](https://falco.org/docs/) is the best resource to learn about Falco.
|
||||
|
||||
You can find the latest release downloads on the official [release archive](https://bintray.com/falcosecurity)
|
||||
|
||||
Furthermore the comprehensive [installation guide](https://falco.org/docs/installation/) for Falco is available in the documentation website.
|
||||
|
||||
#### How do you compare Falco with other security tools?
|
||||
|
||||
One of the questions we often get when we talk about Falco is “How does Falco differ from other Linux security tools such as SELinux, AppArmor, Auditd, etc.?”. We wrote a [blog post](https://sysdig.com/blog/selinux-seccomp-falco-technical-discussion/) comparing Falco with other tools.
|
||||
|
||||
|
||||
Documentation
|
||||
---
|
||||
|
||||
See [Falco Documentation](https://falco.org/docs/) to quickly get started using Falco.
|
||||
|
||||
Join the Community
|
||||
---
|
||||
### Join the Community
|
||||
|
||||
To get involved with The Falco Project please visit [the community repository](https://github.com/falcosecurity/community) to find more.
|
||||
|
||||
License Terms
|
||||
---
|
||||
|
||||
Falco is licensed to you under the [Apache 2.0](./COPYING) open source license.
|
||||
|
||||
Contributing
|
||||
---
|
||||
### Contributing
|
||||
|
||||
See the [CONTRIBUTING.md](./CONTRIBUTING.md).
|
||||
|
||||
Security
|
||||
---
|
||||
|
||||
### Security Audit
|
||||
|
||||
A third party security audit was performed by Cure53, you can see the full report [here](./audits/SECURITY_AUDIT_2019_07.pdf).
|
||||
|
||||
### Reporting security vulnerabilities
|
||||
|
||||
Please report security vulnerabilities following the community process documented [here](https://github.com/falcosecurity/.github/blob/master/SECURITY.md).
|
||||
|
||||
### License Terms
|
||||
|
||||
Falco is licensed to you under the [Apache 2.0](./COPYING) open source license.
|
||||
|
||||
|
||||
[1]: https://dl.bintray.com/falcosecurity/rpm-dev
|
||||
[2]: https://dl.bintray.com/falcosecurity/rpm
|
||||
[3]: https://dl.bintray.com/falcosecurity/deb-dev/stable
|
||||
|
||||
@@ -35,7 +35,7 @@ else()
|
||||
URL "https://github.com/openssl/openssl/archive/OpenSSL_1_0_2n.tar.gz"
|
||||
URL_HASH "SHA256=4f4bc907caff1fee6ff8593729e5729891adcee412049153a3bb4db7625e8364"
|
||||
# END CHANGE for CVE-2017-3735, CVE-2017-3731, CVE-2017-3737, CVE-2017-3738, CVE-2017-3736
|
||||
CONFIGURE_COMMAND ./config shared --prefix=${OPENSSL_INSTALL_DIR}
|
||||
CONFIGURE_COMMAND ./config no-shared --prefix=${OPENSSL_INSTALL_DIR}
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_COMMAND ${CMD_MAKE} install)
|
||||
|
||||
@@ -19,13 +19,9 @@ else()
|
||||
set(CURL_INCLUDE_DIR "${CURL_BUNDLE_DIR}/include/")
|
||||
set(CURL_LIBRARIES "${CURL_BUNDLE_DIR}/lib/.libs/libcurl.a")
|
||||
|
||||
if(NOT USE_BUNDLED_OPENSSL)
|
||||
set(CURL_SSL_OPTION "--with-ssl")
|
||||
else()
|
||||
set(CURL_SSL_OPTION "--with-ssl=${OPENSSL_INSTALL_DIR}")
|
||||
message(STATUS "Using bundled curl in '${CURL_BUNDLE_DIR}'")
|
||||
message(STATUS "Using SSL for curl in '${CURL_SSL_OPTION}'")
|
||||
endif()
|
||||
set(CURL_SSL_OPTION "--with-ssl=${OPENSSL_INSTALL_DIR}")
|
||||
message(STATUS "Using bundled curl in '${CURL_BUNDLE_DIR}'")
|
||||
message(STATUS "Using SSL for curl in '${CURL_SSL_OPTION}'")
|
||||
|
||||
externalproject_add(
|
||||
curl
|
||||
|
||||
@@ -110,8 +110,8 @@ else()
|
||||
grpc
|
||||
DEPENDS openssl
|
||||
GIT_REPOSITORY https://github.com/grpc/grpc.git
|
||||
GIT_TAG v1.25.0
|
||||
GIT_SUBMODULES "third_party/protobuf third_party/zlib third_party/cares/cares"
|
||||
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}
|
||||
INSTALL_COMMAND ""
|
||||
@@ -121,6 +121,8 @@ else()
|
||||
HAS_SYSTEM_ZLIB=false
|
||||
HAS_SYSTEM_PROTOBUF=false
|
||||
HAS_SYSTEM_CARES=false
|
||||
HAS_EMBEDDED_OPENSSL_ALPN=false
|
||||
HAS_SYSTEM_OPENSSL_ALPN=true
|
||||
PKG_CONFIG_PATH=${OPENSSL_BUNDLE_DIR}
|
||||
PKG_CONFIG=${PKG_CONFIG_EXECUTABLE}
|
||||
PATH=${PROTOC_DIR}:$ENV{PATH}
|
||||
|
||||
@@ -10,26 +10,44 @@
|
||||
# "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.
|
||||
#
|
||||
if(NOT USE_BUNDLED_DEPS)
|
||||
find_path(JQ_INCLUDE jq.h PATH_SUFFIXES jq)
|
||||
find_library(JQ_LIB NAMES jq)
|
||||
if(JQ_INCLUDE AND JQ_LIB)
|
||||
message(STATUS "Found jq: include: ${JQ_INCLUDE}, lib: ${JQ_LIB}")
|
||||
else()
|
||||
message(FATAL_ERROR "Couldn't find system jq")
|
||||
endif()
|
||||
else()
|
||||
set(JQ_SRC "${PROJECT_BINARY_DIR}/jq-prefix/src/jq")
|
||||
message(STATUS "Using bundled jq in '${JQ_SRC}'")
|
||||
set(JQ_INCLUDE "${JQ_SRC}")
|
||||
set(JQ_LIB "${JQ_SRC}/.libs/libjq.a")
|
||||
ExternalProject_Add(
|
||||
jq
|
||||
URL "https://github.com/stedolan/jq/releases/download/jq-1.5/jq-1.5.tar.gz"
|
||||
URL_HASH "SHA256=c4d2bfec6436341113419debf479d833692cc5cdab7eb0326b5a4d4fbe9f493c"
|
||||
CONFIGURE_COMMAND ./configure --disable-maintainer-mode --enable-all-static --disable-dependency-tracking
|
||||
BUILD_COMMAND ${CMD_MAKE} LDFLAGS=-all-static
|
||||
BUILD_IN_SOURCE 1
|
||||
PATCH_COMMAND curl -L https://github.com/stedolan/jq/commit/8eb1367ca44e772963e704a700ef72ae2e12babd.patch | patch
|
||||
INSTALL_COMMAND "")
|
||||
endif()
|
||||
if (NOT USE_BUNDLED_DEPS)
|
||||
find_path(JQ_INCLUDE jq.h PATH_SUFFIXES jq)
|
||||
find_library(JQ_LIB NAMES jq)
|
||||
if (JQ_INCLUDE AND JQ_LIB)
|
||||
message(STATUS "Found jq: include: ${JQ_INCLUDE}, lib: ${JQ_LIB}")
|
||||
else ()
|
||||
message(FATAL_ERROR "Couldn't find system jq")
|
||||
endif ()
|
||||
else ()
|
||||
set(JQ_SRC "${PROJECT_BINARY_DIR}/jq-prefix/src/jq")
|
||||
message(STATUS "Using bundled jq in '${JQ_SRC}'")
|
||||
set(JQ_INCLUDE "${JQ_SRC}/target/include")
|
||||
set(JQ_INSTALL_DIR "${JQ_SRC}/target")
|
||||
set(JQ_LIB "${JQ_INSTALL_DIR}/lib/libjq.a")
|
||||
set(ONIGURUMA_LIB "${JQ_INSTALL_DIR}/lib/libonig.a")
|
||||
message(STATUS "Bundled jq: include: ${JQ_INCLUDE}, lib: ${JQ_LIB}")
|
||||
|
||||
# Why we mirror jq here?
|
||||
#
|
||||
# In their readme, jq claims that you don't have
|
||||
# to do autoreconf -fi when downloading a released tarball.
|
||||
#
|
||||
# However, they forgot to push the released makefiles
|
||||
# into their release tarbal.
|
||||
#
|
||||
# For this reason, we have to mirror their release after
|
||||
# doing the configuration ourselves.
|
||||
#
|
||||
# This is needed because many distros do not ship the right
|
||||
# version of autoreconf, making virtually impossible to build Falco on them.
|
||||
# Read more about it here:
|
||||
# https://github.com/stedolan/jq/issues/2061#issuecomment-593445920
|
||||
ExternalProject_Add(
|
||||
jq
|
||||
URL "https://dl.bintray.com/falcosecurity/dependencies/jq-1.6.tar.gz"
|
||||
URL_HASH "SHA256=787518068c35e244334cc79b8e56b60dbab352dff175b7f04a94f662b540bfd9"
|
||||
CONFIGURE_COMMAND ./configure --disable-maintainer-mode --enable-all-static --disable-dependency-tracking --with-oniguruma=builtin --prefix=${JQ_INSTALL_DIR}
|
||||
BUILD_COMMAND ${CMD_MAKE} LDFLAGS=-all-static
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_COMMAND ${CMD_MAKE} install)
|
||||
endif ()
|
||||
|
||||
@@ -10,23 +10,17 @@
|
||||
# "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.
|
||||
#
|
||||
if(NOT USE_BUNDLED_DEPS)
|
||||
find_library(LIBYAML_LIB NAMES libyaml.so)
|
||||
if(LIBYAML_LIB)
|
||||
message(STATUS "Found libyaml: lib: ${LIBYAML_LIB}")
|
||||
else()
|
||||
message(FATAL_ERROR "Couldn't find system libyaml")
|
||||
endif()
|
||||
else()
|
||||
set(LIBYAML_SRC "${PROJECT_BINARY_DIR}/libyaml-prefix/src/libyaml")
|
||||
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 --enable-static=true --enable-shared=false
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_COMMAND "")
|
||||
endif()
|
||||
|
||||
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
|
||||
INSTALL_COMMAND ${CMD_MAKE} install)
|
||||
|
||||
|
||||
@@ -18,22 +18,23 @@ set(SYSDIG_CMAKE_WORKING_DIR "${CMAKE_BINARY_DIR}/sysdig-repo")
|
||||
if(USE_BUNDLED_DEPS)
|
||||
# explicitly force this dependency to use the bundled OpenSSL
|
||||
set(USE_BUNDLED_OPENSSL ON)
|
||||
set(USE_BUNDLED_JQ ON)
|
||||
endif()
|
||||
|
||||
file(MAKE_DIRECTORY ${SYSDIG_CMAKE_WORKING_DIR})
|
||||
|
||||
# The sysdig git reference (branch name, commit hash, or tag)
|
||||
# To update sysdig version for the next release, change the default below
|
||||
# In case you want to test against another sysdig version just pass the variable - ie., `cmake -DSYSDIG_VERSION=dev ..`
|
||||
# The sysdig git reference (branch name, commit hash, or tag) To update sysdig version for the next release, change the
|
||||
# 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 "85c88952b018fdbce2464222c3303229f5bfcfad")
|
||||
set(SYSDIG_CHECKSUM "SHA256=6c3f5f2d699c9540e281f50cbc5cb6b580f0fc689798bc65d4a77f57f932a71c")
|
||||
set(SYSDIG_VERSION "ae104eb20ff0198a5dcb0c91cc36c86e7c3f25c7")
|
||||
set(SYSDIG_CHECKSUM "SHA256=43d274e4ce16b0d0e4dd00aab78006c902f36070d1cbb22d12a2685134a2ae51")
|
||||
endif()
|
||||
set(PROBE_VERSION "${SYSDIG_VERSION}")
|
||||
|
||||
# cd /path/to/build && cmake /path/to/source
|
||||
execute_process(COMMAND "${CMAKE_COMMAND}" -DSYSDIG_VERSION=${SYSDIG_VERSION} -DSYSDIG_CHECKSUM=${SYSDIG_CHECKSUM} ${SYSDIG_CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${SYSDIG_CMAKE_WORKING_DIR})
|
||||
|
||||
execute_process(COMMAND "${CMAKE_COMMAND}" -DSYSDIG_VERSION=${SYSDIG_VERSION} -DSYSDIG_CHECKSUM=${SYSDIG_CHECKSUM}
|
||||
${SYSDIG_CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${SYSDIG_CMAKE_WORKING_DIR})
|
||||
|
||||
# todo(leodido, fntlnz) > use the following one when CMake version will be >= 3.13
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -44,18 +44,10 @@
|
||||
items: ["vpa-recommender", "vpa-updater"]
|
||||
|
||||
- list: allowed_k8s_users
|
||||
items:
|
||||
[
|
||||
"minikube",
|
||||
"minikube-user",
|
||||
"kubelet",
|
||||
"kops",
|
||||
"admin",
|
||||
"kube",
|
||||
"kube-proxy",
|
||||
"kube-apiserver-healthcheck",
|
||||
"kubernetes-admin",
|
||||
vertical_pod_autoscaler_users,
|
||||
items: [
|
||||
"minikube", "minikube-user", "kubelet", "kops", "admin", "kube", "kube-proxy", "kube-apiserver-healthcheck",
|
||||
"kubernetes-admin",
|
||||
vertical_pod_autoscaler_users,
|
||||
]
|
||||
|
||||
- rule: Disallowed K8s User
|
||||
@@ -123,7 +115,6 @@
|
||||
- macro: health_endpoint
|
||||
condition: ka.uri=/healthz
|
||||
|
||||
# requires FALCO_ENGINE_VERSION 5
|
||||
- rule: Create Disallowed Pod
|
||||
desc: >
|
||||
Detect an attempt to start a pod with a container image outside of a list of allowed images.
|
||||
@@ -133,7 +124,6 @@
|
||||
source: k8s_audit
|
||||
tags: [k8s]
|
||||
|
||||
# requires FALCO_ENGINE_VERSION 5
|
||||
- rule: Create Privileged Pod
|
||||
desc: >
|
||||
Detect an attempt to start a pod with a privileged container
|
||||
@@ -146,8 +136,7 @@
|
||||
- macro: sensitive_vol_mount
|
||||
condition: >
|
||||
(ka.req.pod.volumes.hostpath intersects (/proc, /var/run/docker.sock, /, /etc, /root, /var/run/crio/crio.sock, /home/admin, /var/lib/kubelet, /var/lib/kubelet/pki, /etc/kubernetes, /etc/kubernetes/manifests))
|
||||
|
||||
# requires FALCO_ENGINE_VERSION 5
|
||||
|
||||
- rule: Create Sensitive Mount Pod
|
||||
desc: >
|
||||
Detect an attempt to start a pod with a volume from a sensitive host directory (i.e. /proc).
|
||||
@@ -159,7 +148,6 @@
|
||||
tags: [k8s]
|
||||
|
||||
# Corresponds to K8s CIS Benchmark 1.7.4
|
||||
# requires FALCO_ENGINE_VERSION 5
|
||||
- rule: Create HostNetwork Pod
|
||||
desc: Detect an attempt to start a pod using the host network.
|
||||
condition: kevt and pod and kcreate and ka.req.pod.host_network intersects (true) and not ka.req.pod.containers.image.repository in (falco_hostnetwork_images)
|
||||
@@ -191,7 +179,7 @@
|
||||
|
||||
- rule: Create/Modify Configmap With Private Credentials
|
||||
desc: >
|
||||
Detect creating/modifying a configmap containing a private credential (aws key, password, etc.)
|
||||
Detect creating/modifying a configmap containing a private credential (aws key, password, etc.)
|
||||
condition: kevt and configmap and kmodify and contains_private_credentials
|
||||
output: K8s configmap with private credential (user=%ka.user.name verb=%ka.verb configmap=%ka.req.configmap.name config=%ka.req.configmap.obj)
|
||||
priority: WARNING
|
||||
@@ -229,6 +217,19 @@
|
||||
source: k8s_audit
|
||||
tags: [k8s]
|
||||
|
||||
- macro: user_known_pod_debug_activities
|
||||
condition: (k8s_audit_never_true)
|
||||
|
||||
# Only works when feature gate EphemeralContainers is enabled
|
||||
- rule: EphemeralContainers Created
|
||||
desc: >
|
||||
Detect any ephemeral container created
|
||||
condition: kevt and pod_subresource and kmodify and ka.target.subresource in (ephemeralcontainers) and not user_known_pod_debug_activities
|
||||
output: Ephemeral container is created in pod (user=%ka.user.name pod=%ka.target.name ns=%ka.target.namespace ephemeral_container_name=%jevt.value[/requestObject/ephemeralContainers/0/name] ephemeral_container_image=%jevt.value[/requestObject/ephemeralContainers/0/image])
|
||||
priority: NOTICE
|
||||
source: k8s_audit
|
||||
tags: [k8s]
|
||||
|
||||
# In a local/user rules fie, you can append to this list to add additional allowed namespaces
|
||||
- list: allowed_namespaces
|
||||
items: [kube-system, kube-public, default]
|
||||
@@ -244,11 +245,14 @@
|
||||
- list: user_trusted_image_list
|
||||
items: []
|
||||
|
||||
- list: k8s_image_list
|
||||
items: [k8s.gcr.io/kube-apiserver, kope/kube-apiserver-healthcheck]
|
||||
|
||||
- macro: trusted_pod
|
||||
condition: (ka.req.pod.containers.image.repository in (user_trusted_image_list))
|
||||
condition: (ka.req.pod.containers.image.repository in (user_trusted_image_list) or
|
||||
ka.req.pod.containers.image.repository in (k8s_image_list))
|
||||
|
||||
# Detect any new pod created in the kube-system namespace
|
||||
# requires FALCO_ENGINE_VERSION 5
|
||||
- rule: Pod Created in Kube Namespace
|
||||
desc: Detect any attempt to create a pod in the kube-system or kube-public namespaces
|
||||
condition: kevt and pod and kcreate and ka.target.namespace in (kube-system, kube-public) and not trusted_pod
|
||||
@@ -293,7 +297,6 @@
|
||||
source: k8s_audit
|
||||
tags: [k8s]
|
||||
|
||||
# requires FALCO_ENGINE_VERSION 5
|
||||
- rule: ClusterRole With Wildcard Created
|
||||
desc: Detect any attempt to create a Role/ClusterRole with wildcard resources or verbs
|
||||
condition: kevt and (role or clusterrole) and kcreate and (ka.req.role.rules.resources intersects ("*") or ka.req.role.rules.verbs intersects ("*"))
|
||||
@@ -306,7 +309,6 @@
|
||||
condition: >
|
||||
(ka.req.role.rules.verbs intersects (create, update, patch, delete, deletecollection))
|
||||
|
||||
# requires FALCO_ENGINE_VERSION 5
|
||||
- rule: ClusterRole With Write Privileges Created
|
||||
desc: Detect any attempt to create a Role/ClusterRole that can perform write-related actions
|
||||
condition: kevt and (role or clusterrole) and kcreate and writable_verbs
|
||||
@@ -315,7 +317,6 @@
|
||||
source: k8s_audit
|
||||
tags: [k8s]
|
||||
|
||||
# requires FALCO_ENGINE_VERSION 5
|
||||
- rule: ClusterRole With Pod Exec Created
|
||||
desc: Detect any attempt to create a Role/ClusterRole that can exec to pods
|
||||
condition: kevt and (role or clusterrole) and kcreate and ka.req.role.rules.resources intersects ("pods/exec")
|
||||
@@ -479,26 +480,20 @@
|
||||
source: k8s_audit
|
||||
tags: [k8s]
|
||||
|
||||
|
||||
# This macro disables following rule, change to k8s_audit_never_true to enable it
|
||||
- macro: allowed_full_admin_users
|
||||
condition: (k8s_audit_always_true)
|
||||
|
||||
# This list includes some of the default user names for an administrator in several K8s installations
|
||||
- list: full_admin_k8s_users
|
||||
items:
|
||||
[
|
||||
"admin",
|
||||
"kubernetes-admin",
|
||||
"kubernetes-admin@kubernetes",
|
||||
"kubernetes-admin@cluster.local",
|
||||
"minikube-user",
|
||||
]
|
||||
items: ["admin", "kubernetes-admin", "kubernetes-admin@kubernetes", "kubernetes-admin@cluster.local", "minikube-user"]
|
||||
|
||||
# This rules detect an operation triggered by an user name that is
|
||||
# included in the list of those that are default administrators upon
|
||||
# cluster creation. This may signify a permission setting too broader.
|
||||
# As we can't check for role of the user on a general ka.* event, this
|
||||
# may or may not be an administrator. Customize the full_admin_k8s_users
|
||||
# This rules detect an operation triggered by an user name that is
|
||||
# included in the list of those that are default administrators upon
|
||||
# cluster creation. This may signify a permission setting too broader.
|
||||
# As we can't check for role of the user on a general ka.* event, this
|
||||
# may or may not be an administrator. Customize the full_admin_k8s_users
|
||||
# list to your needs, and activate at your discrection.
|
||||
|
||||
# # How to test:
|
||||
@@ -548,7 +543,7 @@
|
||||
output: >
|
||||
K8s Ingress Without TLS Cert Created (user=%ka.user.name ingress=%ka.target.name
|
||||
namespace=%ka.target.namespace)
|
||||
source: k8s_audit
|
||||
source: k8s_audit
|
||||
priority: WARNING
|
||||
tags: [k8s, network]
|
||||
|
||||
@@ -594,3 +589,4 @@
|
||||
priority: WARNING
|
||||
source: k8s_audit
|
||||
tags: [k8s]
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
# Required-Stop: $remote_fs $syslog
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: Falco syscall activity monitoring agent
|
||||
# Short-Description: Falco Cloud Native runtime security
|
||||
# Description: Falco is a system activity monitoring agent
|
||||
# driven by system calls with support for containers.
|
||||
### END INIT INFO
|
||||
@@ -62,11 +62,11 @@ do_start()
|
||||
# 0 if daemon has been started
|
||||
# 1 if daemon was already running
|
||||
# 2 if daemon could not be started
|
||||
if [ ! -d /sys/module/falco ]; then
|
||||
/sbin/modprobe falco || exit 2
|
||||
fi
|
||||
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
|
||||
|| return 1
|
||||
if [ ! -d /sys/module/falco ]; then
|
||||
/sbin/modprobe falco || exit 1
|
||||
fi
|
||||
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \
|
||||
$DAEMON_ARGS \
|
||||
|| return 2
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright (C) 2019 The Falco Authors.
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -18,10 +18,10 @@
|
||||
#
|
||||
|
||||
#
|
||||
# falco syscall monitoring agent
|
||||
# Falco Cloud Native runtime security
|
||||
#
|
||||
# chkconfig: 2345 55 45
|
||||
# description: Falco syscall monitoring agent
|
||||
# description: Falco Cloud Native runtime security
|
||||
#
|
||||
|
||||
### BEGIN INIT INFO
|
||||
@@ -52,10 +52,10 @@ start() {
|
||||
[ -x $exec ] || exit 5
|
||||
# [ -f $config ] || exit 6
|
||||
echo -n $"Starting $prog: "
|
||||
daemon $exec --daemon --pidfile=$pidfile
|
||||
if [ ! -d /sys/module/falco ]; then
|
||||
/sbin/modprobe falco || return $?
|
||||
fi
|
||||
daemon $exec --daemon --pidfile=$pidfile
|
||||
retval=$?
|
||||
echo
|
||||
[ $retval -eq 0 ] && touch $lockfile
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
- macro: allowed_k8s_containers
|
||||
condition: (ka.req.pod.containers.image.repository in (nginx))
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
-- 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.
|
||||
@@ -11,24 +11,25 @@
|
||||
-- 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")
|
||||
local compiler = {}
|
||||
|
||||
compiler.trim = parser.trim
|
||||
|
||||
function map(f, arr)
|
||||
local res = {}
|
||||
for i, v in ipairs(arr) do
|
||||
res[i] = f(v)
|
||||
end
|
||||
return res
|
||||
local res = {}
|
||||
for i,v in ipairs(arr) do
|
||||
res[i] = f(v)
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
function foldr(f, acc, arr)
|
||||
for i, v in pairs(arr) do
|
||||
acc = f(acc, v)
|
||||
end
|
||||
return acc
|
||||
for i,v in pairs(arr) do
|
||||
acc = f(acc, v)
|
||||
end
|
||||
return acc
|
||||
end
|
||||
|
||||
--[[
|
||||
@@ -46,192 +47,181 @@ end
|
||||
--]]
|
||||
|
||||
function copy_ast_obj(obj)
|
||||
if type(obj) ~= 'table' then
|
||||
return obj
|
||||
end
|
||||
local res = {}
|
||||
for k, v in pairs(obj) do
|
||||
res[copy_ast_obj(k)] = copy_ast_obj(v)
|
||||
end
|
||||
return res
|
||||
if type(obj) ~= 'table' then return obj end
|
||||
local res = {}
|
||||
for k, v in pairs(obj) do res[copy_ast_obj(k)] = copy_ast_obj(v) end
|
||||
return res
|
||||
end
|
||||
|
||||
function expand_macros(ast, defs, changed)
|
||||
|
||||
if (ast.type == "Rule") then
|
||||
return expand_macros(ast.filter, defs, changed)
|
||||
elseif ast.type == "Filter" then
|
||||
if (ast.value.type == "Macro") then
|
||||
if (defs[ast.value.value] == nil) then
|
||||
return false, "Undefined macro '" .. ast.value.value .. "' used in filter."
|
||||
end
|
||||
defs[ast.value.value].used = true
|
||||
ast.value = copy_ast_obj(defs[ast.value.value].ast)
|
||||
changed = true
|
||||
return true, changed
|
||||
end
|
||||
return expand_macros(ast.value, defs, changed)
|
||||
if (ast.type == "Rule") then
|
||||
return expand_macros(ast.filter, defs, changed)
|
||||
elseif ast.type == "Filter" then
|
||||
if (ast.value.type == "Macro") then
|
||||
if (defs[ast.value.value] == nil) then
|
||||
return false, "Undefined macro '".. ast.value.value .. "' used in filter."
|
||||
end
|
||||
defs[ast.value.value].used = true
|
||||
ast.value = copy_ast_obj(defs[ast.value.value].ast)
|
||||
changed = true
|
||||
return true, changed
|
||||
end
|
||||
return expand_macros(ast.value, defs, changed)
|
||||
|
||||
elseif ast.type == "BinaryBoolOp" then
|
||||
elseif ast.type == "BinaryBoolOp" then
|
||||
|
||||
if (ast.left.type == "Macro") then
|
||||
if (defs[ast.left.value] == nil) then
|
||||
return false, "Undefined macro '" .. ast.left.value .. "' used in filter."
|
||||
end
|
||||
defs[ast.left.value].used = true
|
||||
ast.left = copy_ast_obj(defs[ast.left.value].ast)
|
||||
changed = true
|
||||
end
|
||||
if (ast.left.type == "Macro") then
|
||||
if (defs[ast.left.value] == nil) then
|
||||
return false, "Undefined macro '".. ast.left.value .. "' used in filter."
|
||||
end
|
||||
defs[ast.left.value].used = true
|
||||
ast.left = copy_ast_obj(defs[ast.left.value].ast)
|
||||
changed = true
|
||||
end
|
||||
|
||||
if (ast.right.type == "Macro") then
|
||||
if (defs[ast.right.value] == nil) then
|
||||
return false, "Undefined macro " .. ast.right.value .. " used in filter."
|
||||
end
|
||||
defs[ast.right.value].used = true
|
||||
ast.right = copy_ast_obj(defs[ast.right.value].ast)
|
||||
changed = true
|
||||
end
|
||||
if (ast.right.type == "Macro") then
|
||||
if (defs[ast.right.value] == nil) then
|
||||
return false, "Undefined macro ".. ast.right.value .. " used in filter."
|
||||
end
|
||||
defs[ast.right.value].used = true
|
||||
ast.right = copy_ast_obj(defs[ast.right.value].ast)
|
||||
changed = true
|
||||
end
|
||||
|
||||
local status, changed_left = expand_macros(ast.left, defs, false)
|
||||
if status == false then
|
||||
return false, changed_left
|
||||
end
|
||||
local status, changed_right = expand_macros(ast.right, defs, false)
|
||||
if status == false then
|
||||
return false, changed_right
|
||||
end
|
||||
return true, changed or changed_left or changed_right
|
||||
local status, changed_left = expand_macros(ast.left, defs, false)
|
||||
if status == false then
|
||||
return false, changed_left
|
||||
end
|
||||
local status, changed_right = expand_macros(ast.right, defs, false)
|
||||
if status == false then
|
||||
return false, changed_right
|
||||
end
|
||||
return true, changed or changed_left or changed_right
|
||||
|
||||
elseif ast.type == "UnaryBoolOp" then
|
||||
if (ast.argument.type == "Macro") then
|
||||
if (defs[ast.argument.value] == nil) then
|
||||
return false, "Undefined macro " .. ast.argument.value .. " used in filter."
|
||||
end
|
||||
defs[ast.argument.value].used = true
|
||||
ast.argument = copy_ast_obj(defs[ast.argument.value].ast)
|
||||
changed = true
|
||||
end
|
||||
return expand_macros(ast.argument, defs, changed)
|
||||
end
|
||||
return true, changed
|
||||
elseif ast.type == "UnaryBoolOp" then
|
||||
if (ast.argument.type == "Macro") then
|
||||
if (defs[ast.argument.value] == nil) then
|
||||
return false, "Undefined macro ".. ast.argument.value .. " used in filter."
|
||||
end
|
||||
defs[ast.argument.value].used = true
|
||||
ast.argument = copy_ast_obj(defs[ast.argument.value].ast)
|
||||
changed = true
|
||||
end
|
||||
return expand_macros(ast.argument, defs, changed)
|
||||
end
|
||||
return true, changed
|
||||
end
|
||||
|
||||
function get_macros(ast, set)
|
||||
if (ast.type == "Macro") then
|
||||
set[ast.value] = true
|
||||
return set
|
||||
end
|
||||
if (ast.type == "Macro") then
|
||||
set[ast.value] = true
|
||||
return set
|
||||
end
|
||||
|
||||
if ast.type == "Filter" then
|
||||
return get_macros(ast.value, set)
|
||||
end
|
||||
if ast.type == "Filter" then
|
||||
return get_macros(ast.value, set)
|
||||
end
|
||||
|
||||
if ast.type == "BinaryBoolOp" then
|
||||
local left = get_macros(ast.left, {})
|
||||
local right = get_macros(ast.right, {})
|
||||
if ast.type == "BinaryBoolOp" then
|
||||
local left = get_macros(ast.left, {})
|
||||
local right = get_macros(ast.right, {})
|
||||
|
||||
for m, _ in pairs(left) do
|
||||
set[m] = true
|
||||
end
|
||||
for m, _ in pairs(right) do
|
||||
set[m] = true
|
||||
end
|
||||
for m, _ in pairs(left) do set[m] = true end
|
||||
for m, _ in pairs(right) do set[m] = true end
|
||||
|
||||
return set
|
||||
end
|
||||
if ast.type == "UnaryBoolOp" then
|
||||
return get_macros(ast.argument, set)
|
||||
end
|
||||
return set
|
||||
return set
|
||||
end
|
||||
if ast.type == "UnaryBoolOp" then
|
||||
return get_macros(ast.argument, set)
|
||||
end
|
||||
return set
|
||||
end
|
||||
|
||||
function get_filters(ast)
|
||||
|
||||
local filters = {}
|
||||
local filters = {}
|
||||
|
||||
function cb(node)
|
||||
if node.type == "FieldName" then
|
||||
filters[node.value] = 1
|
||||
end
|
||||
end
|
||||
function cb(node)
|
||||
if node.type == "FieldName" then
|
||||
filters[node.value] = 1
|
||||
end
|
||||
end
|
||||
|
||||
parser.traverse_ast(ast.filter.value, {
|
||||
FieldName = 1
|
||||
}, cb)
|
||||
parser.traverse_ast(ast.filter.value, {FieldName=1} , cb)
|
||||
|
||||
return filters
|
||||
return filters
|
||||
end
|
||||
|
||||
function compiler.expand_lists_in(source, list_defs)
|
||||
|
||||
for name, def in pairs(list_defs) do
|
||||
for name, def in pairs(list_defs) do
|
||||
|
||||
local bpos = string.find(source, name, 1, true)
|
||||
local bpos = string.find(source, name, 1, true)
|
||||
|
||||
while bpos ~= nil do
|
||||
def.used = true
|
||||
while bpos ~= nil do
|
||||
def.used = true
|
||||
|
||||
local epos = bpos + string.len(name)
|
||||
local epos = bpos + string.len(name)
|
||||
|
||||
-- The characters surrounding the name must be delimiters of beginning/end of string
|
||||
if (bpos == 1 or string.match(string.sub(source, bpos - 1, bpos - 1), "[%s(),=]")) and
|
||||
(epos > string.len(source) or string.match(string.sub(source, epos, epos), "[%s(),=]")) then
|
||||
new_source = ""
|
||||
-- The characters surrounding the name must be delimiters of beginning/end of string
|
||||
if (bpos == 1 or string.match(string.sub(source, bpos-1, bpos-1), "[%s(),=]")) and (epos > string.len(source) or string.match(string.sub(source, epos, epos), "[%s(),=]")) then
|
||||
new_source = ""
|
||||
|
||||
if bpos > 1 then
|
||||
new_source = new_source .. string.sub(source, 1, bpos - 1)
|
||||
end
|
||||
if bpos > 1 then
|
||||
new_source = new_source..string.sub(source, 1, bpos-1)
|
||||
end
|
||||
|
||||
sub = table.concat(def.items, ", ")
|
||||
sub = table.concat(def.items, ", ")
|
||||
|
||||
new_source = new_source .. sub
|
||||
new_source = new_source..sub
|
||||
|
||||
if epos <= string.len(source) then
|
||||
new_source = new_source .. string.sub(source, epos, string.len(source))
|
||||
end
|
||||
if epos <= string.len(source) then
|
||||
new_source = new_source..string.sub(source, epos, string.len(source))
|
||||
end
|
||||
|
||||
source = new_source
|
||||
bpos = bpos + (string.len(sub) - string.len(name))
|
||||
end
|
||||
source = new_source
|
||||
bpos = bpos + (string.len(sub)-string.len(name))
|
||||
end
|
||||
|
||||
bpos = string.find(source, name, bpos + 1, true)
|
||||
end
|
||||
end
|
||||
bpos = string.find(source, name, bpos+1, true)
|
||||
end
|
||||
end
|
||||
|
||||
return source
|
||||
return source
|
||||
end
|
||||
|
||||
function compiler.compile_macro(line, macro_defs, list_defs)
|
||||
|
||||
line = compiler.expand_lists_in(line, list_defs)
|
||||
line = compiler.expand_lists_in(line, list_defs)
|
||||
|
||||
local ast, error_msg = parser.parse_filter(line)
|
||||
local ast, error_msg = parser.parse_filter(line)
|
||||
|
||||
if (error_msg) then
|
||||
msg = "Compilation error when compiling \"" .. line .. "\": " .. error_msg
|
||||
return false, msg
|
||||
end
|
||||
if (error_msg) then
|
||||
msg = "Compilation error when compiling \""..line.."\": ".. error_msg
|
||||
return false, msg
|
||||
end
|
||||
|
||||
-- Simply as a validation step, try to expand all macros in this
|
||||
-- macro's condition. This changes the ast, so we make a copy
|
||||
-- first.
|
||||
local ast_copy = copy_ast_obj(ast)
|
||||
-- Simply as a validation step, try to expand all macros in this
|
||||
-- macro's condition. This changes the ast, so we make a copy
|
||||
-- first.
|
||||
local ast_copy = copy_ast_obj(ast)
|
||||
|
||||
if (ast.type == "Rule") then
|
||||
-- Line is a filter, so expand macro references
|
||||
repeat
|
||||
status, expanded = expand_macros(ast_copy, macro_defs, false)
|
||||
if status == false then
|
||||
msg = "Compilation error when compiling \"" .. line .. "\": " .. expanded
|
||||
return false, msg
|
||||
end
|
||||
until expanded == false
|
||||
if (ast.type == "Rule") then
|
||||
-- Line is a filter, so expand macro references
|
||||
repeat
|
||||
status, expanded = expand_macros(ast_copy, macro_defs, false)
|
||||
if status == false then
|
||||
msg = "Compilation error when compiling \""..line.."\": ".. expanded
|
||||
return false, msg
|
||||
end
|
||||
until expanded == false
|
||||
|
||||
else
|
||||
return false, "Unexpected top-level AST type: " .. ast.type
|
||||
end
|
||||
else
|
||||
return false, "Unexpected top-level AST type: "..ast.type
|
||||
end
|
||||
|
||||
return true, ast
|
||||
return true, ast
|
||||
end
|
||||
|
||||
--[[
|
||||
@@ -239,31 +229,32 @@ end
|
||||
--]]
|
||||
function compiler.compile_filter(name, source, macro_defs, list_defs)
|
||||
|
||||
source = compiler.expand_lists_in(source, list_defs)
|
||||
source = compiler.expand_lists_in(source, list_defs)
|
||||
|
||||
local ast, error_msg = parser.parse_filter(source)
|
||||
local ast, error_msg = parser.parse_filter(source)
|
||||
|
||||
if (error_msg) then
|
||||
msg = "Compilation error when compiling \"" .. source .. "\": " .. error_msg
|
||||
return false, msg
|
||||
end
|
||||
if (error_msg) then
|
||||
msg = "Compilation error when compiling \""..source.."\": "..error_msg
|
||||
return false, msg
|
||||
end
|
||||
|
||||
if (ast.type == "Rule") then
|
||||
-- Line is a filter, so expand macro references
|
||||
repeat
|
||||
status, expanded = expand_macros(ast, macro_defs, false)
|
||||
if status == false then
|
||||
return false, expanded
|
||||
end
|
||||
until expanded == false
|
||||
if (ast.type == "Rule") then
|
||||
-- Line is a filter, so expand macro references
|
||||
repeat
|
||||
status, expanded = expand_macros(ast, macro_defs, false)
|
||||
if status == false then
|
||||
return false, expanded
|
||||
end
|
||||
until expanded == false
|
||||
|
||||
else
|
||||
return false, "Unexpected top-level AST type: " .. ast.type
|
||||
end
|
||||
else
|
||||
return false, "Unexpected top-level AST type: "..ast.type
|
||||
end
|
||||
|
||||
filters = get_filters(ast)
|
||||
filters = get_filters(ast)
|
||||
|
||||
return true, ast, filters
|
||||
return true, ast, filters
|
||||
end
|
||||
|
||||
|
||||
return compiler
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
-- 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.
|
||||
@@ -12,6 +12,7 @@
|
||||
-- See the License for the specific language governing permissions and
|
||||
-- limitations under the License.
|
||||
--
|
||||
|
||||
--[[
|
||||
Falco grammar and parser.
|
||||
|
||||
@@ -39,258 +40,232 @@ local space = lpeg.space
|
||||
|
||||
-- creates an error message for the input string
|
||||
local function syntaxerror(errorinfo, pos, msg)
|
||||
local error_msg = "%s: syntax error, %s"
|
||||
return string.format(error_msg, pos, msg)
|
||||
local error_msg = "%s: syntax error, %s"
|
||||
return string.format(error_msg, pos, msg)
|
||||
end
|
||||
|
||||
-- gets the farthest failure position
|
||||
local function getffp(s, i, t)
|
||||
return t.ffp or i, t
|
||||
return t.ffp or i, t
|
||||
end
|
||||
|
||||
-- gets the table that contains the error information
|
||||
local function geterrorinfo()
|
||||
return Cmt(Carg(1), getffp) * (C(V "OneWord") + Cc("EOF")) / function(t, u)
|
||||
t.unexpected = u
|
||||
return t
|
||||
end
|
||||
return Cmt(Carg(1), getffp) * (C(V "OneWord") + Cc("EOF")) / function(t, u)
|
||||
t.unexpected = u
|
||||
return t
|
||||
end
|
||||
end
|
||||
|
||||
-- creates an errror message using the farthest failure position
|
||||
local function errormsg()
|
||||
return geterrorinfo() / function(t)
|
||||
local p = t.ffp or 1
|
||||
local msg = "unexpected '%s', expecting %s"
|
||||
msg = string.format(msg, t.unexpected, t.expected)
|
||||
return nil, syntaxerror(t, p, msg)
|
||||
end
|
||||
return geterrorinfo() / function(t)
|
||||
local p = t.ffp or 1
|
||||
local msg = "unexpected '%s', expecting %s"
|
||||
msg = string.format(msg, t.unexpected, t.expected)
|
||||
return nil, syntaxerror(t, p, msg)
|
||||
end
|
||||
end
|
||||
|
||||
-- reports a syntactic error
|
||||
local function report_error()
|
||||
return errormsg()
|
||||
return errormsg()
|
||||
end
|
||||
|
||||
--- sets the farthest failure position and the expected tokens
|
||||
local function setffp(s, i, t, n)
|
||||
if not t.ffp or i > t.ffp then
|
||||
t.ffp = i
|
||||
t.list = {}
|
||||
t.list[n] = n
|
||||
t.expected = "'" .. n .. "'"
|
||||
elseif i == t.ffp then
|
||||
if not t.list[n] then
|
||||
t.list[n] = n
|
||||
t.expected = "'" .. n .. "', " .. t.expected
|
||||
end
|
||||
end
|
||||
return false
|
||||
if not t.ffp or i > t.ffp then
|
||||
t.ffp = i
|
||||
t.list = {}
|
||||
t.list[n] = n
|
||||
t.expected = "'" .. n .. "'"
|
||||
elseif i == t.ffp then
|
||||
if not t.list[n] then
|
||||
t.list[n] = n
|
||||
t.expected = "'" .. n .. "', " .. t.expected
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function updateffp(name)
|
||||
return Cmt(Carg(1) * Cc(name), setffp)
|
||||
return Cmt(Carg(1) * Cc(name), setffp)
|
||||
end
|
||||
|
||||
-- regular combinators and auxiliary functions
|
||||
|
||||
local function token(pat, name)
|
||||
return pat * V "Skip" + updateffp(name) * P(false)
|
||||
return pat * V "Skip" + updateffp(name) * P(false)
|
||||
end
|
||||
|
||||
local function symb(str)
|
||||
return token(P(str), str)
|
||||
return token(P(str), str)
|
||||
end
|
||||
|
||||
local function kw(str)
|
||||
return token(P(str) * -V "idRest", str)
|
||||
return token(P(str) * -V "idRest", str)
|
||||
end
|
||||
|
||||
local function list(pat, sep)
|
||||
return Ct(pat ^ -1 * (sep * pat ^ 0) ^ 0) / function(elements)
|
||||
return {
|
||||
type = "List",
|
||||
elements = elements
|
||||
}
|
||||
end
|
||||
return Ct(pat ^ -1 * (sep * pat ^ 0) ^ 0) / function(elements)
|
||||
return {type = "List", elements = elements}
|
||||
end
|
||||
end
|
||||
|
||||
-- http://lua-users.org/wiki/StringTrim
|
||||
--http://lua-users.org/wiki/StringTrim
|
||||
function trim(s)
|
||||
if (type(s) ~= "string") then
|
||||
return s
|
||||
end
|
||||
return (s:gsub("^%s*(.-)%s*$", "%1"))
|
||||
if (type(s) ~= "string") then
|
||||
return s
|
||||
end
|
||||
return (s:gsub("^%s*(.-)%s*$", "%1"))
|
||||
end
|
||||
parser.trim = trim
|
||||
|
||||
local function terminal(tag)
|
||||
-- Rather than trim the whitespace in this way, it would be nicer to exclude it from the capture...
|
||||
return token(V(tag), tag) / function(tok)
|
||||
val = tok
|
||||
if tag ~= "String" then
|
||||
-- Rather than trim the whitespace in this way, it would be nicer to exclude it from the capture...
|
||||
return token(V(tag), tag) / function(tok)
|
||||
val = tok
|
||||
if tag ~= "String" then
|
||||
val = trim(tok)
|
||||
end
|
||||
return {
|
||||
type = tag,
|
||||
value = val
|
||||
}
|
||||
end
|
||||
end
|
||||
return {type = tag, value = val}
|
||||
end
|
||||
end
|
||||
|
||||
local function unaryboolop(op, e)
|
||||
return {
|
||||
type = "UnaryBoolOp",
|
||||
operator = op,
|
||||
argument = e
|
||||
}
|
||||
return {type = "UnaryBoolOp", operator = op, argument = e}
|
||||
end
|
||||
|
||||
local function unaryrelop(e, op)
|
||||
return {
|
||||
type = "UnaryRelOp",
|
||||
operator = op,
|
||||
argument = e
|
||||
}
|
||||
return {type = "UnaryRelOp", operator = op, argument = e}
|
||||
end
|
||||
|
||||
local function binaryop(e1, op, e2)
|
||||
if not op then
|
||||
return e1
|
||||
else
|
||||
return {
|
||||
type = "BinaryBoolOp",
|
||||
operator = op,
|
||||
left = e1,
|
||||
right = e2
|
||||
}
|
||||
end
|
||||
if not op then
|
||||
return e1
|
||||
else
|
||||
return {type = "BinaryBoolOp", operator = op, left = e1, right = e2}
|
||||
end
|
||||
end
|
||||
|
||||
local function bool(pat, sep)
|
||||
return Cf(pat * Cg(sep * pat) ^ 0, binaryop)
|
||||
return Cf(pat * Cg(sep * pat) ^ 0, binaryop)
|
||||
end
|
||||
|
||||
local function rel(left, sep, right)
|
||||
return left * sep * right / function(e1, op, e2)
|
||||
return {
|
||||
type = "BinaryRelOp",
|
||||
operator = op,
|
||||
left = e1,
|
||||
right = e2
|
||||
}
|
||||
end
|
||||
return left * sep * right / function(e1, op, e2)
|
||||
return {type = "BinaryRelOp", operator = op, left = e1, right = e2}
|
||||
end
|
||||
end
|
||||
|
||||
-- grammar
|
||||
|
||||
local function filter(e)
|
||||
return {
|
||||
type = "Filter",
|
||||
value = e
|
||||
}
|
||||
return {type = "Filter", value = e}
|
||||
end
|
||||
|
||||
local function rule(filter)
|
||||
return {
|
||||
type = "Rule",
|
||||
filter = filter
|
||||
}
|
||||
return {type = "Rule", filter = filter}
|
||||
end
|
||||
|
||||
local G = {
|
||||
V "Start", -- Entry rule
|
||||
Start = V "Skip" * (V "Comment" + V "Rule" / rule) ^ -1 * -1 + report_error(),
|
||||
-- Grammar
|
||||
Comment = P "#" * P(1) ^ 0,
|
||||
Rule = V "Filter" / filter * ((V "Skip") ^ -1),
|
||||
Filter = V "OrExpression",
|
||||
OrExpression = bool(V "AndExpression", V "OrOp"),
|
||||
AndExpression = bool(V "NotExpression", V "AndOp"),
|
||||
NotExpression = V "UnaryBoolOp" * V "NotExpression" / unaryboolop + V "ExistsExpression",
|
||||
ExistsExpression = terminal "FieldName" * V "ExistsOp" / unaryrelop + V "MacroExpression",
|
||||
MacroExpression = terminal "Macro" + V "RelationalExpression",
|
||||
RelationalExpression = rel(terminal "FieldName", V "RelOp", V "Value") +
|
||||
rel(terminal "FieldName", V "SetOp", V "InList") + V "PrimaryExp",
|
||||
PrimaryExp = symb("(") * V "Filter" * symb(")"),
|
||||
FuncArgs = symb("(") * list(V "Value", symb(",")) * symb(")"),
|
||||
-- Terminals
|
||||
Value = terminal "Number" + terminal "String" + terminal "BareString",
|
||||
InList = symb("(") * list(V "Value", symb(",")) * symb(")"),
|
||||
-- Lexemes
|
||||
Space = space ^ 1,
|
||||
Skip = (V "Space") ^ 0,
|
||||
idStart = alpha + P("_"),
|
||||
idRest = alnum + P("_"),
|
||||
Identifier = V "idStart" * V "idRest" ^ 0,
|
||||
Macro = V "idStart" * V "idRest" ^ 0 * -P ".",
|
||||
Int = digit ^ 1,
|
||||
PathString = (alnum + S ",.-_/*?") ^ 1,
|
||||
PortRangeString = (V "Int" + S ":,") ^ 1,
|
||||
Index = V "PortRangeString" + V "Int" + V "PathString",
|
||||
FieldName = V "Identifier" * (P "." + V "Identifier") ^ 1 * (P "[" * V "Index" * P "]") ^ -1,
|
||||
Name = C(V "Identifier") * -V "idRest",
|
||||
Hex = (P("0x") + P("0X")) * xdigit ^ 1,
|
||||
Expo = S("eE") * S("+-") ^ -1 * digit ^ 1,
|
||||
Float = (((digit ^ 1 * P(".") * digit ^ 0) + (P(".") * digit ^ 1)) * V "Expo" ^ -1) + (digit ^ 1 * V "Expo"),
|
||||
Number = C(V "Hex" + V "Float" + V "Int") / function(n)
|
||||
return tonumber(n)
|
||||
end,
|
||||
String = (P '"' * C(((P "\\" * P(1)) + (P(1) - P '"')) ^ 0) * P '"' + P "'" *
|
||||
C(((P "\\" * P(1)) + (P(1) - P "'")) ^ 0) * P "'"),
|
||||
BareString = C((P(1) - S " (),=") ^ 1),
|
||||
OrOp = kw("or") / "or",
|
||||
AndOp = kw("and") / "and",
|
||||
Colon = kw(":"),
|
||||
RelOp = symb("=") / "=" + symb("==") / "==" + symb("!=") / "!=" + symb("<=") / "<=" + symb(">=") / ">=" + symb("<") /
|
||||
"<" + symb(">") / ">" + symb("contains") / "contains" + symb("icontains") / "icontains" + symb("glob") / "glob" +
|
||||
symb("startswith") / "startswith" + symb("endswith") / "endswith",
|
||||
SetOp = kw("in") / "in" + kw("intersects") / "intersects" + kw("pmatch") / "pmatch",
|
||||
UnaryBoolOp = kw("not") / "not",
|
||||
ExistsOp = kw("exists") / "exists",
|
||||
-- for error reporting
|
||||
OneWord = V "Name" + V "Number" + V "String" + P(1)
|
||||
V "Start", -- Entry rule
|
||||
Start = V "Skip" * (V "Comment" + V "Rule" / rule) ^ -1 * -1 + report_error(),
|
||||
-- Grammar
|
||||
Comment = P "#" * P(1) ^ 0,
|
||||
Rule = V "Filter" / filter * ((V "Skip") ^ -1),
|
||||
Filter = V "OrExpression",
|
||||
OrExpression = bool(V "AndExpression", V "OrOp"),
|
||||
AndExpression = bool(V "NotExpression", V "AndOp"),
|
||||
NotExpression = V "UnaryBoolOp" * V "NotExpression" / unaryboolop + V "ExistsExpression",
|
||||
ExistsExpression = terminal "FieldName" * V "ExistsOp" / unaryrelop + V "MacroExpression",
|
||||
MacroExpression = terminal "Macro" + V "RelationalExpression",
|
||||
RelationalExpression = rel(terminal "FieldName", V "RelOp", V "Value") +
|
||||
rel(terminal "FieldName", V "SetOp", V "InList") +
|
||||
V "PrimaryExp",
|
||||
PrimaryExp = symb("(") * V "Filter" * symb(")"),
|
||||
FuncArgs = symb("(") * list(V "Value", symb(",")) * symb(")"),
|
||||
-- Terminals
|
||||
Value = terminal "Number" + terminal "String" + terminal "BareString",
|
||||
InList = symb("(") * list(V "Value", symb(",")) * symb(")"),
|
||||
-- Lexemes
|
||||
Space = space ^ 1,
|
||||
Skip = (V "Space") ^ 0,
|
||||
idStart = alpha + P("_"),
|
||||
idRest = alnum + P("_"),
|
||||
Identifier = V "idStart" * V "idRest" ^ 0,
|
||||
Macro = V "idStart" * V "idRest" ^ 0 * -P ".",
|
||||
Int = digit ^ 1,
|
||||
PathString = (alnum + S ",.-_/*?") ^ 1,
|
||||
PortRangeString = (V "Int" + S ":,") ^ 1,
|
||||
Index = V "PortRangeString" + V "Int" + V "PathString",
|
||||
FieldName = V "Identifier" * (P "." + V "Identifier") ^ 1 * (P "[" * V "Index" * P "]") ^ -1,
|
||||
Name = C(V "Identifier") * -V "idRest",
|
||||
Hex = (P("0x") + P("0X")) * xdigit ^ 1,
|
||||
Expo = S("eE") * S("+-") ^ -1 * digit ^ 1,
|
||||
Float = (((digit ^ 1 * P(".") * digit ^ 0) + (P(".") * digit ^ 1)) * V "Expo" ^ -1) + (digit ^ 1 * V "Expo"),
|
||||
Number = C(V "Hex" + V "Float" + V "Int") / function(n)
|
||||
return tonumber(n)
|
||||
end,
|
||||
String = (P '"' * C(((P "\\" * P(1)) + (P(1) - P '"')) ^ 0) * P '"' +
|
||||
P "'" * C(((P "\\" * P(1)) + (P(1) - P "'")) ^ 0) * P "'"),
|
||||
BareString = C((P(1) - S " (),=") ^ 1),
|
||||
OrOp = kw("or") / "or",
|
||||
AndOp = kw("and") / "and",
|
||||
Colon = kw(":"),
|
||||
RelOp = symb("=") / "=" + symb("==") / "==" + symb("!=") / "!=" + symb("<=") / "<=" + symb(">=") / ">=" +
|
||||
symb("<") / "<" +
|
||||
symb(">") / ">" +
|
||||
symb("contains") / "contains" +
|
||||
symb("icontains") / "icontains" +
|
||||
symb("glob") / "glob" +
|
||||
symb("startswith") / "startswith" +
|
||||
symb("endswith") / "endswith",
|
||||
SetOp = kw("in") / "in" + kw("intersects") / "intersects" + kw("pmatch") / "pmatch",
|
||||
UnaryBoolOp = kw("not") / "not",
|
||||
ExistsOp = kw("exists") / "exists",
|
||||
-- for error reporting
|
||||
OneWord = V "Name" + V "Number" + V "String" + P(1)
|
||||
}
|
||||
|
||||
--[[
|
||||
Parses a single filter and returns the AST.
|
||||
--]]
|
||||
function parser.parse_filter(subject)
|
||||
local errorinfo = {
|
||||
subject = subject
|
||||
}
|
||||
lpeg.setmaxstack(1000)
|
||||
local ast, error_msg = lpeg.match(G, subject, nil, errorinfo)
|
||||
return ast, error_msg
|
||||
local errorinfo = {subject = subject}
|
||||
lpeg.setmaxstack(1000)
|
||||
local ast, error_msg = lpeg.match(G, subject, nil, errorinfo)
|
||||
return ast, error_msg
|
||||
end
|
||||
|
||||
function print_ast(ast, level)
|
||||
local t = ast.type
|
||||
level = level or 0
|
||||
local prefix = string.rep(" ", level * 4)
|
||||
level = level + 1
|
||||
local t = ast.type
|
||||
level = level or 0
|
||||
local prefix = string.rep(" ", level * 4)
|
||||
level = level + 1
|
||||
|
||||
if t == "Rule" then
|
||||
print_ast(ast.filter, level)
|
||||
elseif t == "Filter" then
|
||||
print_ast(ast.value, level)
|
||||
elseif t == "BinaryBoolOp" or t == "BinaryRelOp" then
|
||||
print(prefix .. ast.operator)
|
||||
print_ast(ast.left, level)
|
||||
print_ast(ast.right, level)
|
||||
elseif t == "UnaryRelOp" or t == "UnaryBoolOp" then
|
||||
print(prefix .. ast.operator)
|
||||
print_ast(ast.argument, level)
|
||||
elseif t == "List" then
|
||||
for i, v in ipairs(ast.elements) do
|
||||
print_ast(v, level)
|
||||
end
|
||||
elseif t == "FieldName" or t == "Number" or t == "String" or t == "BareString" or t == "Macro" then
|
||||
print(prefix .. t .. " " .. ast.value)
|
||||
elseif t == "MacroDef" then
|
||||
-- don't print for now
|
||||
else
|
||||
error("Unexpected type in print_ast: " .. t)
|
||||
end
|
||||
if t == "Rule" then
|
||||
print_ast(ast.filter, level)
|
||||
elseif t == "Filter" then
|
||||
print_ast(ast.value, level)
|
||||
elseif t == "BinaryBoolOp" or t == "BinaryRelOp" then
|
||||
print(prefix .. ast.operator)
|
||||
print_ast(ast.left, level)
|
||||
print_ast(ast.right, level)
|
||||
elseif t == "UnaryRelOp" or t == "UnaryBoolOp" then
|
||||
print(prefix .. ast.operator)
|
||||
print_ast(ast.argument, level)
|
||||
elseif t == "List" then
|
||||
for i, v in ipairs(ast.elements) do
|
||||
print_ast(v, level)
|
||||
end
|
||||
elseif t == "FieldName" or t == "Number" or t == "String" or t == "BareString" or t == "Macro" then
|
||||
print(prefix .. t .. " " .. ast.value)
|
||||
elseif t == "MacroDef" then
|
||||
-- don't print for now
|
||||
else
|
||||
error("Unexpected type in print_ast: " .. t)
|
||||
end
|
||||
end
|
||||
parser.print_ast = print_ast
|
||||
|
||||
@@ -300,32 +275,32 @@ parser.print_ast = print_ast
|
||||
-- cb(ast_node, ctx)
|
||||
-- ctx is optional.
|
||||
function traverse_ast(ast, node_types, cb, ctx)
|
||||
local t = ast.type
|
||||
local t = ast.type
|
||||
|
||||
if node_types[t] ~= nil then
|
||||
cb(ast, ctx)
|
||||
end
|
||||
if node_types[t] ~= nil then
|
||||
cb(ast, ctx)
|
||||
end
|
||||
|
||||
if t == "Rule" then
|
||||
traverse_ast(ast.filter, node_types, cb, ctx)
|
||||
elseif t == "Filter" then
|
||||
traverse_ast(ast.value, node_types, cb, ctx)
|
||||
elseif t == "BinaryBoolOp" or t == "BinaryRelOp" then
|
||||
traverse_ast(ast.left, node_types, cb, ctx)
|
||||
traverse_ast(ast.right, node_types, cb, ctx)
|
||||
elseif t == "UnaryRelOp" or t == "UnaryBoolOp" then
|
||||
traverse_ast(ast.argument, node_types, cb, ctx)
|
||||
elseif t == "List" then
|
||||
for i, v in ipairs(ast.elements) do
|
||||
traverse_ast(v, node_types, cb, ctx)
|
||||
end
|
||||
elseif t == "MacroDef" then
|
||||
traverse_ast(ast.value, node_types, cb, ctx)
|
||||
elseif t == "FieldName" or t == "Number" or t == "String" or t == "BareString" or t == "Macro" then
|
||||
-- do nothing, no traversal needed
|
||||
else
|
||||
error("Unexpected type in traverse_ast: " .. t)
|
||||
end
|
||||
if t == "Rule" then
|
||||
traverse_ast(ast.filter, node_types, cb, ctx)
|
||||
elseif t == "Filter" then
|
||||
traverse_ast(ast.value, node_types, cb, ctx)
|
||||
elseif t == "BinaryBoolOp" or t == "BinaryRelOp" then
|
||||
traverse_ast(ast.left, node_types, cb, ctx)
|
||||
traverse_ast(ast.right, node_types, cb, ctx)
|
||||
elseif t == "UnaryRelOp" or t == "UnaryBoolOp" then
|
||||
traverse_ast(ast.argument, node_types, cb, ctx)
|
||||
elseif t == "List" then
|
||||
for i, v in ipairs(ast.elements) do
|
||||
traverse_ast(v, node_types, cb, ctx)
|
||||
end
|
||||
elseif t == "MacroDef" then
|
||||
traverse_ast(ast.value, node_types, cb, ctx)
|
||||
elseif t == "FieldName" or t == "Number" or t == "String" or t == "BareString" or t == "Macro" then
|
||||
-- do nothing, no traversal needed
|
||||
else
|
||||
error("Unexpected type in traverse_ast: " .. t)
|
||||
end
|
||||
end
|
||||
parser.traverse_ast = traverse_ast
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
-- 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.
|
||||
@@ -12,52 +12,55 @@
|
||||
-- See the License for the specific language governing permissions and
|
||||
-- limitations under the License.
|
||||
--
|
||||
|
||||
local parser = require("parser")
|
||||
local sinsp_rule_utils = {}
|
||||
|
||||
function sinsp_rule_utils.check_for_ignored_syscalls_events(ast, filter_type, source)
|
||||
|
||||
function check_syscall(val)
|
||||
if ignored_syscalls[val] then
|
||||
error("Ignored syscall \"" .. val .. "\" in " .. filter_type .. ": " .. source)
|
||||
end
|
||||
function check_syscall(val)
|
||||
if ignored_syscalls[val] then
|
||||
error("Ignored syscall \""..val.."\" in "..filter_type..": "..source)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function check_event(val)
|
||||
if ignored_events[val] then
|
||||
error("Ignored event \"" .. val .. "\" in " .. filter_type .. ": " .. source)
|
||||
end
|
||||
end
|
||||
function check_event(val)
|
||||
if ignored_events[val] then
|
||||
error("Ignored event \""..val.."\" in "..filter_type..": "..source)
|
||||
end
|
||||
end
|
||||
|
||||
function cb(node)
|
||||
if node.left.type == "FieldName" and (node.left.value == "evt.type" or node.left.value == "syscall.type") then
|
||||
function cb(node)
|
||||
if node.left.type == "FieldName" and
|
||||
(node.left.value == "evt.type" or
|
||||
node.left.value == "syscall.type") then
|
||||
|
||||
if (node.operator == "in" or node.operator == "intersects" or node.operator == "pmatch") then
|
||||
for i, v in ipairs(node.right.elements) do
|
||||
if v.type == "BareString" then
|
||||
if node.left.value == "evt.type" then
|
||||
check_event(v.value)
|
||||
else
|
||||
check_syscall(v.value)
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
if node.right.type == "BareString" then
|
||||
if node.left.value == "evt.type" then
|
||||
check_event(node.right.value)
|
||||
else
|
||||
check_syscall(node.right.value)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if (node.operator == "in" or
|
||||
node.operator == "intersects" or
|
||||
node.operator == "pmatch") then
|
||||
for i, v in ipairs(node.right.elements) do
|
||||
if v.type == "BareString" then
|
||||
if node.left.value == "evt.type" then
|
||||
check_event(v.value)
|
||||
else
|
||||
check_syscall(v.value)
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
if node.right.type == "BareString" then
|
||||
if node.left.value == "evt.type" then
|
||||
check_event(node.right.value)
|
||||
else
|
||||
check_syscall(node.right.value)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
parser.traverse_ast(ast, {
|
||||
BinaryRelOp = 1
|
||||
}, cb)
|
||||
parser.traverse_ast(ast, {BinaryRelOp=1}, cb)
|
||||
end
|
||||
|
||||
-- Examine the ast and find the event types/syscalls for which the
|
||||
@@ -72,129 +75,125 @@ end
|
||||
|
||||
function sinsp_rule_utils.get_evttypes_syscalls(name, ast, source, warn_evttypes, verbose)
|
||||
|
||||
local evttypes = {}
|
||||
local syscallnums = {}
|
||||
local evtnames = {}
|
||||
local found_event = false
|
||||
local found_not = false
|
||||
local found_event_after_not = false
|
||||
local evttypes = {}
|
||||
local syscallnums = {}
|
||||
local evtnames = {}
|
||||
local found_event = false
|
||||
local found_not = false
|
||||
local found_event_after_not = false
|
||||
|
||||
function cb(node)
|
||||
if node.type == "UnaryBoolOp" then
|
||||
if node.operator == "not" then
|
||||
found_not = true
|
||||
end
|
||||
else
|
||||
if node.operator == "!=" then
|
||||
found_not = true
|
||||
end
|
||||
if node.left.type == "FieldName" and node.left.value == "evt.type" then
|
||||
found_event = true
|
||||
if found_not then
|
||||
found_event_after_not = true
|
||||
end
|
||||
if (node.operator == "in" or node.operator == "intersects" or node.operator == "pmatch") then
|
||||
for i, v in ipairs(node.right.elements) do
|
||||
if v.type == "BareString" then
|
||||
function cb(node)
|
||||
if node.type == "UnaryBoolOp" then
|
||||
if node.operator == "not" then
|
||||
found_not = true
|
||||
end
|
||||
else
|
||||
if node.operator == "!=" then
|
||||
found_not = true
|
||||
end
|
||||
if node.left.type == "FieldName" and node.left.value == "evt.type" then
|
||||
found_event = true
|
||||
if found_not then
|
||||
found_event_after_not = true
|
||||
end
|
||||
if (node.operator == "in" or
|
||||
node.operator == "intersects" or
|
||||
node.operator == "pmatch") then
|
||||
for i, v in ipairs(node.right.elements) do
|
||||
if v.type == "BareString" then
|
||||
|
||||
-- The event must be a known event
|
||||
if events[v.value] == nil and syscalls[v.value] == nil then
|
||||
error("Unknown event/syscall \"" .. v.value .. "\" in filter: " .. source)
|
||||
end
|
||||
-- The event must be a known event
|
||||
if events[v.value] == nil and syscalls[v.value] == nil then
|
||||
error("Unknown event/syscall \""..v.value.."\" in filter: "..source)
|
||||
end
|
||||
|
||||
evtnames[v.value] = 1
|
||||
if events[v.value] ~= nil then
|
||||
for id in string.gmatch(events[v.value], "%S+") do
|
||||
evttypes[id] = 1
|
||||
end
|
||||
end
|
||||
evtnames[v.value] = 1
|
||||
if events[v.value] ~= nil then
|
||||
for id in string.gmatch(events[v.value], "%S+") do
|
||||
evttypes[id] = 1
|
||||
end
|
||||
end
|
||||
|
||||
if syscalls[v.value] ~= nil then
|
||||
for id in string.gmatch(syscalls[v.value], "%S+") do
|
||||
syscallnums[id] = 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
if node.right.type == "BareString" then
|
||||
if syscalls[v.value] ~= nil then
|
||||
for id in string.gmatch(syscalls[v.value], "%S+") do
|
||||
syscallnums[id] = 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
if node.right.type == "BareString" then
|
||||
|
||||
-- The event must be a known event
|
||||
if events[node.right.value] == nil and syscalls[node.right.value] == nil then
|
||||
error("Unknown event/syscall \"" .. node.right.value .. "\" in filter: " .. source)
|
||||
end
|
||||
-- The event must be a known event
|
||||
if events[node.right.value] == nil and syscalls[node.right.value] == nil then
|
||||
error("Unknown event/syscall \""..node.right.value.."\" in filter: "..source)
|
||||
end
|
||||
|
||||
evtnames[node.right.value] = 1
|
||||
if events[node.right.value] ~= nil then
|
||||
for id in string.gmatch(events[node.right.value], "%S+") do
|
||||
evttypes[id] = 1
|
||||
end
|
||||
end
|
||||
evtnames[node.right.value] = 1
|
||||
if events[node.right.value] ~= nil then
|
||||
for id in string.gmatch(events[node.right.value], "%S+") do
|
||||
evttypes[id] = 1
|
||||
end
|
||||
end
|
||||
|
||||
if syscalls[node.right.value] ~= nil then
|
||||
for id in string.gmatch(syscalls[node.right.value], "%S+") do
|
||||
syscallnums[id] = 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if syscalls[node.right.value] ~= nil then
|
||||
for id in string.gmatch(syscalls[node.right.value], "%S+") do
|
||||
syscallnums[id] = 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
parser.traverse_ast(ast.filter.value, {
|
||||
BinaryRelOp = 1,
|
||||
UnaryBoolOp = 1
|
||||
}, cb)
|
||||
parser.traverse_ast(ast.filter.value, {BinaryRelOp=1, UnaryBoolOp=1} , cb)
|
||||
|
||||
if not found_event then
|
||||
if warn_evttypes == true then
|
||||
io.stderr:write("Rule " .. name .. ": warning (no-evttype):\n")
|
||||
io.stderr:write(source .. "\n")
|
||||
io.stderr:write(
|
||||
" did not contain any evt.type restriction, meaning it will run for all event types.\n")
|
||||
io.stderr:write(
|
||||
" This has a significant performance penalty. Consider adding an evt.type restriction if possible.\n")
|
||||
end
|
||||
evttypes = {}
|
||||
syscallnums = {}
|
||||
evtnames = {}
|
||||
end
|
||||
if not found_event then
|
||||
if warn_evttypes == true then
|
||||
io.stderr:write("Rule "..name..": warning (no-evttype):\n")
|
||||
io.stderr:write(source.."\n")
|
||||
io.stderr:write(" did not contain any evt.type restriction, meaning it will run for all event types.\n")
|
||||
io.stderr:write(" This has a significant performance penalty. Consider adding an evt.type restriction if possible.\n")
|
||||
end
|
||||
evttypes = {}
|
||||
syscallnums = {}
|
||||
evtnames = {}
|
||||
end
|
||||
|
||||
if found_event_after_not then
|
||||
if warn_evttypes == true then
|
||||
io.stderr:write("Rule " .. name .. ": warning (trailing-evttype):\n")
|
||||
io.stderr:write(source .. "\n")
|
||||
io.stderr:write(" does not have all evt.type restrictions at the beginning of the condition,\n")
|
||||
io.stderr:write(" or uses a negative match (i.e. \"not\"/\"!=\") for some evt.type restriction.\n")
|
||||
io.stderr:write(
|
||||
" This has a performance penalty, as the rule can not be limited to specific event types.\n")
|
||||
io.stderr:write(" Consider moving all evt.type restrictions to the beginning of the rule and/or\n")
|
||||
io.stderr:write(" replacing negative matches with positive matches if possible.\n")
|
||||
end
|
||||
evttypes = {}
|
||||
syscallnums = {}
|
||||
evtnames = {}
|
||||
end
|
||||
if found_event_after_not then
|
||||
if warn_evttypes == true then
|
||||
io.stderr:write("Rule "..name..": warning (trailing-evttype):\n")
|
||||
io.stderr:write(source.."\n")
|
||||
io.stderr:write(" does not have all evt.type restrictions at the beginning of the condition,\n")
|
||||
io.stderr:write(" or uses a negative match (i.e. \"not\"/\"!=\") for some evt.type restriction.\n")
|
||||
io.stderr:write(" This has a performance penalty, as the rule can not be limited to specific event types.\n")
|
||||
io.stderr:write(" Consider moving all evt.type restrictions to the beginning of the rule and/or\n")
|
||||
io.stderr:write(" replacing negative matches with positive matches if possible.\n")
|
||||
end
|
||||
evttypes = {}
|
||||
syscallnums = {}
|
||||
evtnames = {}
|
||||
end
|
||||
|
||||
evtnames_only = {}
|
||||
local num_evtnames = 0
|
||||
for name, dummy in pairs(evtnames) do
|
||||
table.insert(evtnames_only, name)
|
||||
num_evtnames = num_evtnames + 1
|
||||
end
|
||||
evtnames_only = {}
|
||||
local num_evtnames = 0
|
||||
for name, dummy in pairs(evtnames) do
|
||||
table.insert(evtnames_only, name)
|
||||
num_evtnames = num_evtnames + 1
|
||||
end
|
||||
|
||||
if num_evtnames == 0 then
|
||||
table.insert(evtnames_only, "all")
|
||||
end
|
||||
if num_evtnames == 0 then
|
||||
table.insert(evtnames_only, "all")
|
||||
end
|
||||
|
||||
table.sort(evtnames_only)
|
||||
table.sort(evtnames_only)
|
||||
|
||||
if verbose then
|
||||
io.stderr:write("Event types/Syscalls for rule " .. name .. ": " .. table.concat(evtnames_only, ",") .. "\n")
|
||||
end
|
||||
if verbose then
|
||||
io.stderr:write("Event types/Syscalls for rule "..name..": "..table.concat(evtnames_only, ",").."\n")
|
||||
end
|
||||
|
||||
return evttypes, syscallnums
|
||||
return evttypes, syscallnums
|
||||
end
|
||||
|
||||
return sinsp_rule_utils
|
||||
|
||||
@@ -75,6 +75,7 @@ target_include_directories(
|
||||
"${STRING_VIEW_LITE_INCLUDE}"
|
||||
"${YAMLCPP_INCLUDE_DIR}"
|
||||
"${CIVETWEB_INCLUDE_DIR}"
|
||||
"${OPENSSL_INCLUDE_DIR}"
|
||||
"${GRPC_INCLUDE}"
|
||||
"${GRPCPP_INCLUDE}"
|
||||
"${PROTOBUF_INCLUDE}"
|
||||
@@ -89,6 +90,8 @@ target_link_libraries(
|
||||
"${GRPC_LIB}"
|
||||
"${GRPCPP_LIB}"
|
||||
"${PROTOBUF_LIB}"
|
||||
"${OPENSSL_LIBRARY_SSL}"
|
||||
"${OPENSSL_LIBRARY_CRYPTO}"
|
||||
"${LIBYAML_LIB}"
|
||||
"${YAMLCPP_LIB}"
|
||||
"${CIVETWEB_LIB}")
|
||||
|
||||
Reference in New Issue
Block a user