Compare commits

..

43 Commits

Author SHA1 Message Date
Leonardo Di Donato
670736d87e Merge remote-tracking branch 'origin/dev' 2019-07-16 16:20:08 +00:00
Mark Stemm
a084f8c4ed CHANGELOG/README changes for 0.16.0
Bumping version, noting changes since last release.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2019-07-12 12:18:42 -07:00
Mark Stemm
01f65e3bae Add new tests for validating rules files
Add a bunch of additional test cases for validating rules files. Each
has a specific kind of parse failure and checks for the appropriate
error info on stdout.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2019-07-11 11:24:22 -07:00
Mark Stemm
1711ed0a2e Pass back explicit errors in load_rules()
Instead of relying on lua errors to pass back parse errors, pass back an
explicit true + required engine version or false + error message.

Also clean up the error message to display info + context on the
error. When the error related to yaml parsing, use the row number passed
back in lyaml's error string to print the specific line with the error.

When parsing rules/macros/lists, print the object being parsed alongside
the error.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2019-07-11 11:24:22 -07:00
Mark Stemm
839d76a760 Send validate output to stdout
When parsing rules files with -V (validate), print info on the result of
loading the rules file to stdout. That way a caller can capture stdout
to pass along any rules parsing error.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2019-07-11 11:24:22 -07:00
Mark Stemm
dc7bff127f New flags to compare stdout/stderr, validate rules
New test options stdout_is/stderr_is do a direct comparison between
stdout/stderr and the provided value.

Test option validate_rules_file maps to -V arguments, which validate
rules and exits.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2019-07-11 11:24:22 -07:00
Leonardo Di Donato
e80ff6296a new: luacheck basic config
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2019-07-10 18:49:02 +02:00
Leonardo Di Donato
231f881c5a update: ignore luacheck cache
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2019-07-10 18:49:02 +02:00
Leonardo Di Donato
cb5a3a14e6 new: k8s.gcr.io/kube-proxy addition to falco trusted images
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2019-07-10 16:43:41 +02:00
Leonardo Di Donato
4c68da0dcc new: YAML lint configuration
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2019-07-10 13:00:03 +02:00
Mattia Pagnozzi
a32870ae1d Add runc to the list of possible container entrypoint parents
Docker versions >= 18.09 removed the "docker-" prefix, so include runc
in the list.

Signed-off-by: Mattia Pagnozzi <mattia.pagnozzi@gmail.com>
2019-07-09 14:31:49 +02:00
Leonardo Di Donato
fdbd520cce fix: bump falco engine version
Co-Authored-By: Lorenzo Fontana <lo@linux.com>
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2019-07-09 11:45:38 +02:00
Leonardo Di Donato
f20a5a04bf new: cmake format file
Co-Authored-by: Lorenzo Fontana <lo@linux.com>
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2019-07-08 19:05:06 +02:00
Lorenzo Fontana
affb1086a3 update: fields checksum while adding ka.useragent
Signed-off-by: Lorenzo Fontana <lo@linux.com>

Co-authored-by: Leonardo Di Donato <leodidonato@gmail.com>
2019-07-08 17:40:41 +02:00
Lorenzo Fontana
8155d467ab update: ka.useragent in k8s audit fields
Signed-off-by: Lorenzo Fontana <lo@linux.com>

Co-authored-by: Leonardo Di Donato <leodidonato@gmail.com>
2019-07-08 17:40:41 +02:00
Lorenzo Fontana
bf19d8c881 chore: format json_evt in preparation to add fields
Signed-off-by: Lorenzo Fontana <lo@linux.com>

Co-authored-by: Leonardo Di Donato <leodidonato@gmail.com>
2019-07-08 17:40:41 +02:00
Mark Stemm
75b816d806 Merge remote-tracking branch 'origin/dev' 2019-06-12 13:37:56 -07:00
Mark Stemm
194a017d8f Merge remote-tracking branch 'origin/dev' 2019-06-12 09:14:36 -07:00
Mark Stemm
ff376d312b Merge remote-tracking branch 'origin/dev' 2019-06-07 15:15:48 -07:00
Mark Stemm
807c00b827 Merge remote-tracking branch 'origin/dev' 2019-06-07 15:09:50 -07:00
Mark Stemm
db419459aa Merge remote-tracking branch 'origin/dev' 2019-05-13 13:45:34 -07:00
Mark Stemm
36a095ccb3 Merge remote-tracking branch 'origin/dev' 2019-05-13 13:43:10 -07:00
Xiang Dai
f4b0b3c096 falco.yaml: change default program_output action (#507)
falco-CLA-1.0-signed-off-by: Xiang Dai <764524258@qq.com>1
2019-02-20 09:18:45 -08:00
Xiang Dai
e546555de8 fix k8s install issue (#506)
falco-CLA-1.0-signed-off-by: Xiang Dai <764524258@qq.com>
2019-02-20 09:17:34 -08:00
Xiang Dai
1fb53eefdb Update output (#511)
falco-CLA-1.0-signed-off-by: Xiang Dai <764524258@qq.com>

Signed-off-by: Xiang Dai <764524258@qq.com>
2019-02-11 13:01:49 -08:00
Mark Stemm
44e88f28a4 Merge remote-tracking branch 'origin/dev' 2019-02-10 14:57:00 -08:00
Mark Stemm
62c1a0440d Merge remote-tracking branch 'origin/dev' 2019-02-06 16:38:53 -08:00
Mark Stemm
ddf55d3c8e Merge remote-tracking branch 'origin/dev' 2019-01-17 07:28:18 -08:00
Mark Stemm
bd7a9733fd Merge branch 'dev' 2018-11-09 13:41:29 -08:00
Mark Stemm
ff299c1d43 Merge remote-tracking branch 'origin/dev' 2018-09-11 13:33:56 -07:00
Mark Stemm
5e38f130cc Merge remote-tracking branch 'origin/dev' 2018-09-11 11:02:10 -07:00
Mark Stemm
470710366b Merge remote-tracking branch 'origin/dev' 2018-07-31 12:06:09 -07:00
Mark Stemm
6acb13e6bb Merge branch 'dev' 2018-07-24 17:33:24 -07:00
David Archer
b496116fe3 Don't make driver compilation fail when kernel is compiled with CONFIG_ORC_UNWINDER or CONFIG_STACK_VALIDATION. (#362)
sysdig-CLA-1.0-signed-off-by: David Archer <darcher@gmail.com>
2018-04-30 14:30:39 -07:00
Mark Stemm
2a0911dcfd Merge branch 'dev' 2018-04-24 16:21:18 -07:00
Mark Stemm
94df00e512 Merge branch 'dev' 2018-01-18 09:07:00 -08:00
Mark Stemm
3ee76637f4 Merge branch 'dev' 2018-01-17 20:30:28 -08:00
Mark Stemm
e8aee19f6c Merge remote-tracking branch 'origin/dev', 0.8.1 2017-10-10 10:49:27 -07:00
Mark Stemm
74556e5f6e Merge branch 'dev' 2017-10-09 17:17:12 -07:00
Mark Stemm
809d20c294 Merge pull request #246 from draios/dev
Merging for 0.7.0
2017-05-30 13:30:39 -07:00
Mark Stemm
b0ae29c23a Merge branch 'dev' 2017-05-15 11:12:11 -07:00
Mark Stemm
d1b6b2be87 Merge pull request #229 from draios/dev
Merging for 0.6.0
2017-03-29 16:00:06 -07:00
Mark Stemm
e00181d553 Merge pull request #174 from draios/dev
Merging for 0.5.0
2016-12-22 13:25:32 -08:00
15 changed files with 348 additions and 132 deletions

119
.cmake-format Normal file
View File

@@ -0,0 +1,119 @@
# --------------------------
# General Formatting Options
# --------------------------
# How wide to allow formatted cmake files
line_width = 80
# How many spaces to tab for indent
tab_size = 2
# If arglists are longer than this, break them always
max_subargs_per_line = 3
# If true, separate flow control names from their parentheses with a space
separate_ctrl_name_with_space = False
# If true, separate function names from parentheses with a space
separate_fn_name_with_space = False
# If a statement is wrapped to more than one line, than dangle the closing
# parenthesis on it's own line
dangle_parens = False
# If the statement spelling length (including space and parenthesis is larger
# than the tab width by more than this amoung, then force reject un-nested
# layouts.
max_prefix_chars = 2
# If a candidate layout is wrapped horizontally but it exceeds this many lines,
# then reject the layout.
max_lines_hwrap = 2
# What style line endings to use in the output.
line_ending = 'unix'
# Format command names consistently as 'lower' or 'upper' case
command_case = 'canonical'
# Format keywords consistently as 'lower' or 'upper' case
keyword_case = 'unchanged'
# Specify structure for custom cmake functions
additional_commands = {
"pkg_find": {
"kwargs": {
"PKG": "*"
}
}
}
# A list of command names which should always be wrapped
always_wrap = []
# Specify the order of wrapping algorithms during successive reflow attempts
algorithm_order = [0, 1, 2, 3, 4]
# If true, the argument lists which are known to be sortable will be sorted
# lexicographicall
enable_sort = True
# If true, the parsers may infer whether or not an argument list is sortable
# (without annotation).
autosort = False
# If a comment line starts with at least this many consecutive hash characters,
# then don't lstrip() them off. This allows for lazy hash rulers where the first
# hash char is not separated by space
hashruler_min_length = 10
# A dictionary containing any per-command configuration overrides. Currently
# only `command_case` is supported.
per_command = {}
# --------------------------
# Comment Formatting Options
# --------------------------
# What character to use for bulleted lists
bullet_char = '*'
# What character to use as punctuation after numerals in an enumerated list
enum_char = '.'
# enable comment markup parsing and reflow
enable_markup = True
# If comment markup is enabled, don't reflow the first comment block in each
# listfile. Use this to preserve formatting of your copyright/license
# statements.
first_comment_is_literal = False
# If comment markup is enabled, don't reflow any comment block which matches
# this (regex) pattern. Default is `None` (disabled).
literal_comment_pattern = None
# Regular expression to match preformat fences in comments
# default=r'^\s*([`~]{3}[`~]*)(.*)$'
fence_pattern = '^\\s*([`~]{3}[`~]*)(.*)$'
# Regular expression to match rulers in comments
# default=r'^\s*[^\w\s]{3}.*[^\w\s]{3}$'
ruler_pattern = '^\\s*[^\\w\\s]{3}.*[^\\w\\s]{3}$'
# If true, then insert a space between the first hash char and remaining hash
# chars in a hash ruler, and normalize it's length to fill the column
canonicalize_hashrulers = True
# ---------------------------------
# Miscellaneous Options
# ---------------------------------
# If true, emit the unicode byte-order mark (BOM) at the start of the file
emit_byteorder_mark = False
# Specify the encoding of the input file. Defaults to utf-8.
input_encoding = 'utf-8'
# Specify the encoding of the output file. Defaults to utf-8. Note that cmake
# only claims to support utf-8 so be careful when using anything else
output_encoding = 'utf-8'

5
.gitignore vendored
View File

@@ -20,4 +20,7 @@ docker/event-generator/mysqld
docker/event-generator/httpd
docker/event-generator/sha1sum
docker/event-generator/vipw
.vscode/*
.vscode/*
.luacheckcache

9
.luacheckrc Normal file
View File

@@ -0,0 +1,9 @@
std = "min"
cache = true
include_files = {
"userspace/falco/lua/*.lua",
"userspace/engine/lua/*.lua",
"userspace/engine/lua/lyaml/*.lua",
"*.luacheckrc"
}
exclude_files = {"build"}

8
.yamllint.conf Normal file
View File

@@ -0,0 +1,8 @@
extends: default
rules:
indentation: disable
document-start: disable
comments: disable
line-length: disable
new-line-at-end-of-file: disable

View File

@@ -2,6 +2,74 @@
This file documents all notable changes to Falco. The release numbering uses [semantic versioning](http://semver.org).
## v0.16.0
Released 2019-07-12
## Major Changes
* Clean up error reporting to provide more meaningful error messages along with context when loading rules files. When run with -V, the results of the validation ("OK" or error message) are sent to standard output. [[#708](https://github.com/falcosecurity/falco/pull/708)]
* Improve rule loading performance by optimizing lua parsing paths to avoid expensive pattern matches. [[#694](https://github.com/falcosecurity/falco/pull/694)]
* Bump falco engine version to 4 to reflect new fields `ka.useragent`, others. [[#710](https://github.com/falcosecurity/falco/pull/710)] [[#681](https://github.com/falcosecurity/falco/pull/681)]
* Add Catch2 as a unit testing framework. This will add additional coverage on top of the regression tests using Avocado. [[#687](https://github.com/falcosecurity/falco/pull/687)]
## Minor Changes
* Add SYSDIG_DIR Cmake option to specify location for sysdig source code when building falco. [[#677](https://github.com/falcosecurity/falco/pull/677)] [[#679](https://github.com/falcosecurity/falco/pull/679)] [[#702](https://github.com/falcosecurity/falco/pull/702)]
* New field `ka.useragent` reports the useragent from k8s audit events. [[#709](https://github.com/falcosecurity/falco/pull/709)]
* Add clang formatter for C++ syntax formatting. [[#701](https://github.com/falcosecurity/falco/pull/701)] [[#689](https://github.com/falcosecurity/falco/pull/689)]
* Partial changes towards lua syntax formatting. No particular formatting enforced yet, though. [[#718](https://github.com/falcosecurity/falco/pull/718)]
* Partial changes towards yaml syntax formatting. No particular formatting enforced yet, though. [[#714](https://github.com/falcosecurity/falco/pull/714)]
* Add cmake syntax formatting. [[#703](https://github.com/falcosecurity/falco/pull/703)]
* Token bucket unit tests and redesign. [[#692](https://github.com/falcosecurity/falco/pull/692)]
* Update github PR template. [[#699](https://github.com/falcosecurity/falco/pull/699)]
* Fix PR template for kind/rule-*. [[#697](https://github.com/falcosecurity/falco/pull/697)]
## Bug Fixes
* Remove an unused cmake file. [[#700](https://github.com/falcosecurity/falco/pull/700)]
* Misc Cmake cleanups. [[#673](https://github.com/falcosecurity/falco/pull/673)]
* Misc k8s install docs improvements. [[#671](https://github.com/falcosecurity/falco/pull/671)]
## Rule Changes
* Allow k8s.gcr.io/kube-proxy image to run privileged. [[#717](https://github.com/falcosecurity/falco/pull/717)]
* Add runc to the list of possible container entrypoint parents. [[#712](https://github.com/falcosecurity/falco/pull/712)]
* Skip Source RFC 1918 addresses when considering outbound connections. [[#685](https://github.com/falcosecurity/falco/pull/685)]
* Add additional `user_XXX` placeholder macros to allow for easy customization of rule exceptions. [[#685](https://github.com/falcosecurity/falco/pull/685)]
* Let weaveworks programs change namespaces. [[#685](https://github.com/falcosecurity/falco/pull/685)]
* Add additional openshift images. [[#685](https://github.com/falcosecurity/falco/pull/685)]
* Add openshift as a k8s binary. [[#678](https://github.com/falcosecurity/falco/pull/678)]
* Add dzdo as a binary that can change users. [[#678](https://github.com/falcosecurity/falco/pull/678)]
* Allow azure/calico binaries to change namespaces. [[#678](https://github.com/falcosecurity/falco/pull/678)]
* Add back trusted_containers list for backport compatibility [[#675](https://github.com/falcosecurity/falco/pull/675)]
* Add mkdirat as a syscall for mkdir operations. [[#667](https://github.com/falcosecurity/falco/pull/667)]
* Add container id/repository to rules that can work with containers. [[#667](https://github.com/falcosecurity/falco/pull/667)]
## v0.15.3
Released 2019-06-12

View File

@@ -5,7 +5,7 @@
#### Latest release
**v0.15.3**
**v0.16.0**
Read the [change log](https://github.com/falcosecurity/falco/blob/dev/CHANGELOG.md)
Dev Branch: [![Build Status](https://travis-ci.com/falcosecurity/falco.svg?branch=dev)](https://travis-ci.com/falcosecurity/falco)<br />

View File

@@ -166,4 +166,5 @@ program_output:
http_output:
enabled: false
url: http://some.url
url: http://some.url

View File

@@ -59,7 +59,8 @@ Now that we have the requirements for our Daemon Set in place, we can create our
```
k8s-using-daemonset$ kubectl create -f k8s-with-rbac/falco-daemonset-configmap.yaml
daemonset "falco" created
daemonset.extensions "falco-daemonset" created
k8s-using-daemonset$
```
@@ -97,14 +98,13 @@ In order to test that Falco is working correctly, you can launch a shell in a Po
```
k8s-using-daemonset$ kubectl get pods
NAME READY STATUS RESTARTS AGE
falco-74htl 1/1 Running 0 13h
falco-fqz2m 1/1 Running 0 13h
falco-sgjfx 1/1 Running 0 13h
k8s-using-daemonset$ kubectl exec -it falco-74htl bash
root@falco-74htl:/# exit
k8s-using-daemonset$ kubectl logs falco-74htl
{"output":"17:48:58.590038385: Notice A shell was spawned in a container with an attached terminal (user=root k8s.pod=falco-74htl container=a98c2aa8e670 shell=bash parent=<NA> cmdline=bash terminal=34816)","priority":"Notice","rule":"Terminal shell in container","time":"2017-12-20T17:48:58.590038385Z", "output_fields": {"container.id":"a98c2aa8e670","evt.time":1513792138590038385,"k8s.pod.name":"falco-74htl","proc.cmdline":"bash ","proc.name":"bash","proc.pname":null,"proc.tty":34816,"user.name":"root"}}
NAME READY STATUS RESTARTS AGE
falco-daemonset-b695d 1/1 Running 0 2d
falco-daemonset-n8q2v 1/1 Running 0 2d
k8s-using-daemonset$ kubectl exec -it falco-daemonset-b695d bash
root@falco-daemonset-b695d:/# exit
k8s-using-daemonset$ kubectl logs falco-daemonset-b695d
07:16:09.217866519: Error File below known binary directory renamed/removed (user=root command=event_generator pcmdline=<NA> operation=rename file=<NA> res=0 oldpath=/bin/true newpath=/bin/true.event-generator-sh ) k8s.ns=default k8s.pod=falco-event-generator-deployment-645444689b-j6mth container=0e67aad65846 k8s.ns=default k8s.pod=falco-event-generator-deployment-645444689b-j6mth container=0e67aad65846
k8s-using-daemonset$
```

View File

@@ -1740,7 +1740,7 @@
docker.io/sysdig/agent, docker.io/sysdig/falco, docker.io/sysdig/sysdig,
gcr.io/google_containers/kube-proxy, docker.io/calico/node,
docker.io/rook/toolbox, docker.io/cloudnativelabs/kube-router, docker.io/mesosphere/mesos-slave,
docker.io/docker/ucp-agent, sematext_images
docker.io/docker/ucp-agent, sematext_images, k8s.gcr.io/kube-proxy
]
- macro: falco_privileged_containers
@@ -1832,7 +1832,7 @@
# when we lose events and lose track of state.
- macro: container_entrypoint
condition: (not proc.pname exists or proc.pname in (runc:[0:PARENT], runc:[1:CHILD], docker-runc, exe))
condition: (not proc.pname exists or proc.pname in (runc:[0:PARENT], runc:[1:CHILD], runc, docker-runc, exe))
- rule: Launch Sensitive Mount Container
desc: >
@@ -2253,7 +2253,7 @@
condition: >
spawned_process and container and
((proc.name = "nc" and (proc.args contains "-e" or proc.args contains "-c")) or
(proc.name = "ncat" and (proc.args contains "--sh-exec" or proc.args contains "--exec" or proc.args contains "-e "
(proc.name = "ncat" and (proc.args contains "--sh-exec" or proc.args contains "--exec" or proc.args contains "-e "
or proc.args contains "-c " or proc.args contains "--lua-exec"))
)
output: >

View File

@@ -0,0 +1,5 @@
- rule: condition not rule
condition:
desc: some desc
output: some output
priority: INFO

View File

@@ -0,0 +1,2 @@
- macro: macro with comp error
condition: gak

View File

@@ -19,9 +19,9 @@ limitations under the License.
// The version of rules/filter fields/etc supported by this falco
// engine.
#define FALCO_ENGINE_VERSION (3)
#define FALCO_ENGINE_VERSION (4)
// This is the result of running "falco --list -N | sha256sum" and
// represents the fields supported by this version of falco. It's used
// at build time to detect a changed set of fields.
#define FALCO_FIELDS_CHECKSUM "9b5557ec8f16f5606a1544573b152d211d5212f653ee039146836a17266ff449"
#define FALCO_FIELDS_CHECKSUM "ceb069d9f9b2d4ebcc5de39bddc53b7af2e6b8f072edc293668fd6ac4e532413"

View File

@@ -19,8 +19,8 @@ limitations under the License.
#include <ctype.h>
#include "utils.h"
#include "uri.h"
#include "utils.h"
#include "falco_common.h"
#include "json_evt.h"
@@ -30,7 +30,6 @@ using namespace std;
json_event::json_event()
{
}
json_event::~json_event()
@@ -60,7 +59,7 @@ std::string json_event_filter_check::def_format(const json &j, std::string &fiel
std::string json_event_filter_check::json_as_string(const json &j)
{
if (j.type() == json::value_t::string)
if(j.type() == json::value_t::string)
{
return j;
}
@@ -70,32 +69,35 @@ std::string json_event_filter_check::json_as_string(const json &j)
}
}
json_event_filter_check::field_info::field_info()
: m_idx_mode(IDX_NONE), m_idx_type(IDX_NUMERIC)
json_event_filter_check::field_info::field_info():
m_idx_mode(IDX_NONE), m_idx_type(IDX_NUMERIC)
{
}
json_event_filter_check::field_info::field_info(std::string name,
std::string desc)
: m_name(name), m_desc(desc),
m_idx_mode(IDX_NONE), m_idx_type(IDX_NUMERIC)
std::string desc):
m_name(name),
m_desc(desc),
m_idx_mode(IDX_NONE), m_idx_type(IDX_NUMERIC)
{
}
json_event_filter_check::field_info::field_info(std::string name,
std::string desc,
index_mode mode)
: m_name(name), m_desc(desc),
m_idx_mode(mode), m_idx_type(IDX_NUMERIC)
index_mode mode):
m_name(name),
m_desc(desc),
m_idx_mode(mode), m_idx_type(IDX_NUMERIC)
{
}
json_event_filter_check::field_info::field_info(std::string name,
std::string desc,
index_mode mode,
index_type itype)
: m_name(name), m_desc(desc),
m_idx_mode(mode), m_idx_type(itype)
index_type itype):
m_name(name),
m_desc(desc),
m_idx_mode(mode), m_idx_type(itype)
{
}
@@ -107,14 +109,15 @@ json_event_filter_check::alias::alias()
{
}
json_event_filter_check::alias::alias(nlohmann::json::json_pointer ptr)
: m_jptr(ptr), m_format(def_format)
json_event_filter_check::alias::alias(nlohmann::json::json_pointer ptr):
m_jptr(ptr), m_format(def_format)
{
}
json_event_filter_check::alias::alias(nlohmann::json::json_pointer ptr,
format_t format)
: m_jptr(ptr), m_format(format)
format_t format):
m_jptr(ptr),
m_format(format)
{
}
@@ -122,8 +125,8 @@ json_event_filter_check::alias::~alias()
{
}
json_event_filter_check::json_event_filter_check()
: m_format(def_format)
json_event_filter_check::json_event_filter_check():
m_format(def_format)
{
}
@@ -150,7 +153,7 @@ int32_t json_event_filter_check::parse_field_name(const char *str, bool alloc_st
// What follows the match must not be alphanumeric or a dot
if(strncmp(info.m_name.c_str(), str, info.m_name.size()) == 0 &&
!isalnum((int) str[info.m_name.size()]) &&
!isalnum((int)str[info.m_name.size()]) &&
str[info.m_name.size()] != '.' &&
info.m_name.size() > match_len)
{
@@ -169,7 +172,7 @@ int32_t json_event_filter_check::parse_field_name(const char *str, bool alloc_st
if(end != NULL)
{
m_idx = string(start, end-start);
m_idx = string(start, end - start);
}
idx_len = (end - start + 2);
@@ -197,14 +200,14 @@ int32_t json_event_filter_check::parse_field_name(const char *str, bool alloc_st
return match_len + idx_len;
}
void json_event_filter_check::add_filter_value(const char* str, uint32_t len, uint32_t i)
void json_event_filter_check::add_filter_value(const char *str, uint32_t len, uint32_t i)
{
m_values.push_back(string(str));
}
bool json_event_filter_check::compare(gen_event *evt)
{
json_event *jevt = (json_event *) evt;
json_event *jevt = (json_event *)evt;
std::string value = extract(jevt);
@@ -225,7 +228,7 @@ bool json_event_filter_check::compare(gen_event *evt)
case CO_IN:
for(auto &val : m_values)
{
if (value == val)
if(value == val)
{
return true;
}
@@ -268,11 +271,12 @@ json_event_filter_check::check_info &json_event_filter_check::get_fields()
return m_info;
}
uint8_t* json_event_filter_check::extract(gen_event *evt, uint32_t* len, bool sanitize_strings)
uint8_t *json_event_filter_check::extract(gen_event *evt, uint32_t *len, bool sanitize_strings)
{
json_event *jevt = (json_event *) evt;
json_event *jevt = (json_event *)evt;
try {
try
{
const json &j = jevt->jevt().at(m_jptr);
// Only format when the value was actually found in
@@ -286,7 +290,7 @@ uint8_t* json_event_filter_check::extract(gen_event *evt, uint32_t* len, bool sa
*len = m_tstr.size();
return (uint8_t *) m_tstr.c_str();
return (uint8_t *)m_tstr.c_str();
}
std::string json_event_filter_check::extract(json_event *evt)
@@ -299,7 +303,7 @@ std::string json_event_filter_check::extract(json_event *evt)
if(res != NULL)
{
ret.assign((const char *) res, len);
ret.assign((const char *)res, len);
}
return ret;
@@ -315,18 +319,15 @@ jevt_filter_check::jevt_filter_check()
{
m_info = {"jevt",
"generic ways to access json events",
{
{s_jevt_time_field, "json event timestamp as a string that includes the nanosecond part"},
{s_jevt_time_iso_8601_field, "json event timestamp in ISO 8601 format, including nanoseconds and time zone offset (in UTC)"},
{s_jevt_rawtime_field, "absolute event timestamp, i.e. nanoseconds from epoch."},
{s_jevt_value_field, "General way to access single property from json object. The syntax is [<json pointer expression>]. The property is returned as a string", IDX_REQUIRED, IDX_KEY},
{s_jevt_obj_field, "The entire json object, stringified"}
}};
{{s_jevt_time_field, "json event timestamp as a string that includes the nanosecond part"},
{s_jevt_time_iso_8601_field, "json event timestamp in ISO 8601 format, including nanoseconds and time zone offset (in UTC)"},
{s_jevt_rawtime_field, "absolute event timestamp, i.e. nanoseconds from epoch."},
{s_jevt_value_field, "General way to access single property from json object. The syntax is [<json pointer expression>]. The property is returned as a string", IDX_REQUIRED, IDX_KEY},
{s_jevt_obj_field, "The entire json object, stringified"}}};
}
jevt_filter_check::~jevt_filter_check()
{
}
int32_t jevt_filter_check::parse_field_name(const char *str, bool alloc_state, bool needed_for_filtering)
@@ -360,55 +361,56 @@ int32_t jevt_filter_check::parse_field_name(const char *str, bool alloc_state, b
const char *end;
// What follows must be [<json pointer expression>]
if (*(str + s_jevt_value_field.size()) != '[' ||
((end = strchr(str + 1, ']')) == NULL))
if(*(str + s_jevt_value_field.size()) != '[' ||
((end = strchr(str + 1, ']')) == NULL))
{
throw falco_exception(string("Could not parse filtercheck field \"") + str + "\". Did not have expected format with 'jevt.value[<json pointer>]'");
}
try {
m_jptr = json::json_pointer(string(str + (s_jevt_value_field.size()+1), (end-str-(s_jevt_value_field.size()+1))));
try
{
m_jptr = json::json_pointer(string(str + (s_jevt_value_field.size() + 1), (end - str - (s_jevt_value_field.size() + 1))));
}
catch (json::parse_error& e)
catch(json::parse_error &e)
{
throw falco_exception(string("Could not parse filtercheck field \"") + str + "\". Invalid json selector (" + e.what() + ")");
}
// The +1 accounts for the closing ']'
m_field = string(str, end-str + 1);
m_field = string(str, end - str + 1);
return (end - str + 1);
}
return 0;
}
uint8_t* jevt_filter_check::extract(gen_event *evt, uint32_t* len, bool sanitize_stings)
uint8_t *jevt_filter_check::extract(gen_event *evt, uint32_t *len, bool sanitize_stings)
{
if(m_field == s_jevt_rawtime_field)
{
m_tstr = to_string(evt->get_ts());
*len = m_tstr.size();
return (uint8_t *) m_tstr.c_str();
return (uint8_t *)m_tstr.c_str();
}
else if(m_field == s_jevt_time_field)
{
sinsp_utils::ts_to_string(evt->get_ts(), &m_tstr, false, true);
*len = m_tstr.size();
return (uint8_t *) m_tstr.c_str();
return (uint8_t *)m_tstr.c_str();
}
else if(m_field == s_jevt_time_iso_8601_field)
{
sinsp_utils::ts_to_iso_8601(evt->get_ts(), &m_tstr);
*len = m_tstr.size();
return (uint8_t *) m_tstr.c_str();
return (uint8_t *)m_tstr.c_str();
}
else if(m_field == s_jevt_obj_field)
{
json_event *jevt = (json_event *) evt;
json_event *jevt = (json_event *)evt;
m_tstr = jevt->jevt().dump();
*len = m_tstr.size();
return (uint8_t *) m_tstr.c_str();
return (uint8_t *)m_tstr.c_str();
}
return json_event_filter_check::extract(evt, len, sanitize_stings);
@@ -418,7 +420,7 @@ json_event_filter_check *jevt_filter_check::allocate_new()
{
jevt_filter_check *chk = new jevt_filter_check();
return (json_event_filter_check *) chk;
return (json_event_filter_check *)chk;
}
std::string k8s_audit_filter_check::index_image(const json &j, std::string &field, std::string &idx)
@@ -427,8 +429,9 @@ std::string k8s_audit_filter_check::index_image(const json &j, std::string &fiel
string image;
try {
image = j[idx_num].at("image");
try
{
image = j[idx_num].at("image");
}
catch(json::out_of_range &e)
{
@@ -470,7 +473,6 @@ std::string k8s_audit_filter_check::index_has_name(const json &j, std::string &f
return string("false");
}
std::string k8s_audit_filter_check::index_query_param(const json &j, std::string &field, std::string &idx)
{
string uri = j;
@@ -489,7 +491,7 @@ std::string k8s_audit_filter_check::index_query_param(const json &j, std::string
{
std::vector<std::string> param_parts = sinsp_split(part, '=');
if(param_parts.size() == 2 && uri::decode(param_parts[0], true)==idx)
if(param_parts.size() == 2 && uri::decode(param_parts[0], true) == idx)
{
return uri::decode(param_parts[1]);
}
@@ -498,7 +500,6 @@ std::string k8s_audit_filter_check::index_query_param(const json &j, std::string
return string("<NA>");
}
std::string k8s_audit_filter_check::index_generic(const json &j, std::string &field, std::string &idx)
{
json item;
@@ -511,7 +512,8 @@ std::string k8s_audit_filter_check::index_generic(const json &j, std::string &fi
{
uint64_t idx_num = (idx.empty() ? 0 : stoi(idx));
try {
try
{
item = j[idx_num];
}
catch(json::out_of_range &e)
@@ -529,7 +531,7 @@ std::string k8s_audit_filter_check::index_select(const json &j, std::string &fie
// Use the suffix of the field to determine which property to
// select from each object.
std::string prop = field.substr(field.find_last_of(".")+1);
std::string prop = field.substr(field.find_last_of(".") + 1);
std::string ret;
@@ -542,7 +544,8 @@ std::string k8s_audit_filter_check::index_select(const json &j, std::string &fie
ret += " ";
}
try {
try
{
ret += json_event_filter_check::json_as_string(obj.at(prop));
}
catch(json::out_of_range &e)
@@ -553,7 +556,8 @@ std::string k8s_audit_filter_check::index_select(const json &j, std::string &fie
}
else
{
try {
try
{
ret = j[stoi(idx)].at(prop);
}
catch(json::out_of_range &e)
@@ -573,7 +577,8 @@ std::string k8s_audit_filter_check::index_privileged(const json &j, std::string
if(!idx.empty())
{
try {
try
{
privileged = j[stoi(idx)].at(jpriv);
}
catch(json::out_of_range &e)
@@ -584,7 +589,8 @@ std::string k8s_audit_filter_check::index_privileged(const json &j, std::string
{
for(auto &container : j)
{
try {
try
{
if(container.at(jpriv))
{
privileged = true;
@@ -621,42 +627,41 @@ k8s_audit_filter_check::k8s_audit_filter_check()
{
m_info = {"ka",
"Access K8s Audit Log Events",
{
{"ka.auditid", "The unique id of the audit event"},
{"ka.stage", "Stage of the request (e.g. RequestReceived, ResponseComplete, etc.)"},
{"ka.auth.decision", "The authorization decision"},
{"ka.auth.reason", "The authorization reason"},
{"ka.user.name", "The user name performing the request"},
{"ka.user.groups", "The groups to which the user belongs"},
{"ka.impuser.name", "The impersonated user name"},
{"ka.verb", "The action being performed"},
{"ka.uri", "The request URI as sent from client to server"},
{"ka.uri.param", "The value of a given query parameter in the uri (e.g. when uri=/foo?key=val, ka.uri.param[key] is val).", IDX_REQUIRED, IDX_KEY},
{"ka.target.name", "The target object name"},
{"ka.target.namespace", "The target object namespace"},
{"ka.target.resource", "The target object resource"},
{"ka.target.subresource", "The target object subresource"},
{"ka.req.binding.subjects", "When the request object refers to a cluster role binding, the subject (e.g. account/users) being linked by the binding"},
{"ka.req.binding.subject.has_name", "When the request object refers to a cluster role binding, return true if a subject with the provided name exists", IDX_REQUIRED, IDX_KEY},
{"ka.req.binding.role", "When the request object refers to a cluster role binding, the role being linked by the binding"},
{"ka.req.configmap.name", "If the request object refers to a configmap, the configmap name"},
{"ka.req.configmap.obj", "If the request object refers to a configmap, the entire configmap object"},
{"ka.req.container.image", "When the request object refers to a container, the container's images. Can be indexed (e.g. ka.req.container.image[0]). Without any index, returns the first image", IDX_ALLOWED, IDX_NUMERIC},
{"ka.req.container.image.repository", "The same as req.container.image, but only the repository part (e.g. sysdig/falco)", IDX_ALLOWED, IDX_NUMERIC},
{"ka.req.container.host_network", "When the request object refers to a container, the value of the hostNetwork flag."},
{"ka.req.container.privileged", "When the request object refers to a container, whether or not any container is run privileged. With an index, return whether or not the ith container is run privileged.", IDX_ALLOWED, IDX_NUMERIC},
{"ka.req.role.rules", "When the request object refers to a role/cluster role, the rules associated with the role"},
{"ka.req.role.rules.apiGroups", "When the request object refers to a role/cluster role, the api groups associated with the role's rules. With an index, return only the api groups from the ith rule. Without an index, return all api groups concatenated", IDX_ALLOWED, IDX_NUMERIC},
{"ka.req.role.rules.nonResourceURLs", "When the request object refers to a role/cluster role, the non resource urls associated with the role's rules. With an index, return only the non resource urls from the ith rule. Without an index, return all non resource urls concatenated", IDX_ALLOWED, IDX_NUMERIC},
{"ka.req.role.rules.verbs", "When the request object refers to a role/cluster role, the verbs associated with the role's rules. With an index, return only the verbs from the ith rule. Without an index, return all verbs concatenated", IDX_ALLOWED, IDX_NUMERIC},
{"ka.req.role.rules.resources", "When the request object refers to a role/cluster role, the resources associated with the role's rules. With an index, return only the resources from the ith rule. Without an index, return all resources concatenated", IDX_ALLOWED, IDX_NUMERIC},
{"ka.req.service.type", "When the request object refers to a service, the service type"},
{"ka.req.service.ports", "When the request object refers to a service, the service's ports. Can be indexed (e.g. ka.req.service.ports[0]). Without any index, returns all ports", IDX_ALLOWED, IDX_NUMERIC},
{"ka.req.volume.hostpath", "If the request object contains volume definitions, whether or not a hostPath volume exists that mounts the specified path from the host (...hostpath[/etc]=true if a volume mounts /etc from the host). The index can be a glob, in which case all volumes are considered to find any path matching the specified glob (...hostpath[/usr/*] would match either /usr/local or /usr/bin)", IDX_REQUIRED, IDX_KEY},
{"ka.resp.name", "The response object name"},
{"ka.response.code", "The response code"},
{"ka.response.reason", "The response reason (usually present only for failures)"}
}};
{{"ka.auditid", "The unique id of the audit event"},
{"ka.stage", "Stage of the request (e.g. RequestReceived, ResponseComplete, etc.)"},
{"ka.auth.decision", "The authorization decision"},
{"ka.auth.reason", "The authorization reason"},
{"ka.user.name", "The user name performing the request"},
{"ka.user.groups", "The groups to which the user belongs"},
{"ka.impuser.name", "The impersonated user name"},
{"ka.verb", "The action being performed"},
{"ka.uri", "The request URI as sent from client to server"},
{"ka.uri.param", "The value of a given query parameter in the uri (e.g. when uri=/foo?key=val, ka.uri.param[key] is val).", IDX_REQUIRED, IDX_KEY},
{"ka.target.name", "The target object name"},
{"ka.target.namespace", "The target object namespace"},
{"ka.target.resource", "The target object resource"},
{"ka.target.subresource", "The target object subresource"},
{"ka.req.binding.subjects", "When the request object refers to a cluster role binding, the subject (e.g. account/users) being linked by the binding"},
{"ka.req.binding.subject.has_name", "When the request object refers to a cluster role binding, return true if a subject with the provided name exists", IDX_REQUIRED, IDX_KEY},
{"ka.req.binding.role", "When the request object refers to a cluster role binding, the role being linked by the binding"},
{"ka.req.configmap.name", "If the request object refers to a configmap, the configmap name"},
{"ka.req.configmap.obj", "If the request object refers to a configmap, the entire configmap object"},
{"ka.req.container.image", "When the request object refers to a container, the container's images. Can be indexed (e.g. ka.req.container.image[0]). Without any index, returns the first image", IDX_ALLOWED, IDX_NUMERIC},
{"ka.req.container.image.repository", "The same as req.container.image, but only the repository part (e.g. sysdig/falco)", IDX_ALLOWED, IDX_NUMERIC},
{"ka.req.container.host_network", "When the request object refers to a container, the value of the hostNetwork flag."},
{"ka.req.container.privileged", "When the request object refers to a container, whether or not any container is run privileged. With an index, return whether or not the ith container is run privileged.", IDX_ALLOWED, IDX_NUMERIC},
{"ka.req.role.rules", "When the request object refers to a role/cluster role, the rules associated with the role"},
{"ka.req.role.rules.apiGroups", "When the request object refers to a role/cluster role, the api groups associated with the role's rules. With an index, return only the api groups from the ith rule. Without an index, return all api groups concatenated", IDX_ALLOWED, IDX_NUMERIC},
{"ka.req.role.rules.nonResourceURLs", "When the request object refers to a role/cluster role, the non resource urls associated with the role's rules. With an index, return only the non resource urls from the ith rule. Without an index, return all non resource urls concatenated", IDX_ALLOWED, IDX_NUMERIC},
{"ka.req.role.rules.verbs", "When the request object refers to a role/cluster role, the verbs associated with the role's rules. With an index, return only the verbs from the ith rule. Without an index, return all verbs concatenated", IDX_ALLOWED, IDX_NUMERIC},
{"ka.req.role.rules.resources", "When the request object refers to a role/cluster role, the resources associated with the role's rules. With an index, return only the resources from the ith rule. Without an index, return all resources concatenated", IDX_ALLOWED, IDX_NUMERIC},
{"ka.req.service.type", "When the request object refers to a service, the service type"},
{"ka.req.service.ports", "When the request object refers to a service, the service's ports. Can be indexed (e.g. ka.req.service.ports[0]). Without any index, returns all ports", IDX_ALLOWED, IDX_NUMERIC},
{"ka.req.volume.hostpath", "If the request object contains volume definitions, whether or not a hostPath volume exists that mounts the specified path from the host (...hostpath[/etc]=true if a volume mounts /etc from the host). The index can be a glob, in which case all volumes are considered to find any path matching the specified glob (...hostpath[/usr/*] would match either /usr/local or /usr/bin)", IDX_REQUIRED, IDX_KEY},
{"ka.resp.name", "The response object name"},
{"ka.response.code", "The response code"},
{"ka.response.reason", "The response reason (usually present only for failures)"},
{"ka.useragent", "The useragent of the client who made the request to the apiserver"}}};
{
m_aliases = {
@@ -693,21 +698,20 @@ k8s_audit_filter_check::k8s_audit_filter_check()
{"ka.req.volume.hostpath", {"/requestObject/spec/volumes"_json_pointer, check_hostpath_vols}},
{"ka.resp.name", {"/responseObject/metadata/name"_json_pointer}},
{"ka.response.code", {"/responseStatus/code"_json_pointer}},
{"ka.response.reason", {"/responseStatus/reason"_json_pointer}}
};
{"ka.response.reason", {"/responseStatus/reason"_json_pointer}},
{"ka.useragent", {"/userAgent"_json_pointer}}};
}
}
k8s_audit_filter_check::~k8s_audit_filter_check()
{
}
json_event_filter_check *k8s_audit_filter_check::allocate_new()
{
k8s_audit_filter_check *chk = new k8s_audit_filter_check();
return (json_event_filter_check *) chk;
return (json_event_filter_check *)chk;
}
json_event_filter::json_event_filter()
@@ -762,9 +766,9 @@ std::list<json_event_filter_check::check_info> &json_event_filter_factory::get_f
return m_info;
}
json_event_formatter::json_event_formatter(json_event_filter_factory &json_factory, std::string &format)
: m_format(format),
m_json_factory(json_factory)
json_event_formatter::json_event_formatter(json_event_filter_factory &json_factory, std::string &format):
m_format(format),
m_json_factory(json_factory)
{
parse_format();
}
@@ -777,7 +781,7 @@ std::string json_event_formatter::tostring(json_event *ev)
{
std::string ret;
std::list<std::pair<std::string,std::string>> resolved;
std::list<std::pair<std::string, std::string>> resolved;
resolve_tokens(ev, resolved);
@@ -793,7 +797,7 @@ std::string json_event_formatter::tojson(json_event *ev)
{
nlohmann::json ret;
std::list<std::pair<std::string,std::string>> resolved;
std::list<std::pair<std::string, std::string>> resolved;
resolve_tokens(ev, resolved);
@@ -828,11 +832,11 @@ void json_event_formatter::parse_format()
{
// Skip the %
tformat.erase(0, 1);
json_event_filter_check *chk = (json_event_filter_check *) m_json_factory.new_filtercheck(tformat.c_str());
json_event_filter_check *chk = (json_event_filter_check *)m_json_factory.new_filtercheck(tformat.c_str());
if(!chk)
{
throw falco_exception(string ("Could not parse format string \"") + m_format + "\": unknown filtercheck field " + tformat);
throw falco_exception(string("Could not parse format string \"") + m_format + "\": unknown filtercheck field " + tformat);
}
size = chk->parsed_size();
@@ -852,7 +856,7 @@ void json_event_formatter::parse_format()
// Empty fields are only allowed at the beginning of the string
if(m_tokens.size() > 0)
{
throw falco_exception(string ("Could not parse format string \"" + m_format + "\": empty filtercheck field"));
throw falco_exception(string("Could not parse format string \"" + m_format + "\": empty filtercheck field"));
}
continue;
}
@@ -864,7 +868,7 @@ void json_event_formatter::parse_format()
}
}
void json_event_formatter::resolve_tokens(json_event *ev, std::list<std::pair<std::string,std::string>> &resolved)
void json_event_formatter::resolve_tokens(json_event *ev, std::list<std::pair<std::string, std::string>> &resolved)
{
for(auto tok : m_tokens)
{

View File

@@ -17,8 +17,6 @@ limitations under the License.
*/
#include <sstream>
#include "rules.h"
#include "logger.h"

View File

@@ -21,7 +21,6 @@ limitations under the License.
#include <set>
#include <memory>
#include <regex>
#include "sinsp.h"
#include "filter.h"
@@ -58,13 +57,13 @@ class falco_rules
void add_filter(string &rule, std::set<uint32_t> &evttypes, std::set<uint32_t> &syscalls, std::set<string> &tags);
void add_k8s_audit_filter(string &rule, std::set<string> &tags);
void enable_rule(string &rule, bool enabled);
std::string get_context(const std::string &content, uint64_t line, uint64_t column);
lua_parser* m_sinsp_lua_parser;
lua_parser* m_json_lua_parser;
sinsp* m_inspector;
falco_engine *m_engine;
lua_State* m_ls;
string m_lua_load_rules = "load_rules";
string m_lua_ignored_syscalls = "ignored_syscalls";
string m_lua_ignored_events = "ignored_events";