Compare commits

...

66 Commits

Author SHA1 Message Date
Leonardo Di Donato
beafd2b868 update(userspace/falco): access peer from context method
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-21 13:37:55 +00:00
Leonardo Di Donato
31bb5c5070 build: refinements to comments (in CMakeLists.txt files and in output to stdout)
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-21 13:37:29 +00:00
Leonardo Di Donato
195b475204 new(userspace/falco): push back header metadata (session and request ID) when received from clients
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-21 13:36:49 +00:00
Leonardo Di Donato
4da9cd3764 wip(userspace/falco): evaluate usage of any protobuf type
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-17 18:48:36 +00:00
Leonardo Di Donato
b7e4913de1 build(userspace/falco): compile inputs proto
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-17 18:47:56 +00:00
Leonardo Di Donato
356188542c chore: output the build type during the build
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-17 15:59:20 +00:00
Leonardo Di Donato
fd7731cf09 new(userspace/falco): initial inputs service implementation
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-17 15:58:52 +00:00
Leonardo Di Donato
b1d33ddf08 new(userspace/falco): initial inputs.input RPC endpoint (unary)
Initial implementation of the start, process, end methods for the unary
version of the Inputs API.

Infact, in some use cases we do not want a streaming API but an unary
one.
Also, having a unary API that accepts repeated events can prove to be
more performant than a streaming one. But this needs to be proven by
numbers.

Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-17 15:56:34 +00:00
Leonardo Di Donato
f7c66cbbdc wip(userspace/falco): initial input and event proto files
Atm, these protos try to mimic sinps_event structure. It's very likely,
for performances reasons, decoding reasons, copying reasons, we do not
want them to be so big.

Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-17 15:53:58 +00:00
toc-me[bot]
d30df38e4b update(proposals): toc for 20190826-grpc-outputs.md
Co-authored-by: Leonardo Di Donato <leodidonato@gmail.com>
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-11 12:57:23 +00:00
Leonardo Di Donato
74d1a1f18f update(userspace/falco): use falco::outputs
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-11 12:54:54 +00:00
Leonardo Di Donato
cc847f53bb build: using newer outputs.proto
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-11 12:51:20 +00:00
Leonardo Di Donato
051a1a6f74 chore(userspace/falco): renaming output.proto, packages, and RPC name to plural
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-11 12:50:51 +00:00
Leonardo Di Donato
9c112890d4 update(proposals): naming of Outputs API
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-11 12:49:29 +00:00
Leonardo Di Donato
8ecf208901 update(userspace/falco): use internal protobuf API for gRPC stream contexts and request contexts
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-11 01:59:45 +00:00
Leonardo Di Donato
bd3c2ce8e8 build: compile internal protobuf API for gRPC
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-11 01:56:25 +00:00
Leonardo Di Donato
f49014bbe4 new(userspace/falco): introducing internal protobuf API for gRPC
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-11 01:55:43 +00:00
Leonardo Di Donato
e4fe9104f3 update(userspace/falco): reuse falco protobuf schema for grpc logging level, too
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-11 00:45:00 +00:00
Leonardo Di Donato
03df81af23 update(userspace/falco): set gRPC logging severity using Falco logging level (config)
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-11 00:27:02 +00:00
Leonardo Di Donato
fcb33d32cf fix(userspace/falco): fixing logs without new line
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-11 00:23:15 +00:00
Leonardo Di Donato
cb1cb5b12c fix(userspace/falco): make log level a project-wide config
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-11 00:22:36 +00:00
Leonardo Di Donato
467f33c5ff update(userspace/falco): log (debug + error) info about gRPC events per thread
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-10 19:51:12 +00:00
Leonardo Di Donato
4e916a7a58 chore(userspace/falco): print debug info for gRPC service implementations
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-10 19:50:10 +00:00
Leonardo Di Donato
325357c465 update(userspace/falco): store a representation of grpc meta into the context
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-10 19:48:59 +00:00
Leonardo Di Donato
0f81e9b95a chore(userspace/falco): log request's context info like tag, state, stream (grpc)
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-10 18:30:18 +00:00
Leonardo Di Donato
8b167bb1d9 chore(userspace/falco): log grpc debug info like session_id, request_id, context status, ...
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-10 18:29:16 +00:00
Leonardo Di Donato
8dba2485e2 update(userspace/falco): make grpc context accessible
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-10 18:28:29 +00:00
Leonardo Di Donato
85cd219682 chore(userspace/falco): enable grpc debug logging verbosity
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-10 18:27:33 +00:00
Jean-Philippe Lachance
488e667f46 Add Coveo to the list of Falco adopters
Signed-off-by: Jean-Philippe Lachance <jplachance@coveo.com>
2020-02-07 11:47:06 +01:00
Leonardo Di Donato
253ff64d64 chore: stick with the error messages we have
Because we can't easily change the integration test fixtures.

Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-07 11:28:57 +01:00
Leonardo Di Donato
b3171dbae1 update(userspace/falco): use mutable proto fields where applicable
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-07 11:28:57 +01:00
Leonardo Di Donato
738d757b08 docs(userspace/falco): document gRPC errors and actions
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-07 11:28:57 +01:00
Leonardo Di Donato
5663d4d02b update(userspace/falco): major, minor, patch are digits, so use integers
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-07 11:28:57 +01:00
Leonardo Di Donato
2a9c9bdc53 update(cmake/modules): module to detect Falco version from the git index
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-07 11:28:57 +01:00
Leonardo Di Donato
ae2eb8de8e fix(userspace): ensure threadiness is gt 0
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-07 11:28:57 +01:00
Leonardo Di Donato
c7aff2d4cb new(userspace/falco): register version gRPC service
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-07 11:28:57 +01:00
Leonardo Di Donato
bc297bdc8f build: better way to extract falco commit hash (also extract ref)
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-07 11:28:57 +01:00
Leonardo Di Donato
2a91289ee4 update(userspace/falco): request context and request stream context templatize the service too now
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-07 11:28:57 +01:00
Leonardo Di Donato
c224633454 new(userspace/falco): initial work for version gRPC svc registration
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-07 11:28:57 +01:00
Leonardo Di Donato
714a6619ad new(userspace/falco): gRPC unary version service impl
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-07 11:28:57 +01:00
Leonardo Di Donato
550ee0d8fc build: compile version proto
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-07 11:28:57 +01:00
Leonardo Di Donato
8d49e45d44 docs(userspace/falco): document version protobuf
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-07 11:28:57 +01:00
Leonardo Di Donato
5e8f98ea92 new(userspace/falco): protobuf for gRPC version service
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-07 11:28:57 +01:00
Leonardo Di Donato
e560056b92 update(userspace/falco): define version part variables
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-07 11:28:57 +01:00
Leonardo Di Donato
84261d2071 build: extract version pieces
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-07 11:28:57 +01:00
Leonardo Di Donato
c374264384 docs(tests/falco): license for webserver unit tests
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-07 11:28:57 +01:00
Lorenzo Fontana
af3d89b706 fix(userspace/engine): formatting and auto declarations
Signed-off-by: Lorenzo Fontana <lo@linux.com>
2020-02-06 19:16:21 +01:00
Lorenzo Fontana
5b9001d1d5 fix(userspace/engine): make sure that m_uses_paths is always false by default
Signed-off-by: Lorenzo Fontana <lo@linux.com>
2020-02-06 19:16:21 +01:00
Lorenzo Fontana
240f7e2057 fix(userspace/engine): base64 format fix
Signed-off-by: Lorenzo Fontana <lo@linux.com>
Co-Authored-By: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-04 21:00:00 +01:00
Vaibhav
22a95796c1 feat(userspace): Add banned.h which includes banned functions.
This defines certain functions as invalid tokens, i.e., when
compiled, the compiler throws an error.

Currently only `strcpy` is included as a banned function.

Fixes #788

Signed-off-by: Vaibhav <vrongmeal@gmail.com>
2020-02-04 17:47:56 +01:00
Leonardo Di Donato
f98da284d0 docs: update references to branches into README
Co-authored-by: Lorenzo Fontana <lo@linux.com>
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-02-03 17:15:45 +01:00
Mark Stemm
3693b16c91 Let puma reactor spawn shells
Sample Falco alert:

```
Shell spawned by untrusted binary (user=git shell=sh parent=puma reactor
cmdline=sh -c pgrep -fl "unicorn.* worker\[.*?\]" pcmdline=puma reactor
gparent=puma ggparent=runsv aname[4]=ru...
```

https://github.com/puma/puma says it is "A Ruby/Rack web server built
for concurrency".

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2020-02-03 16:13:57 +01:00
Mark Stemm
48a0f512fb Let cilium-cni change namespaces
Sample Falco alert:

```
Namespace change (setns) by unexpected program (user=root
command=cilium-cni parent=cilium-cni host CID2 CID1 image=<NA>)
```

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2020-02-03 16:13:57 +01:00
Mark Stemm
01c9d8ba31 Let runc write to /exec.fifo
Sample Falco alert:

```
File below / or /root opened for writing (user=<NA>
command=runc:[1:CHILD] init parent=docker-runc-cur file=/exec.fifo
program=runc:[1:CHILD] CID1 image=<NA>)
```

This github issue provides some context:
https://github.com/opencontainers/runc/pull/1698

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2020-02-03 16:13:57 +01:00
Mark Stemm
7794e468ba Alow writes to /etc/pki from openshift secrets dir
Sample falco alert:

```
File below /etc opened for writing (user=root command=cp
/run/secrets/kubernetes.io/serviceaccount/ca.crt
/etc/pki/ca-trust/source/anchors/openshift-ca.crt parent=bash
pcmdline=bash -c #!/bin/bash\nset -euo pipefail\n\n# set by the node
image\nunset KUB...
```

The exception is conditioned on containers.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2020-02-03 16:13:57 +01:00
Mark Stemm
0d74f3938d Let avinetworks supervisor write some ssh cfg
Sample Falco alert:

```
File below /etc opened for writing (user=root command=se_supervisor.p
/opt/avi/scripts/se_supervisor.py -d parent=systemd pcmdline=systemd
file=/etc/ssh/ssh_monitor_config_10.24.249.200 program=se_supervisor.p
gparent=docker-containe ggparent=docker-con...
```

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2020-02-03 16:13:57 +01:00
Mark Stemm
e5f06e399f Let mcafee write to /etc/cma.d
Sample Falco alert:

```
File below /etc opened for writing (user=root command=macompatsvc
self_start parent=macompatsvc pcmdline=macompatsvc self_start
file=/etc/cma.d/lpc.conf program=macompatsvc gparent=macompatsvc
ggparent=systemd gggparent=<NA> CID1 image=<NA>)
```

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2020-02-03 16:13:57 +01:00
Mark Stemm
fa3e48ca1a Add "dsc_host" as a MS OMS program
Sample Falco alert:

```
File below /etc opened for writing (user=<NA> command=dsc_host
/opt/dsc/output PerformRequiredConfigurationChecks 1 parent=python
pcmdline=python
/opt/microsoft/omsconfig/Scripts/PerformRequiredConfigurationChecks.py
file=/etc/opt/omi/conf/omsconfig/con...
```

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2020-02-03 16:13:57 +01:00
Kris Nova
bf0cdb7c38 Updating community section of README.md
Pointing to the community repo as the source of truth

Signed-off-by: Kris Nova <kris@nivenly.com>
2020-01-28 14:23:56 +01:00
Kris Nova
be67c4adaf Updating logo and slogan to match branding guidelines
Signed-off-by: Kris Nova <kris@nivenly.com>
2020-01-28 14:21:21 +01:00
Kris Nova
b088a57dd0 Adding Glossary
- Adding section to define language used in the project

Signed-off-by: Kris Nova <kris@nivenly.com>
2020-01-28 12:35:15 +01:00
Kris Nova
40fbc96736 Updating with comments from Bencer
Signed-off-by: Kris Nova <kris@nivenly.com>
2020-01-28 12:35:15 +01:00
Kris Nova
c350876456 Updating README.md from Janet's review
- Updating language around contributed/created/donated
 - Adding 3 key benefits

Signed-off-by: Kris Nova <kris@nivenly.com>
2020-01-28 12:35:15 +01:00
Kris Nova
bf8367b280 Updating Falco Logo Path
Signed-off-by: Kris Nova <kris@nivenly.com>
2020-01-28 12:35:15 +01:00
Kris Nova
c510808299 Adding branding guidelines to GitHub
Signed-off-by: Kris Nova <kris@nivenly.com>
2020-01-28 12:35:15 +01:00
Leonardo Di Donato
a1d6a4762e fix(docker/minimal): libyaml
Co-authored-by: Lorenzo Fontana <lo@linux.com>
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-01-24 11:53:02 +01:00
49 changed files with 1215 additions and 355 deletions

View File

@@ -4,6 +4,8 @@ This is a list of production adopters of Falco (in alphabetical order):
* [Booz Allen Hamilton](https://www.boozallen.com/) - BAH leverages Falco as part of their Kubernetes environment to verify that work loads behave as they did in their CD DevSecOps pipelines. BAH offers a solution to internal developers to easily build DevSecOps pipelines for projects. This makes it easy for developers to incorporate Security principles early on in the development cycle. In production, Falco is used to verify that the code the developer ships does not violate any of the production security requirements. BAH [are speaking at Kubecon NA 2019](https://kccncna19.sched.com/event/UaWr/building-reusable-devsecops-pipelines-on-a-secure-kubernetes-platform-steven-terrana-booz-allen-hamilton-michael-ducy-sysdig) on their use of Falco.
* [Coveo](https://www.coveo.com/) - Coveo stitches together content and data, learning from every interaction, to tailor every experience using AI to drive growth, satisfy customers and develop employee proficiency. All Falco events are centralized in our SIEM for analysis. Understanding what is running on production servers, and the context around why things are running is even more tricky now that we have further abstractions with containers and orchestration systems. Falco is giving us a good visibility inside containers and complement other Host and Network Intrusion Detection Systems. In a near future, we expect to deploy serverless functions to take action when Falco identifies patterns worth taking action for.
* [Frame.io](https://frame.io/) - Frame.io is a cloud-based (SaaS) video review and collaboration platform that enables users to securely upload source media, work-in-progress edits, dailies, and more into private workspaces where they can invite their team and clients to collaborate on projects. Understanding what is running on production servers, and the context around why things are running is even more tricky now that we have further abstractions like Docker and Kubernetes. To get this needed visibility into our system, we rely on Falco. Falco's ability to collect raw system calls such as open, connect, exec, along with their arguments offer key insights on what is happening on the production system and became the foundation of our intrusion detection and alerting system.
* [League](https://league.com/ca/) - League provides health benefits management services to help employees understand and get the most from their benefits, and employers to provide effective, efficient plans. Falco is used to monitor our deployed services on Kubernetes, protecting against malicious access to containerswhich could lead to leaks of PHI or other sensitive data. The Falco alerts are logged in Stackdriver for grouping and further analysis. In the future, we're hoping for integrations with Prometheus and AlertManager as well.

View File

@@ -18,7 +18,8 @@ option(USE_BUNDLED_DEPS "Bundle hard to find dependencies into the Falco binary"
option(BUILD_WARNINGS_AS_ERRORS "Enable building with -Wextra -Werror flags" OFF)
# Elapsed time
# set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CMAKE_COMMAND} -E time") # TODO(fntlnz, leodido): add a flag to enable this
# TODO(fntlnz, leodido): add a flag to enable this
# set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CMAKE_COMMAND} -E time")
# Make flag for parallel processing
include(ProcessorCount)
@@ -48,6 +49,7 @@ else()
set(CMAKE_BUILD_TYPE "release")
set(KBUILD_FLAGS "${DRAIOS_FEATURE_FLAGS}")
endif()
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
set(CMAKE_COMMON_FLAGS "-Wall -ggdb ${DRAIOS_FEATURE_FLAGS}")
@@ -67,24 +69,7 @@ set(CMAKE_CXX_FLAGS_DEBUG "${DRAIOS_DEBUG_FLAGS}")
set(CMAKE_C_FLAGS_RELEASE "-O3 -fno-strict-aliasing -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -fno-strict-aliasing -DNDEBUG")
# Create the falco version variable according to git index
if(NOT FALCO_VERSION)
include(GetGitRevisionDescription)
git_get_exact_tag(FALCO_TAG)
if(NOT FALCO_TAG)
git_describe(FALCO_VERSION "--always")
git_local_changes(FALCO_CHANGES)
if(FALCO_CHANGES STREQUAL "DIRTY")
string(TOLOWER "${FALCO_CHANGES}" FALCO_CHANGES)
set(FALCO_VERSION "${FALCO_VERSION}.${FALCO_CHANGES}")
endif()
set(FALCO_VERSION "0.${FALCO_VERSION}")
else()
set(FALCO_VERSION "${FALCO_TAG}")
string(REGEX REPLACE "^v([0-9]+)(\\.[0-9]+)(\\.[0-9]+)?" "\\1\\2\\3" FALCO_VERSION ${FALCO_VERSION})
endif()
endif()
message(STATUS "Falco version: ${FALCO_VERSION}")
include(GetFalcoVersion)
set(PACKAGE_NAME "falco")
set(PROBE_VERSION "${FALCO_VERSION}")
@@ -240,6 +225,7 @@ include(sysdig)
# Installation
install(FILES falco.yaml DESTINATION "${FALCO_ETC_DIR}")
# Coverage
include(Coverage)
# Tests

View File

@@ -1,16 +1,16 @@
<p><img align="right" src="https://github.com/falcosecurity/falco-website/raw/master/themes/falco-fresh/static/images/favicon.png" width="64px"/></p>
<p></p>
<p align="center"><img src="https://raw.githubusercontent.com/falcosecurity/community/master/logo/primary-logo.png" width="360"></p>
<p align="center"><b>Cloud Native Runtime Security.</b></p>
# Falco
<hr>
# The Falco Project
#### Latest release
**v0.19.0**
Read the [change log](https://github.com/falcosecurity/falco/blob/dev/CHANGELOG.md)
Read the [change log](CHANGELOG.md)
Dev Branch: [![Build Status](https://travis-ci.com/falcosecurity/falco.svg?branch=dev)](https://travis-ci.com/falcosecurity/falco)<br />
Master Branch: [![Build Status](https://travis-ci.com/falcosecurity/falco.svg?branch=master)](https://travis-ci.com/falcosecurity/falco)<br />
CII Best Practices: [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/2317/badge)](https://bestpractices.coreinfrastructure.org/projects/2317)
[![Build Status](https://img.shields.io/circleci/build/github/falcosecurity/falco/master?style=for-the-badge)](https://circleci.com/gh/falcosecurity/falco) [![CII Best Practices Summary](https://img.shields.io/cii/summary/2317?label=CCI%20Best%20Practices&style=for-the-badge)](https://bestpractices.coreinfrastructure.org/projects/2317) [![GitHub](https://img.shields.io/github/license/falcosecurity/falco?style=for-the-badge)](COPYING)
---
@@ -47,27 +47,7 @@ See [Falco Documentation](https://falco.org/docs/) to quickly get started using
Join the Community
---
* [Join the mailing list](https://lists.cncf.io/g/cncf-falco-dev/) for news and a Google calendar invite for our Falco open source meetings. Note: this is the only way to get a calendar invite for our open meetings.
* [Website](https://falco.org) for Falco.
* Join our [Public Slack](https://slack.sysdig.com) channel for Falco announcements and discussions.
Community call
---
> Are you using Falco? Do you have have ideas for things to do with Falco? How can Falco be better?
Falco has bi-weekly [community](https://github.com/falcosecurity/community) call which is an open call to discuss Falco from a user perspective. These happen on opposite weeks of Repo planning calls.
[Wednesdays at 8am Pacific](https://lists.cncf.io/g/cncf-falco-dev/calendar) on [Zoom](https://sysdig.zoom.us/j/213235330).
Repo planning
---
> Do you want to contribute to Falco? Are you interested in working on Falco? Do you want to fix something or make something better?
Falco has bi-weekly planning meetings which is an open call to discuss upcoming Falco releases, and assign open GitHub issues to engineers. These happen on opposite weeks of office hours calls.
[Wednesdays at 8am Pacific](https://lists.cncf.io/g/cncf-falco-dev/calendar) on [Zoom](https://sysdig.zoom.us/j/213235330).
To get involved with The Falco Project please visit [the community repository](https://github.com/falcosecurity/community) to find more.
License Terms
---

142
brand/README.md Normal file
View File

@@ -0,0 +1,142 @@
<p align="center"><img src="primary-logo.png" width="360"></p>
<p align="center"><b>Cloud Native Runtime Security.</b></p>
# Falco Branding Guidelines
This document describes The Falco Project's branding guidelines, language, and message.
Content in this document can be used to publically share about Falco.
### Logo
There are 3 logos available for use in this directory. Use the primary logo unless required otherwise due to background issues, or printing.
The Falco logo is Apache 2 licensed and free to use in media and publication for the CNCF Falco project.
### Slogan
> Cloud Native Runtime Security
### What is Falco?
Falco is a runtime security project originally created by Sysdig, Inc.
Falco was contributed to the CNCF in October 2018.
The CNCF now owns The Falco Project.
### What is Runtime Security?
Runtime security refers to an approach to preventing unwanted activity on a computer system.
With runtime security an operator deploys **both** prevention tooling (access control, policy enforcement, etc) along side detection tooling (systems observability, anomaly detection, etc).
Runtime security is the practice of using detection tooling to detect unwanted behavior, such that it can then be prevented using prevention techniques.
Runtime security is a holistic approach to defense, and useful in scenarios where prevention tooling either was unaware of an exploit or attack vector, or when defective applications are ran in even the most secure environment.
### What does Falco do?
Falco consumes signals from the Linux kernel, and container management tools such as Docker and Kubernetes.
Falco parses the signals and asserts them against security rules.
If a rule has been violated, Falco triggers an alert.
### How does Falco work?
Falco traces kernel events and reports information about the system calls being executed at runtime.
Falco leverages the extended berkley packet filter (eBPF) which is a kernel feature implemented for dynamic crash-resilient and secure code execution in the kernel.
Falco enriches these kernel events with information about containers running on the system.
Falco also can consume signals from other input streams such as the containerd socket, the Kubernetes API server and the Kubernetes audit log.
At runtime, Falco will reason about these events and assert them against configured security rules.
Based on the severity of a violation an alert is triggered.
These alerts are configurable and extensible, for instance sending a notification or [plumbing through to other projects like Prometheus](https://github.com/falcosecurity/falco-exporter).
### Benefits of using Falco
- **Strengthen Security** Create security rules driven by a context-rich and flexible engine to define unexpected application behavior.
- **Reduce Risk** Immediately respond to policy violation alerts by plugging Falco into your current security response workflows and processes.
- **Leverage up-to-date Rules** Alert using community-sourced detections of malicious activity and CVE exploits.
### Falco and securing Kubernetes
Securing Kubernetes requires putting controls in place to detect unexpected behavior that could be malicious or harmful to a cluster or application(s).
Examples of malicious behavior include:
- Exploits of unpatched and new vulnerabilities in applications or Kubernetes itself.
- Insecure configurations in applications or Kubernetes itself.
- Leaked or weak credentials or secret material.
- Insider threats from adjacent applications running at the same layer.
Falco is capable of [consuming the Kubernetes audit logs](https://kubernetes.io/docs/tasks/debug-application-cluster/falco/#use-falco-to-collect-audit-events).
By adding Kubernetes application context, and Kubernetes audit logs teams can understand who did what.
### Writing about Falco
##### Yes
Notice the capitalization of the following terms.
- The Falco Project
- Falco
##### No
- falco
- the falco project
- the Falco project
### Encouraged Phrasing
Below are phrases that the project has reviewed, and found to be effective ways of messaging Falco's value add.
Even when processes are in place for vulnerability scanning and implementing pod security and network policies, not every risk will be addressed. You still need mechanisms to confirm these security barriers are effective, help configure them, and provide with a last line of defense when they fail.
##### Falco as a factory
This term refers to the concept that Falco is a stateless processing engine. A large amount of data comes into the engine, but meticulously crafted security alerts come out.
##### The engine that powers...
Falco ultimately is a security engine. It reasons about signals coming from a system at runtime, and can alert if an anomaly is detected.
##### Anomaly detection
This refers to an event that occurs with something unsual, concerning, or odd occurs.
We can associate anomalies with unwanted behavior, and alert in their presence.
##### Detection tooling
Falco does not prevent unwanted behavior.
Falco however alerts when unusual behavior occurs.
This is commonly referred to as **detection** or **forensics**.
---
# Glossary
#### Probe
Used to describe the `.o` object that would be dynamically loaded into the kernel as a secure and stable (e)BPF probe.
This is one option used to pass kernel events up to userspace for Falco to consume.
Sometimes this word is incorrectly used to refer to a `module`.
#### Module
Used to describe the `.ko` object that would be loaded into the kernel as a potentially risky kernel module.
This is one option used to pass kernel events up to userspace for Falco to consume.
Sometimes this word is incorrectly used to refer to a `probe`.
#### Driver (deprecated)
An older, more generalized term for a `module` or `probe`. We discourage the use of this word as a project.
#### Falco
The name of the project, and also the name of [the main engine](https://github.com/falcosecurity/falco) that the rest of the project is built on.
#### Sysdig, Inc
The name of the company that originally created The Falco Project, and later donated to the CNCF.
#### sysdig
A [CLI tool](https://github.com/draios/sysdig) used to evaluate kernel system events at runtime.

BIN
brand/primary-logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

1
brand/teal-logo.png Normal file
View File

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 708.41 374.92"><defs><style>.cls-1{fill:#00b4c8;}</style></defs><title>Falco horizontal logo_teal2</title><g id="fqqZXT"><path class="cls-1" d="M204.69,154.4Q151.5,208,98,261.25a48.42,48.42,0,0,1-5.27,4.87c-2.55,1.89-5.34,2-7.65-.45s-1.51-5,.41-7.06c4.6-4.94,9.35-9.74,14.13-14.5q52.56-52.31,105.14-104.59c3.35-3.34,18.05,7.52,21.58,11.1"/><path class="cls-1" d="M215.06,171.36c-.15,2.14-1.54,3.55-2.93,4.94l-87.82,87.79c-2.75,2.74-6,5.42-9.46,1.68-3.15-3.39-.5-6.44,2.06-9q43.44-43.44,86.89-86.87c2.21-2.22,4.58-4.23,8-3A4.61,4.61,0,0,1,215.06,171.36Z"/><path class="cls-1" d="M70.93,71c2.42-.09,4.09,1.31,5.64,2.87q41.82,41.79,83.61,83.59c2.6,2.61,5,5.74,1.69,9s-6.41,1-9-1.66Q111,123,69.25,81.2c-2.09-2.1-3.72-4.39-2.45-7.53A4.34,4.34,0,0,1,70.93,71Z"/><path class="cls-1" d="M203.42,268c-5,1-8.9-1.34-12.45-5-6.35-6.61-12.87-13-19.41-19.46-3.85-3.8-4-7.41-.14-11.28,11.14-11.07,22.21-22.21,33.35-33.29,2.45-2.44,5.43-4.49,8.55-1.55,3.48,3.29,1.19,6.41-1.39,9-8.74,8.84-17.44,17.73-26.4,26.35-3.4,3.27-3.93,5.72-.19,9.06,4.22,3.78,8.13,7.91,12,12,2.54,2.68,5.35,4.25,9.18,4.11s8.28-.12,8.16,5.09c-.12,5-4.74,4.8-8.4,5.14A21,21,0,0,1,203.42,268Z"/><path class="cls-1" d="M148.7,178.36c-.75,3.49-2.68,5.6-6.43,4.36a13,13,0,0,1-4.74-3.31q-30.11-30-60.1-60a23.14,23.14,0,0,1-2.56-3c-1.72-2.42-1.88-5,.3-7.11s4.84-1.76,7,.26c3.65,3.42,7.17,7,10.71,10.53q25.65,25.64,51.28,51.3C146.12,173.37,148.49,175.13,148.7,178.36Z"/><path class="cls-1" d="M133.74,192.93a4.9,4.9,0,0,1-2.53,4.29,5.37,5.37,0,0,1-6.63-.95c-3.35-3.1-6.57-6.34-9.8-9.57q-14.34-14.3-28.61-28.63a34.27,34.27,0,0,1-4.17-5,4.57,4.57,0,0,1,.36-6,5,5,0,0,1,6-1.12,11.65,11.65,0,0,1,3.7,2.58q19.44,19.33,38.79,38.76C132.4,188.85,133.77,190.54,133.74,192.93Z"/></g><path class="cls-1" d="M413.15,190.86a25.57,25.57,0,0,0-10.35-6.63,46.78,46.78,0,0,0-16-2.37A83.35,83.35,0,0,0,372,183.12a75.16,75.16,0,0,0-10.58,2.53l2.37,15.48a53.47,53.47,0,0,1,9-2.21A72.44,72.44,0,0,1,385,198a22.61,22.61,0,0,1,8.13,1.26,13,13,0,0,1,5.22,3.56,13.23,13.23,0,0,1,2.76,5.29,24.6,24.6,0,0,1,.79,6.32v3.16a61.65,61.65,0,0,0-7.42-1.34,57.43,57.43,0,0,0-6.64-.4,61.45,61.45,0,0,0-13,1.35,32.26,32.26,0,0,0-11,4.42,22.7,22.7,0,0,0-7.51,8,24.09,24.09,0,0,0-2.76,12A28.39,28.39,0,0,0,356,254.05a21.6,21.6,0,0,0,6.79,8.22,28.56,28.56,0,0,0,10.51,4.58,60.24,60.24,0,0,0,13.58,1.42A137.25,137.25,0,0,0,407,266.93c5.94-.9,10.4-1.66,13.35-2.29V214.56a50.84,50.84,0,0,0-1.66-13.35A24.93,24.93,0,0,0,413.15,190.86Zm-11.3,61.3a71.4,71.4,0,0,1-13.43.94q-7.26,0-11.53-2.6t-4.26-9.4a10,10,0,0,1,1.57-5.77,10.67,10.67,0,0,1,4.19-3.55,20.18,20.18,0,0,1,5.85-1.74,43.43,43.43,0,0,1,6.39-.47,42.23,42.23,0,0,1,6.64.47,37,37,0,0,1,4.58,1Z"/><path class="cls-1" d="M461.38,248.44a9.27,9.27,0,0,1-2-4,26.17,26.17,0,0,1-.55-5.85V143.94l-19.12,3.16v95.1a40.74,40.74,0,0,0,1.35,11,17.57,17.57,0,0,0,4.66,8.06,21.71,21.71,0,0,0,8.92,5,52,52,0,0,0,14.14,1.89l2.69-15.8a29.78,29.78,0,0,1-6.24-1.34A8.76,8.76,0,0,1,461.38,248.44Z"/><path class="cls-1" d="M532.2,251.05a49.24,49.24,0,0,1-9.64.95q-13.11,0-18.64-7.19t-5.53-19.51q0-12.8,5.85-19.83t17.06-7a40.4,40.4,0,0,1,8.92.95,43.38,43.38,0,0,1,7.51,2.37l4.1-15.64a57.88,57.88,0,0,0-22.11-4.26,42.15,42.15,0,0,0-17.06,3.31,37.35,37.35,0,0,0-12.88,9.17,40.64,40.64,0,0,0-8.14,13.82,50.82,50.82,0,0,0-2.84,17.14,56.83,56.83,0,0,0,2.53,17.3A37.22,37.22,0,0,0,489,256.34a34.82,34.82,0,0,0,13,9,47.83,47.83,0,0,0,18.4,3.24,68.05,68.05,0,0,0,13.19-1.27,39.84,39.84,0,0,0,9.56-2.84l-2.69-15.8A45,45,0,0,1,532.2,251.05Z"/><path class="cls-1" d="M625.77,207.37a40.7,40.7,0,0,0-8.14-13.67,35.23,35.23,0,0,0-12.56-8.76,40.93,40.93,0,0,0-16-3.08,40.34,40.34,0,0,0-16,3.08,36.32,36.32,0,0,0-12.56,8.76,39.88,39.88,0,0,0-8.21,13.67,51.31,51.31,0,0,0-2.93,17.77A52,52,0,0,0,552.31,243a40.47,40.47,0,0,0,8.13,13.75,36.57,36.57,0,0,0,12.48,8.85A40.14,40.14,0,0,0,589,268.74a40.69,40.69,0,0,0,16.19-3.15,36.32,36.32,0,0,0,12.56-8.85A39.7,39.7,0,0,0,625.85,243a53.47,53.47,0,0,0,2.84-17.85A51.55,51.55,0,0,0,625.77,207.37Zm-22,37.52q-5.29,7.28-14.77,7.27t-14.77-7.27q-5.29-7.26-5.3-19.75,0-12.31,5.3-19.51T589,198.44q9.48,0,14.77,7.19t5.29,19.51Q609.1,237.62,603.81,244.89Z"/><path class="cls-1" d="M347.24,218h-47.8v50.57H279.65V150h75.89v15.88h-56.1v36.23h47.8Z"/></svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
brand/white-logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -0,0 +1,59 @@
# Retrieve git ref and commit hash
include(GetGitRevisionDescription)
get_git_head_revision(FALCO_REF FALCO_HASH)
# Create the falco version variable according to git index
if(NOT FALCO_VERSION)
string(STRIP "${FALCO_HASH}" FALCO_HASH)
# Try to obtain the exact git tag
git_get_exact_tag(FALCO_TAG)
if(NOT FALCO_TAG)
# Obtain the closest tag
git_describe(FALCO_VERSION "--abbrev=0" "--tags") # suppress the long format
# Fallback version
if(FALCO_VERSION MATCHES "NOTFOUND$")
set(FALCO_VERSION "0.0.0")
endif()
# TODO(leodido) > Construct the prerelease part (semver 2) Construct the Build metadata part (semver 2)
if(NOT FALCO_HASH MATCHES "NOTFOUND$")
string(SUBSTRING "${FALCO_HASH}" 0 7 FALCO_VERSION_BUILD)
# Check whether there are uncommitted changes or not
git_local_changes(FALCO_CHANGES)
if(FALCO_CHANGES STREQUAL "DIRTY")
string(TOLOWER "${FALCO_CHANGES}" FALCO_CHANGES)
set(FALCO_VERSION_BUILD "${FALCO_VERSION_BUILD}.${FALCO_CHANGES}")
endif()
endif()
# Append the build metadata part (semver 2)
if(FALCO_VERSION_BUILD)
set(FALCO_VERSION "${FALCO_VERSION}+${FALCO_VERSION_BUILD}")
endif()
else()
# A tag has been found: use it as the Falco version
set(FALCO_VERSION "${FALCO_TAG}")
# Remove the starting "v" in case there is one
string(REGEX REPLACE "^v(.*)" "\\1" FALCO_VERSION "${FALCO_TAG}")
endif()
# TODO(leodido) > ensure Falco version is semver before extracting parts Populate partial version variables
string(REGEX MATCH "^(0|[1-9][0-9]*)" FALCO_VERSION_MAJOR "${FALCO_VERSION}")
string(REGEX REPLACE "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\..*" "\\2" FALCO_VERSION_MINOR "${FALCO_VERSION}")
string(REGEX REPLACE "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*).*" "\\3" FALCO_VERSION_PATCH
"${FALCO_VERSION}")
string(
REGEX
REPLACE
"^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)-((0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*)\\.(0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*)*).*"
"\\4"
FALCO_VERSION_PRERELEASE
"${FALCO_VERSION}")
if(FALCO_VERSION_PRERELEASE STREQUAL "${FALCO_VERSION}")
set(FALCO_VERSION_PRERELEASE "")
endif()
if(NOT FALCO_VERSION_BUILD)
string(REGEX REPLACE ".*\\+([0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*)" "\\1" FALCO_VERSION_BUILD "${FALCO_VERSION}")
endif()
if(FALCO_VERSION_BUILD STREQUAL "${FALCO_VERSION}")
set(FALCO_VERSION_BUILD "")
endif()
endif()
message(STATUS "Falco version: ${FALCO_VERSION}")

View File

@@ -104,18 +104,19 @@ function(git_describe _var)
return()
endif()
# TODO sanitize if((${ARGN}" MATCHES "&&") OR (ARGN MATCHES "||") OR (ARGN MATCHES "\\;")) message("Please report the
# following error to the project!") message(FATAL_ERROR "Looks like someone's doing something nefarious with
# git_describe! Passed arguments ${ARGN}") endif()
# message(STATUS "Arguments to execute_process: ${ARGN}")
execute_process(
COMMAND "${GIT_EXECUTABLE}" describe ${hash} ${ARGN}
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE res
OUTPUT_VARIABLE out
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND
"${GIT_EXECUTABLE}"
describe
${hash}
${ARGN}
WORKING_DIRECTORY
"${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE
res
OUTPUT_VARIABLE
out
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT res EQUAL 0)
set(out "${out}-${res}-NOTFOUND")
endif()

View File

@@ -16,7 +16,7 @@ set(SYSDIG_CMAKE_WORKING_DIR "${CMAKE_BINARY_DIR}/sysdig-repo")
# this needs to be here at the top
if(USE_BUNDLED_DEPS)
# explicitly force this dependency to use the system OpenSSL
# explicitly force this dependency to use the bundled OpenSSL
set(USE_BUNDLED_OPENSSL ON)
endif()

View File

@@ -12,7 +12,7 @@ ADD https://s3.amazonaws.com/download.draios.com/stable/tgz/x86_64/falco-${FALCO
# ADD will download from URL and unntar
RUN apt-get update && \
apt-get install -y binutils && \
apt-get install -y libyaml-0-2 binutils && \
# curl -O https://s3.amazonaws.com/download.draios.com/stable/tgz/x86_64/falco-${FALCO_VERSION}-x86_64.tar.gz && \
tar xfzv falco-${FALCO_VERSION}-x86_64.tar.gz && \
rm -f falco-${FALCO_VERSION}-x86_64.tar.gz && \
@@ -24,17 +24,25 @@ RUN apt-get update && \
FROM scratch
COPY --from=ubuntu /lib/x86_64-linux-gnu/libanl.so.1 \
/lib/x86_64-linux-gnu/libc.so.6 /lib/x86_64-linux-gnu/libdl.so.2 \
/lib/x86_64-linux-gnu/libgcc_s.so.1 /lib/x86_64-linux-gnu/libm.so.6 \
/lib/x86_64-linux-gnu/libnsl.so.1 /lib/x86_64-linux-gnu/libnss_compat.so.2 \
/lib/x86_64-linux-gnu/libnss_files.so.2 /lib/x86_64-linux-gnu/libnss_nis.so.2 \
/lib/x86_64-linux-gnu/libpthread.so.0 /lib/x86_64-linux-gnu/librt.so.1 \
/lib/x86_64-linux-gnu/libc.so.6 \
/lib/x86_64-linux-gnu/libdl.so.2 \
/lib/x86_64-linux-gnu/libgcc_s.so.1 \
/lib/x86_64-linux-gnu/libm.so.6 \
/lib/x86_64-linux-gnu/libnsl.so.1 \
/lib/x86_64-linux-gnu/libnss_compat.so.2 \
/lib/x86_64-linux-gnu/libnss_files.so.2 \
/lib/x86_64-linux-gnu/libnss_nis.so.2 \
/lib/x86_64-linux-gnu/libpthread.so.0 \
/lib/x86_64-linux-gnu/librt.so.1 \
/lib/x86_64-linux-gnu/libz.so.1 \
/lib/x86_64-linux-gnu/
COPY --from=ubuntu /usr/lib/x86_64-linux-gnu/libstdc++.so.6 \
/usr/lib/x86_64-linux-gnu/libstdc++.so.6
COPY --from=ubuntu /usr/lib/x86_64-linux-gnu/libyaml-0.so.2.0.5 \
/usr/lib/x86_64-linux-gnu/libyaml-0.so.2
COPY --from=ubuntu /etc/ld.so.cache \
/etc/nsswitch.conf \
/etc/ld.so.cache \

View File

@@ -1,4 +1,4 @@
# gRPC Falco Output
# gRPC Falco Outputs
<!-- toc -->
@@ -77,18 +77,18 @@ syntax = "proto3";
import "google/protobuf/timestamp.proto";
import "schema.proto";
package falco.output;
package falco.outputs;
option go_package = "github.com/falcosecurity/client-go/pkg/api/output";
option go_package = "github.com/falcosecurity/client-go/pkg/api/outputs";
// The `subscribe` service defines the RPC call
// The `outputs` service defines a server-streaming RPC call
// to perform an output `request` which will lead to obtain an output `response`.
service service {
rpc subscribe(request) returns (stream response);
rpc outputs(request) returns (stream response);
}
// The `request` message is the logical representation of the request model.
// It is the input of the `subscribe` service.
// It is the input of the `outputs` service.
// It is used to configure the kind of subscription to the gRPC streaming server.
message request {
bool keepalive = 1;

View File

@@ -744,7 +744,7 @@
- macro: ms_oms_writing_conf
condition: >
((proc.name in (omiagent,omsagent,in_heartbeat_r*,omsadmin.sh,PerformInventor)
((proc.name in (omiagent,omsagent,in_heartbeat_r*,omsadmin.sh,PerformInventor,dsc_host)
or proc.pname in (ms_oms_binaries)
or proc.aname[2] in (ms_oms_binaries))
and (fd.name startswith /etc/opt/omi or fd.name startswith /etc/opt/microsoft/omsagent))
@@ -1156,6 +1156,16 @@
- macro: automount_using_mtab
condition: (proc.pname = automount and fd.name startswith /etc/mtab)
- macro: mcafee_writing_cma_d
condition: (proc.name=macompatsvc and fd.directory=/etc/cma.d)
- macro: avinetworks_supervisor_writing_ssh
condition: >
(proc.cmdline="se_supervisor.p /opt/avi/scripts/se_supervisor.py -d" and
(fd.name startswith /etc/ssh/known_host_ or
fd.name startswith /etc/ssh/ssh_monitor_config_ or
fd.name startswith /etc/ssh/ssh_config_))
# Add conditions to this macro (probably in a separate file,
# overwriting this macro) to allow for specific combinations of
# programs writing below specific directories below
@@ -1190,6 +1200,7 @@
qualys-cloud-ag, locales.postins, nomachine_binaries,
adclient, certutil, crlutil, pam-auth-update, parallels_insta,
openshift-launc, update-rc.d, puppet)
and not (container and proc.cmdline in ("cp /run/secrets/kubernetes.io/serviceaccount/ca.crt /etc/pki/ca-trust/source/anchors/openshift-ca.crt"))
and not proc.pname in (sysdigcloud_binaries, mail_config_binaries, hddtemp.postins, sshkit_script_binaries, locales.postins, deb_binaries, dhcp_binaries)
and not fd.name pmatch (safe_etc_dirs)
and not fd.name in (/etc/container_environment.sh, /etc/container_environment.json, /etc/motd, /etc/motd.svc)
@@ -1273,6 +1284,8 @@
and not etcd_manager_updating_dns
and not user_known_write_below_etc_activities
and not automount_using_mtab
and not mcafee_writing_cma_d
and not avinetworks_supervisor_writing_ssh
- rule: Write below etc
desc: an attempt to write to any file below /etc
@@ -1340,6 +1353,9 @@
- macro: user_known_write_below_root_activities
condition: (never_true)
- macro: runc_writing_exec_fifo
condition: (proc.cmdline="runc:[1:CHILD] init" and fd.name=/exec.fifo)
- rule: Write below root
desc: an attempt to write to any file directly below / or /root
condition: >
@@ -1359,6 +1375,7 @@
and not galley_writing_state
and not calico_writing_state
and not rancher_writing_root
and not runc_writing_exec_fifo
and not known_root_conditions
and not user_known_write_root_conditions
and not user_known_write_below_root_activities
@@ -1529,7 +1546,7 @@
condition: >
evt.type = setns
and not proc.name in (docker_binaries, k8s_binaries, lxd_binaries, sysdigcloud_binaries,
sysdig, nsenter, calico, oci-umount, network_plugin_binaries)
sysdig, nsenter, calico, oci-umount, cilium-cni, network_plugin_binaries)
and not proc.name in (user_known_change_thread_namespace_binaries)
and not proc.name startswith "runc"
and not proc.cmdline startswith "containerd"
@@ -1668,7 +1685,8 @@
mesos_shell_binaries,
erl_child_setup, exechealthz,
PM2, PassengerWatchd, c_rehash, svlogd, logrotate, hhvm, serf,
lb-controller, nvidia-installe, runsv, statsite, erlexec)
lb-controller, nvidia-installe, runsv, statsite, erlexec, calico-node,
"puma reactor")
and not proc.cmdline in (known_shell_spawn_cmdlines)
and not proc.aname in (unicorn_launche)
and not consul_running_net_scripts

View File

@@ -13,7 +13,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "webserver.h"
#include <catch.hpp>
@@ -22,7 +21,7 @@ TEST_CASE("webserver must accept invalid data", "[!hide][webserver][k8s_audit_ha
// falco_engine* engine = new falco_engine();
// falco_outputs* outputs = new falco_outputs(engine);
// std::string errstr;
// std::string input("{\"kind\": 0}");
// std::string input("{\"kind\": 0}");
//k8s_audit_handler::accept_data(engine, outputs, input, errstr);
REQUIRE(1 == 1);

25
userspace/engine/banned.h Normal file
View File

@@ -0,0 +1,25 @@
/*
Copyright (C) 2019 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#pragma once
// BAN macro defines `function` as an invalid token that says using
// the function is banned. This throws a compile time error when the
// function is used.
#define BAN(function) using_##function##_is_banned
#undef strcpy
#define strcpy(a, b) BAN(strcpy)

View File

@@ -18,6 +18,7 @@ limitations under the License.
#include "config_falco_engine.h"
#include "falco_common.h"
#include "banned.h"
std::vector<std::string> falco_common::priority_names = {
"Emergency",
@@ -117,4 +118,3 @@ void falco_common::add_lua_path(string &path)
lua_pop(m_ls, 1);
}

View File

@@ -32,6 +32,7 @@ extern "C" {
}
#include "utils.h"
#include "banned.h"
string lua_on_event = "on_event";

View File

@@ -18,6 +18,7 @@ limitations under the License.
*/
#include "falco_utils.h"
#include "banned.h"
namespace falco
{

View File

@@ -18,6 +18,7 @@ limitations under the License.
#include "formats.h"
#include "falco_engine.h"
#include "banned.h"
sinsp* falco_formats::s_inspector = NULL;
@@ -145,11 +146,13 @@ int falco_formats::format_event (lua_State *ls)
if(strcmp(source, "syscall") == 0)
{
try {
// This is "output"
s_formatters->tostring((sinsp_evt *) evt, sformat, &line);
if(s_json_output)
{
switch(s_inspector->get_buffer_format())
sinsp_evt::param_fmt cur_fmt = s_inspector->get_buffer_format();
switch(cur_fmt)
{
case sinsp_evt::PF_NORMAL:
s_inspector->set_buffer_format(sinsp_evt::PF_JSON);
@@ -170,6 +173,7 @@ int falco_formats::format_event (lua_State *ls)
// do nothing
break;
}
// This is output fields
s_formatters->tostring((sinsp_evt *) evt, sformat, &json_line);
// The formatted string might have a leading newline. If it does, remove it.
@@ -177,8 +181,7 @@ int falco_formats::format_event (lua_State *ls)
{
json_line.erase(0, 1);
}
s_inspector->set_buffer_format(sinsp_evt::PF_NORMAL);
s_inspector->set_buffer_format(cur_fmt);
}
}
catch (sinsp_exception& e)

View File

@@ -21,6 +21,7 @@ limitations under the License.
#include "falco_common.h"
#include "json_evt.h"
#include "banned.h"
using json = nlohmann::json;
using namespace std;
@@ -511,31 +512,27 @@ const json_event_filter_check::values_t &json_event_filter_check::extracted_valu
bool json_event_filter_check::compare(gen_event *evt)
{
json_event *jevt = (json_event *)evt;
auto jevt = (json_event *)evt;
uint32_t len;
const extracted_values_t *evalues = (const extracted_values_t *) extract(jevt, &len);
auto evalues = (const extracted_values_t *) extract(jevt, &len);
values_set_t setvals;
switch(m_cmpop)
{
case CO_EQ:
return evalues->second == m_values;
break;
case CO_NE:
return evalues->second != m_values;
break;
case CO_STARTSWITH:
return (evalues->first.size() == 1 &&
m_values.size() == 1 &&
evalues->first.at(0).startswith(*(m_values.begin())));
break;
case CO_CONTAINS:
return (evalues->first.size() == 1 &&
m_values.size() == 1 &&
evalues->first.at(0).contains(*(m_values.begin())));
break;
case CO_IN:
for(auto &item : evalues->second)
{
@@ -545,7 +542,6 @@ bool json_event_filter_check::compare(gen_event *evt)
}
}
return true;
break;
case CO_PMATCH:
for(auto &item : evalues->second)
{
@@ -558,19 +554,16 @@ bool json_event_filter_check::compare(gen_event *evt)
}
}
return true;
break;
case CO_INTERSECTS:
std::set_intersection(evalues->second.begin(), evalues->second.end(),
m_values.begin(), m_values.end(),
std::inserter(setvals, setvals.begin()));
return (setvals.size() > 0);
break;
return (!setvals.empty());
case CO_LT:
return (evalues->first.size() == 1 &&
m_values.size() == 1 &&
evalues->first.at(0).ptype() == m_values.begin()->ptype() &&
evalues->first.at(0) < *(m_values.begin()));
break;
case CO_LE:
return (evalues->first.size() == 1 &&
m_values.size() == 1 &&
@@ -588,11 +581,9 @@ bool json_event_filter_check::compare(gen_event *evt)
evalues->first.at(0).ptype() == m_values.begin()->ptype() &&
(evalues->first.at(0) > *(m_values.begin()) ||
evalues->first.at(0) == *(m_values.begin())));
break;
case CO_EXISTS:
return (evalues->first.size() == 1 &&
(evalues->first.at(0) != json_event_filter_check::no_value));
break;
default:
throw falco_exception("filter error: unsupported comparison operator");
}

View File

@@ -193,7 +193,6 @@ public:
const values_t &extracted_values();
protected:
// Subclasses can override this method, calling
// add_extracted_value to add extracted values.
virtual bool extract_values(json_event *jevt);
@@ -282,7 +281,8 @@ private:
// If true, this filtercheck works on paths, which enables
// some extra bookkeeping to allow for path prefix searches.
bool m_uses_paths;
bool m_uses_paths = false;
path_prefix_search m_prefix_search;
};
@@ -292,7 +292,7 @@ public:
jevt_filter_check();
virtual ~jevt_filter_check();
int32_t parse_field_name(const char* str, bool alloc_state, bool needed_for_filtering) final;
int32_t parse_field_name(const char* str, bool alloc_state, bool needed_for_filtering) final;
json_event_filter_check *allocate_new();

View File

@@ -24,6 +24,8 @@ extern "C" {
}
#include "falco_engine.h"
#include "banned.h"
const static struct luaL_reg ll_falco_rules [] =
{
{"clear_filters", &falco_rules::clear_filters},
@@ -480,4 +482,3 @@ falco_rules::~falco_rules()
delete m_sinsp_lua_parser;
delete m_json_lua_parser;
}

View File

@@ -15,6 +15,7 @@ limitations under the License.
*/
#include "ruleset.h"
#include "banned.h"
using namespace std;

View File

@@ -20,6 +20,7 @@ limitations under the License.
#include "token_bucket.h"
#include "utils.h"
#include "banned.h"
token_bucket::token_bucket():
token_bucket(sinsp_utils::get_current_time_ns)

View File

@@ -15,16 +15,47 @@ configure_file("${SYSDIG_SOURCE_DIR}/userspace/sysdig/config_sysdig.h.in" config
add_custom_command(
OUTPUT
${CMAKE_CURRENT_BINARY_DIR}/output.grpc.pb.cc ${CMAKE_CURRENT_BINARY_DIR}/output.grpc.pb.h
${CMAKE_CURRENT_BINARY_DIR}/output.pb.cc ${CMAKE_CURRENT_BINARY_DIR}/output.pb.h
${CMAKE_CURRENT_BINARY_DIR}/schema.pb.cc ${CMAKE_CURRENT_BINARY_DIR}/schema.pb.h
COMMENT "Generate gRPC code"
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/output.proto
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --cpp_out=. ${CMAKE_CURRENT_SOURCE_DIR}/output.proto
${CMAKE_CURRENT_BINARY_DIR}/version.grpc.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/version.grpc.pb.h
${CMAKE_CURRENT_BINARY_DIR}/version.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/version.pb.h
${CMAKE_CURRENT_BINARY_DIR}/outputs.grpc.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/outputs.grpc.pb.h
${CMAKE_CURRENT_BINARY_DIR}/outputs.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/outputs.pb.h
${CMAKE_CURRENT_BINARY_DIR}/inputs.grpc.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/inputs.grpc.pb.h
${CMAKE_CURRENT_BINARY_DIR}/inputs.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/inputs.pb.h
${CMAKE_CURRENT_BINARY_DIR}/event.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/event.pb.h
${CMAKE_CURRENT_BINARY_DIR}/schema.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/schema.pb.h
${CMAKE_CURRENT_BINARY_DIR}/grpc.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/grpc.pb.h
COMMENT "Generate gRPC API"
# version API
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/version.proto
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --cpp_out=. ${CMAKE_CURRENT_SOURCE_DIR}/version.proto
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --grpc_out=. --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN}
${CMAKE_CURRENT_SOURCE_DIR}/version.proto
# outputs API
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/outputs.proto ${CMAKE_CURRENT_SOURCE_DIR}/schema.proto
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --cpp_out=. ${CMAKE_CURRENT_SOURCE_DIR}/outputs.proto
${CMAKE_CURRENT_SOURCE_DIR}/schema.proto
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --grpc_out=. --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN}
${CMAKE_CURRENT_SOURCE_DIR}/output.proto
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
${CMAKE_CURRENT_SOURCE_DIR}/outputs.proto
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
# inputs API
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/inputs.proto ${CMAKE_CURRENT_SOURCE_DIR}/event.proto
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --cpp_out=. ${CMAKE_CURRENT_SOURCE_DIR}/inputs.proto
${CMAKE_CURRENT_SOURCE_DIR}/event.proto
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --grpc_out=. --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN}
${CMAKE_CURRENT_SOURCE_DIR}/inputs.proto
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
# context API
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/grpc.proto
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --cpp_out=. ${CMAKE_CURRENT_SOURCE_DIR}/grpc.proto)
add_executable(
falco
@@ -38,16 +69,23 @@ add_executable(
webserver.cpp
grpc_context.cpp
grpc_server_impl.cpp
grpc_request_context.cpp
grpc_server.cpp
utils.cpp
${CMAKE_CURRENT_BINARY_DIR}/output.grpc.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/output.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/schema.pb.cc)
${CMAKE_CURRENT_BINARY_DIR}/version.grpc.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/version.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/outputs.grpc.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/outputs.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/inputs.grpc.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/inputs.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/schema.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/event.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/grpc.pb.cc)
add_dependencies(falco civetweb)
if(USE_BUNDLED_DEPS)
add_dependencies(falco yamlcpp)
add_dependencies(falco yamlcpp)
endif()
target_include_directories(

View File

@@ -16,7 +16,14 @@ limitations under the License.
#pragma once
#define FALCO_BRANCH "@FALCO_REF@"
#define FALCO_HASH "@FALCO_HASH@"
#define FALCO_VERSION "@FALCO_VERSION@"
#define FALCO_VERSION_MAJOR @FALCO_VERSION_MAJOR@
#define FALCO_VERSION_MINOR @FALCO_VERSION_MINOR@
#define FALCO_VERSION_PATCH @FALCO_VERSION_PATCH@
#define FALCO_VERSION_PRERELEASE "@FALCO_VERSION_PRERELEASE@"
#define FALCO_VERSION_BUILD "@FALCO_VERSION_BUILD@"
#define FALCO_LUA_DIR "${CMAKE_INSTALL_PREFIX}/${FALCO_SHARE_DIR}/lua/"
#define FALCO_SOURCE_DIR "${PROJECT_SOURCE_DIR}"

View File

@@ -23,6 +23,7 @@ limitations under the License.
#include "configuration.h"
#include "logger.h"
#include "banned.h"
using namespace std;
@@ -87,7 +88,7 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
filename = m_config->get_scalar<string>("file_output", "filename", "");
if(filename == string(""))
{
throw invalid_argument("Error reading config file (" + m_config_file + "): file output enabled but no filename in configuration block");
throw logic_error("Error reading config file (" + m_config_file + "): file output enabled but no filename in configuration block");
}
file_output.options["filename"] = filename;
@@ -119,7 +120,7 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
program = m_config->get_scalar<string>("program_output", "program", "");
if(program == string(""))
{
throw sinsp_exception("Error reading config file (" + m_config_file + "): program output enabled but no program in configuration block");
throw logic_error("Error reading config file (" + m_config_file + "): program output enabled but no program in configuration block");
}
program_output.options["program"] = program;
@@ -138,7 +139,7 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
if(url == string(""))
{
throw sinsp_exception("Error reading config file (" + m_config_file + "): http output enabled but no url in configuration block");
throw logic_error("Error reading config file (" + m_config_file + "): http output enabled but no url in configuration block");
}
http_output.options["url"] = url;
@@ -148,6 +149,10 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
m_grpc_enabled = m_config->get_scalar<bool>("grpc", "enabled", false);
m_grpc_bind_address = m_config->get_scalar<string>("grpc", "bind_address", "0.0.0.0:5060");
m_grpc_threadiness = m_config->get_scalar<uint32_t>("grpc", "threadiness", 8); // todo > limit it to avoid overshubscription? std::thread::hardware_concurrency()
if(m_grpc_threadiness == 0)
{
throw logic_error("error reading config file (" + m_config_file +"): gRPC threadiness must be greater than 0");
}
m_grpc_private_key = m_config->get_scalar<string>("grpc", "private_key", "/etc/falco/certs/server.key");
m_grpc_cert_chain = m_config->get_scalar<string>("grpc", "cert_chain", "/etc/falco/certs/server.crt");
m_grpc_root_certs = m_config->get_scalar<string>("grpc", "root_certs", "/etc/falco/certs/ca.crt");
@@ -162,12 +167,12 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
if(m_outputs.size() == 0)
{
throw invalid_argument("Error reading config file (" + m_config_file + "): No outputs configured. Please configure at least one output file output enabled but no filename in configuration block");
throw logic_error("Error reading config file (" + m_config_file + "): No outputs configured. Please configure at least one output file output enabled but no filename in configuration block");
}
string log_level = m_config->get_scalar<string>("log_level", "info");
m_log_level = m_config->get_scalar<string>("log_level", "info");
falco_logger::set_level(log_level);
falco_logger::set_level(m_log_level);
m_notifications_rate = m_config->get_scalar<uint32_t>("outputs", "rate", 1);
m_notifications_max_burst = m_config->get_scalar<uint32_t>("outputs", "max_burst", 1000);
@@ -181,7 +186,7 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
if((it = std::find_if(falco_common::priority_names.begin(), falco_common::priority_names.end(), comp)) == falco_common::priority_names.end())
{
throw invalid_argument("Unknown priority \"" + priority + "\"--must be one of emergency, alert, critical, error, warning, notice, informational, debug");
throw logic_error("Unknown priority \"" + priority + "\"--must be one of emergency, alert, critical, error, warning, notice, informational, debug");
}
m_min_priority = (falco_common::priority_type)(it - falco_common::priority_names.begin());
@@ -220,7 +225,7 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
}
else
{
throw invalid_argument("Error reading config file (" + m_config_file + "): syscall event drop action " + act + " must be one of \"ignore\", \"log\", \"alert\", or \"exit\"");
throw logic_error("Error reading config file (" + m_config_file + "): syscall event drop action " + act + " must be one of \"ignore\", \"log\", \"alert\", or \"exit\"");
}
}
@@ -328,7 +333,7 @@ void falco_configuration::set_cmdline_option(const string &opt)
if(!split(opt, '=', keyval))
{
throw invalid_argument("Error parsing config option \"" + opt + "\". Must be of the form key=val or key.subkey=val");
throw logic_error("Error parsing config option \"" + opt + "\". Must be of the form key=val or key.subkey=val");
}
if(split(keyval.first, '.', subkey))

View File

@@ -195,6 +195,7 @@ public:
std::list<std::string> m_rules_filenames;
bool m_json_output;
bool m_json_include_output_property;
std::string m_log_level;
std::vector<falco_outputs::output_config> m_outputs;
uint32_t m_notifications_rate;
uint32_t m_notifications_max_burst;

159
userspace/falco/event.proto Normal file
View File

@@ -0,0 +1,159 @@
syntax = "proto3";
import "google/protobuf/timestamp.proto";
package falco.event;
// note > from ppm_events_public.h
// (ppm_param_type)
enum param_type {
PT_NONE = 0;
PT_INT8 = 1;
PT_INT16 = 2;
PT_INT32 = 3;
PT_INT64 = 4;
PT_UINT8 = 5;
PT_UINT16 = 6;
PT_UINT32 = 7;
PT_UINT64 = 8;
PT_CHARBUF = 9; // A printable buffer of bytes, NULL terminated
PT_BYTEBUF = 10; // A raw buffer of bytes not suitable for printing
PT_ERRNO = 11; // This is an INT4; but will be interpreted as an error code
PT_SOCKADDR = 12; // A sockaddr structure, 1byte family + data
PT_SOCKTUPLE = 13; // A sockaddr tuple,1byte family + 12byte data + 12byte data
PT_FD = 14; // An fd, 64bit
PT_PID = 15; // A pid/tid, 64bit
PT_FDLIST = 16; // A list of fds, 16bit count + count * (64bit fd + 16bit flags)
PT_FSPATH = 17; // A string containing a relative or absolute file system path, null terminated
PT_SYSCALLID = 18; // A 16bit system call ID that can be used as a key for the g_syscall_info_table table
PT_SIGTYPE = 19; // An 8bit signal number
PT_RELTIME = 20; // A relative time. Seconds * 10^9 + nanoseconds, 64bit
PT_ABSTIME = 21; // An absolute time interval. Seconds from epoch * 10^9 + nanoseconds, 64bit
PT_PORT = 22; // A TCP/UDP port, 2 bytes
PT_L4PROTO = 23; // A 1 byte IP protocol type
PT_SOCKFAMILY = 24; // A 1 byte socket family
PT_BOOL = 25; // A boolean value, 4 bytes
PT_IPV4ADDR = 26; // A 4 byte raw IPv4 address
PT_DYN = 27; // Type can vary depending on the context (used for filter fields like evt.rawarg)
PT_FLAGS8 = 28; // This is an UINT8; but will be interpreted as 8 bit flags
PT_FLAGS16 = 29; // This is an UINT6; but will be interpreted as 16 bit flags
PT_FLAGS32 = 30; // This is an UINT2; but will be interpreted as 32 bit flags
PT_UID = 31; // This is an UINT2; MAX_UINT32 will be interpreted as no value
PT_GID = 32; // This is an UINT2; MAX_UINT32 will be interpreted as no value
PT_DOUBLE = 33; // This is a double precision floating point number
PT_SIGSET = 34; // sigset_t (only the lower UINT32 of it)
PT_CHARBUFARRAY = 35; // Pointer to an array of strings exported by the user events decoder, 64bit (internal use only)
PT_CHARBUF_PAIR_ARRAY = 36; // Pointer to an array of string pairs, exported by the user events decoder, 64bit (internal use only)
PT_IPV4NET = 37; // An IPv4 network
PT_IPV6ADDR = 38; // A 16 byte raw IPv6 address
PT_IPV6NET = 39; // An IPv6 network
PT_IPADDR = 40; // Either an IPv4 or IPv6 address; the length indicateswhich one it is
PT_IPNET = 41; // Either an IPv4 or IPv6 network; the length indicates which one it is
PT_MODE = 42; // A 32 bit bitmask to represent file modes
PT_MAX = 43; // Array size
};
// note > ppm_events_public.h
// (ppm_event_flags)
enum event_flags {
EF_NONE = 0;
EF_CREATES_FD = 1; // this event creates an FD (e.g. open)
EF_DESTROYS_FD = 2; // this event destroys an FD (e.g. close)
EF_USES_FD = 4; // this event operates on an FD
EF_READS_FROM_FD = 8; // this event reads data from an FD
EF_WRITES_TO_FD = 16; // this event writes data to an FD
EF_MODIFIES_STATE = 32; // this event causes the machine state to change and should not be dropped by the filtering engine
EF_UNUSED = 64; // this event is not used
EF_WAITS = 128; // this event reads data from an FD
EF_SKIPPARSERESET = 256; // this event shouldn't pollute the parser lastevent state tracker
EF_OLD_VERSION = 512; // this event is kept for backward compatibility
EF_DROP_SIMPLE_CONS = 1024; // this event can be skipped by consumers that privilege low overhead to full event capture
}
// todo(leodido) > complete
// https://github.com/draios/sysdig/blob/master/driver/ppm_events_public.h
// (ppm_event_type)
enum event_type {
PPME_GENERIC_E = 0;
PPME_GENERIC_X = 1;
}
// todo(leodido) > complete
// https://github.com/draios/sysdig/blob/master/driver/ppm_events_public.h
// (ppm_event_category)
enum event_category {
EC_UNKNOWN = 0;
EC_OTHER = 1;
EC_FILE = 2;
}
message parameter {
string name = 1;
uint32 value = 2;
}
message parameter_info {
string name = 1; // parameter name, e.g. 'size'
param_type type = 2; // parameter type, e.g. 'uint16', 'string'
// print_format fmt = 3;
// ? info = 4;
}
message ppm_event {
string name = 1;
event_category category = 2; // event category, e.g. 'file, 'net'
uint32 flags = 3;
uint32 nparams = 4; // number of parameters in the parameters array
repeated parameter_info params = 5;
}
message scap_event {
google.protobuf.Timestamp ts = 1;
uint64 tid = 2;
event_type type = 3;
uint32 nparams = 4;
}
enum command_category {
CAT_NONE = 0;
CAT_CONTAINER = 1;
CAT_HEALTHCHECK = 2;
CAT_LIVENESS_PROBE = 3;
CAT_READINESS_PROBE = 4;
}
// note > threadinfo.h
message thread_info {
uint64 tid = 1; // id of this thread
uint64 pid = 2; // id of the process containing this thread
uint64 ptid = 3; // id of the process that started this thread
uint64 sid = 4; // session id of the process containing this thread
string comm = 5; // name of the process containing this thread, e.g. "top"
string exe = 6; // name of the process containing this thread from argv[0], e.g. "/bin/top"
string exepath = 7; // full executable path of the process containing this thread, e.g. "/bin/top"
string cwd = 8; // working directory of the process containing this thread
repeated string env = 9; // values of all environment variables for the process containing this thread
repeated string args = 10; // command line arguments, e.g., -d1
// string container_id = 11;
// ...
command_category category = 12;
}
// note > event.h
message event {
scap_event evt = 1;
uint32 cpuid = 2;
event_flags flags = 3; // fixme(leodido) > should this be a uint32?
ppm_event info = 4;
string params = 5;
thread_info tinfo = 6;
// fdinfo = 7
uint32 iosize = 8;
// bool fdinfo_name_changed = 9;
// int64 fd_num = 10;
// uint32 num_params = 11;
// map<uint32, string> param_name = 12;
// map<uint32, string> param_value = 13;
}

View File

@@ -15,6 +15,7 @@ limitations under the License.
*/
#include "event_drops.h"
#include "banned.h"
syscall_evt_drop_mgr::syscall_evt_drop_mgr():
m_num_syscall_evt_drops(0),
@@ -75,7 +76,7 @@ bool syscall_evt_drop_mgr::process_event(sinsp *inspector, sinsp_evt *evt)
if(m_simulate_drops)
{
falco_logger::log(LOG_INFO, "Simulating syscall event drop");
falco_logger::log(LOG_INFO, "Simulating syscall event drop\n");
delta.n_drops++;
}
@@ -93,7 +94,7 @@ bool syscall_evt_drop_mgr::process_event(sinsp *inspector, sinsp_evt *evt)
}
else
{
falco_logger::log(LOG_DEBUG, "Syscall event drop but token bucket depleted, skipping actions");
falco_logger::log(LOG_DEBUG, "Syscall event drop but token bucket depleted, skipping actions\n");
}
}
}
@@ -155,7 +156,7 @@ bool syscall_evt_drop_mgr::perform_actions(uint64_t now, scap_stats &delta, bool
if(should_exit)
{
falco_logger::log(LOG_CRIT, msg);
falco_logger::log(LOG_CRIT, "Exiting.");
falco_logger::log(LOG_CRIT, "Exiting.\n");
return false;
}

View File

@@ -45,6 +45,7 @@ limitations under the License.
#include "statsfilewriter.h"
#include "webserver.h"
#include "grpc_server.h"
#include "banned.h"
typedef function<void(sinsp* inspector)> open_t;
@@ -895,7 +896,7 @@ int falco_init(int argc, char **argv)
printf("%s\n", support.dump().c_str());
goto exit;
}
// read hostname
string hostname;
if(char* env_hostname = getenv("FALCO_GRPC_HOSTNAME"))
@@ -1191,7 +1192,7 @@ int falco_init(int argc, char **argv)
{
// TODO(fntlnz,leodido): when we want to spawn multiple threads we need to have a queue per thread, or implement
// different queuing mechanisms, round robin, fanout? What we want to achieve?
grpc_server.init(config.m_grpc_bind_address, config.m_grpc_threadiness, config.m_grpc_private_key, config.m_grpc_cert_chain, config.m_grpc_root_certs);
grpc_server.init(config.m_grpc_bind_address, config.m_grpc_private_key, config.m_grpc_cert_chain, config.m_grpc_root_certs, config.m_grpc_threadiness, config.m_log_level);
grpc_server_thread = std::thread([&grpc_server] {
grpc_server.run();
});

View File

@@ -16,12 +16,12 @@ limitations under the License.
#pragma once
#include "output.pb.h"
#include "outputs.pb.h"
#include "tbb/concurrent_queue.h"
namespace falco
{
namespace output
namespace outputs
{
typedef tbb::concurrent_queue<response> response_cq;

View File

@@ -23,26 +23,25 @@ limitations under the License.
#include "formats.h"
#include "logger.h"
#include "falco_output_queue.h"
#include "banned.h"
using namespace std;
using namespace falco::output;
const static struct luaL_reg ll_falco_outputs [] =
const static struct luaL_reg ll_falco_outputs[] =
{
{"handle_http", &falco_outputs::handle_http},
{"handle_grpc", &falco_outputs::handle_grpc},
{NULL,NULL}
{NULL, NULL}
};
falco_outputs::falco_outputs(falco_engine *engine)
: m_falco_engine(engine),
m_initialized(false),
m_buffered(true),
m_json_output(false),
m_time_format_iso_8601(false),
m_hostname("")
falco_outputs::falco_outputs(falco_engine *engine):
m_falco_engine(engine),
m_initialized(false),
m_buffered(true),
m_json_output(false),
m_time_format_iso_8601(false),
m_hostname("")
{
}
falco_outputs::~falco_outputs()
@@ -57,13 +56,13 @@ falco_outputs::~falco_outputs()
lua_getglobal(m_ls, m_lua_output_cleanup.c_str());
if(!lua_isfunction(m_ls, -1))
{
falco_logger::log(LOG_ERR, std::string("No function ") + m_lua_output_cleanup + " found. ");
falco_logger::log(LOG_ERR, std::string("No function ") + m_lua_output_cleanup + " found.\n");
assert(nullptr == "Missing lua cleanup function in ~falco_outputs");
}
if(lua_pcall(m_ls, 0, 0, 0) != 0)
{
const char* lerr = lua_tostring(m_ls, -1);
const char *lerr = lua_tostring(m_ls, -1);
falco_logger::log(LOG_ERR, std::string("lua_pcall failed, err: ") + lerr);
assert(nullptr == "lua_pcall failed in ~falco_outputs");
}
@@ -76,7 +75,7 @@ void falco_outputs::init(bool json_output,
bool time_format_iso_8601, string hostname)
{
// The engine must have been given an inspector by now.
if(! m_inspector)
if(!m_inspector)
{
throw falco_exception("No inspector provided");
}
@@ -117,12 +116,12 @@ void falco_outputs::add_output(output_config oc)
lua_pushnumber(m_ls, (m_time_format_iso_8601 ? 1 : 0));
// If we have options, build up a lua table containing them
if (oc.options.size())
if(oc.options.size())
{
nargs = 4;
lua_createtable(m_ls, 0, oc.options.size());
for (auto it = oc.options.cbegin(); it != oc.options.cend(); ++it)
for(auto it = oc.options.cbegin(); it != oc.options.cend(); ++it)
{
lua_pushstring(m_ls, (*it).second.c_str());
lua_setfield(m_ls, -2, (*it).first.c_str());
@@ -131,10 +130,9 @@ void falco_outputs::add_output(output_config oc)
if(lua_pcall(m_ls, nargs, 0, 0) != 0)
{
const char* lerr = lua_tostring(m_ls, -1);
const char *lerr = lua_tostring(m_ls, -1);
throw falco_exception(string(lerr));
}
}
void falco_outputs::handle_event(gen_event *ev, string &rule, string &source,
@@ -161,7 +159,7 @@ void falco_outputs::handle_event(gen_event *ev, string &rule, string &source,
if(lua_pcall(m_ls, 7, 0, 0) != 0)
{
const char* lerr = lua_tostring(m_ls, -1);
const char *lerr = lua_tostring(m_ls, -1);
string err = "Error invoking function output: " + string(lerr);
throw falco_exception(err);
}
@@ -176,7 +174,7 @@ void falco_outputs::handle_msg(uint64_t now,
falco_common::priority_type priority,
std::string &msg,
std::string &rule,
std::map<std::string,std::string> &output_fields)
std::map<std::string, std::string> &output_fields)
{
std::string full_msg;
@@ -185,9 +183,9 @@ void falco_outputs::handle_msg(uint64_t now,
nlohmann::json jmsg;
// Convert the time-as-nanoseconds to a more json-friendly ISO8601.
time_t evttime = now/1000000000;
time_t evttime = now / 1000000000;
char time_sec[20]; // sizeof "YYYY-MM-DDTHH:MM:SS"
char time_ns[12]; // sizeof ".sssssssssZ"
char time_ns[12]; // sizeof ".sssssssssZ"
string iso8601evttime;
strftime(time_sec, sizeof(time_sec), "%FT%T", gmtime(&evttime));
@@ -235,7 +233,7 @@ void falco_outputs::handle_msg(uint64_t now,
if(lua_pcall(m_ls, 3, 0, 0) != 0)
{
const char* lerr = lua_tostring(m_ls, -1);
const char *lerr = lua_tostring(m_ls, -1);
string err = "Error invoking function output: " + string(lerr);
throw falco_exception(err);
}
@@ -244,7 +242,6 @@ void falco_outputs::handle_msg(uint64_t now,
{
throw falco_exception("No function " + m_lua_output_msg + " found in lua compiler module");
}
}
void falco_outputs::reopen_outputs()
@@ -257,7 +254,7 @@ void falco_outputs::reopen_outputs()
if(lua_pcall(m_ls, 0, 0, 0) != 0)
{
const char* lerr = lua_tostring(m_ls, -1);
const char *lerr = lua_tostring(m_ls, -1);
throw falco_exception(string(lerr));
}
}
@@ -276,8 +273,8 @@ int falco_outputs::handle_http(lua_State *ls)
lua_error(ls);
}
string url = (char *) lua_tostring(ls, 1);
string msg = (char *) lua_tostring(ls, 2);
string url = (char *)lua_tostring(ls, 1);
string msg = (char *)lua_tostring(ls, 2);
curl = curl_easy_init();
if(curl)
@@ -290,8 +287,9 @@ int falco_outputs::handle_http(lua_State *ls)
res = curl_easy_perform(curl);
if(res != CURLE_OK) {
falco_logger::log(LOG_ERR,"libcurl error: " + string(curl_easy_strerror(res)));
if(res != CURLE_OK)
{
falco_logger::log(LOG_ERR, "libcurl error: " + string(curl_easy_strerror(res)));
}
curl_easy_cleanup(curl);
curl = NULL;
@@ -317,15 +315,16 @@ int falco_outputs::handle_grpc(lua_State *ls)
lua_error(ls);
}
response grpc_res = response();
falco::outputs::response grpc_res = falco::outputs::response();
// time
gen_event* evt = (gen_event*)lua_topointer(ls, 1);
auto& timestamp = *grpc_res.mutable_time();
timestamp = google::protobuf::util::TimeUtil::NanosecondsToTimestamp(evt->get_ts());
gen_event *evt = (gen_event *)lua_topointer(ls, 1);
auto timestamp = grpc_res.mutable_time();
*timestamp = google::protobuf::util::TimeUtil::NanosecondsToTimestamp(evt->get_ts());
// rule
grpc_res.set_rule((char *)lua_tostring(ls, 2));
auto rule = grpc_res.mutable_rule();
*rule = (char *)lua_tostring(ls, 2);
// source
falco::schema::source s = falco::schema::source::SYSCALL;
@@ -348,22 +347,25 @@ int falco_outputs::handle_grpc(lua_State *ls)
grpc_res.set_priority(p);
// output
grpc_res.set_output((char *)lua_tostring(ls, 5));
auto output = grpc_res.mutable_output();
*output = (char *)lua_tostring(ls, 5);
// output fields
auto& fields = *grpc_res.mutable_output_fields();
auto &fields = *grpc_res.mutable_output_fields();
lua_pushnil(ls); // so that lua_next removes it from stack and puts (k, v) on it
while (lua_next(ls, 6) != 0) {
while(lua_next(ls, 6) != 0)
{
fields[lua_tostring(ls, -2)] = lua_tostring(ls, -1);
lua_pop(ls, 1); // remove value, keep key for lua_next
}
lua_pop(ls, 1); // pop table
// hostname
grpc_res.set_hostname((char* )lua_tostring(ls, 7));
auto host = grpc_res.mutable_hostname();
*host = (char *)lua_tostring(ls, 7);
falco::output::queue::get().push(grpc_res);
falco::outputs::queue::get().push(grpc_res);
return 1;
}

View File

@@ -0,0 +1,16 @@
syntax = "proto3";
package falco.grpc;
enum stream_status {
STREAMING = 0;
SUCCESS = 1;
ERROR = 2;
}
enum request_state {
UNKNOWN = 0;
REQUEST = 1;
WRITE = 2;
FINISH = 3;
}

View File

@@ -17,36 +17,34 @@ limitations under the License.
#include <sstream>
#include "grpc_context.h"
#include "banned.h"
falco::grpc::context::context(::grpc::ServerContext* ctx):
m_ctx(ctx)
{
std::string session_id;
std::string request_id;
get_metadata(meta_session, m_session_id);
get_metadata(meta_request, m_request_id);
get_metadata(meta_session, session_id);
get_metadata(meta_request, request_id);
bool has_meta = false;
std::stringstream meta;
if(!session_id.empty())
if(!m_session_id.empty())
{
meta << "[sid=" << session_id << "]";
has_meta = true;
ctx->AddInitialMetadata(meta_session, m_session_id);
meta << "sid=" << m_session_id << "";
}
if(!request_id.empty())
if(!m_request_id.empty())
{
meta << "[rid=" << request_id << "]";
has_meta = true;
}
if(has_meta)
{
meta << " ";
ctx->AddInitialMetadata(meta_request, m_request_id);
meta << ", rid=" << m_request_id << "";
}
m_prefix = meta.str();
}
void falco::grpc::context::context::get_metadata(std::string key, std::string& val)
std::string falco::grpc::context::peer() const
{
return m_ctx->peer();
}
void falco::grpc::context::get_metadata(std::string key, std::string& val)
{
const std::multimap<::grpc::string_ref, ::grpc::string_ref>& client_metadata = m_ctx->client_metadata();
auto it = client_metadata.find(key);
@@ -54,4 +52,4 @@ void falco::grpc::context::context::get_metadata(std::string key, std::string& v
{
val.assign(it->second.data(), it->second.size());
}
}
}

View File

@@ -24,6 +24,8 @@ limitations under the License.
#include <grpc++/grpc++.h>
#endif
#include "grpc.pb.h"
namespace falco
{
namespace grpc
@@ -39,10 +41,14 @@ public:
~context() = default;
void get_metadata(std::string key, std::string& val);
std::string peer() const;
std::string m_prefix; // todo(leodido) > making this read only?
private:
std::string m_session_id;
std::string m_request_id;
::grpc::ServerContext* m_ctx = nullptr;
std::string m_prefix;
};
class stream_context : public context
@@ -52,15 +58,11 @@ public:
context(ctx){};
~stream_context() = default;
enum : char
{
STREAMING = 1,
SUCCESS,
ERROR
} m_status = STREAMING;
stream_status m_status = stream_status::STREAMING;
mutable void* m_stream = nullptr; // todo(fntlnz, leodido) > useful in the future
mutable void* m_stream = nullptr; // todo(fntlnz, leodido) > useful in the future (request-specific stream data)
mutable bool m_has_more = false;
};
} // namespace grpc
} // namespace falco

View File

@@ -0,0 +1,251 @@
/*
Copyright (C) 2016-2019 The Falco Authors
This file is part of falco.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "grpc_request_context.h"
namespace falco
{
namespace grpc
{
template<>
void request_stream_context<falco::outputs::service, falco::outputs::request, falco::outputs::response>::start(server* srv)
{
m_state = request_state::REQUEST;
m_srv_ctx.reset(new ::grpc::ServerContext);
auto srvctx = m_srv_ctx.get();
m_res_writer.reset(new ::grpc::ServerAsyncWriter<outputs::response>(srvctx));
m_stream_ctx.reset();
m_req.Clear();
auto cq = srv->m_completion_queue.get();
// m_stream_ctx->m_stream = this; // todo(leodido) > save the tag - ie., this - into the stream?
gpr_log(
GPR_DEBUG,
"request_stream_context<outputs>::%s -> m_request_func: tag=%p, state=%s",
__func__,
this,
request_state_Name(m_state).c_str());
(srv->m_outputs_svc.*m_request_func)(srvctx, &m_req, m_res_writer.get(), cq, cq, this);
}
template<>
void request_stream_context<falco::outputs::service, falco::outputs::request, falco::outputs::response>::process(server* srv)
{
// When it is the 1st process call
if(m_state == request_state::REQUEST)
{
m_state = request_state::WRITE;
m_stream_ctx.reset(new stream_context(m_srv_ctx.get()));
}
// Processing
gpr_log(
GPR_DEBUG,
"request_stream_context<outputs>::%s -> m_process_func: tag=%p, state=%s",
__func__,
this,
request_state_Name(m_state).c_str());
outputs::response res;
(srv->*m_process_func)(*m_stream_ctx, m_req, res); // outputs_impl()
// When there are still more responses to stream
if(m_stream_ctx->m_has_more)
{
gpr_log(
GPR_DEBUG,
"request_stream_context<outputs>::%s -> write: tag=%p, state=%s",
__func__,
this,
request_state_Name(m_state).c_str());
m_res_writer->Write(res, this);
}
// No more responses to stream
else
{
// Communicate to the gRPC runtime that we have finished.
// The memory address of "this" instance uniquely identifies the event.
m_state = request_state::FINISH;
gpr_log(
GPR_DEBUG,
"request_stream_context<outputs>::%s -> finish: tag=%p, state=finish",
__func__,
this);
m_res_writer->Finish(::grpc::Status::OK, this);
}
}
template<>
void request_stream_context<falco::outputs::service, falco::outputs::request, falco::outputs::response>::end(server* srv, bool errored)
{
if(m_stream_ctx)
{
if(errored)
{
gpr_log(
GPR_ERROR,
"request_stream_context<outputs>::%s -> error streaming: tag=%p, state=%s, stream=%p",
__func__,
this,
request_state_Name(m_state).c_str(),
m_stream_ctx->m_stream);
}
m_stream_ctx->m_status = errored ? stream_status::ERROR : stream_status::SUCCESS;
// Complete the processing
outputs::response res;
(srv->*m_process_func)(*m_stream_ctx, m_req, res); // outputs()
}
else
{
// Flow enters here when the processing of "m_request_func" fails.
// Since this happens into the `start()` function, the processing does not advance to the `process()` function.
// So, `m_stream_ctx` is null because it is set into the `process()` function.
// The stream haven't started.
gpr_log(
GPR_ERROR,
"%s -> ending streaming: tag=%p, state=%s, stream=never started",
__func__,
this,
request_state_Name(m_state).c_str());
}
// Ask to start processing requests
start(srv);
}
template<>
void falco::grpc::request_context<falco::version::service, falco::version::request, falco::version::response>::start(server* srv)
{
m_state = request_state::REQUEST;
m_srv_ctx.reset(new ::grpc::ServerContext);
auto srvctx = m_srv_ctx.get();
m_res_writer.reset(new ::grpc::ServerAsyncResponseWriter<version::response>(srvctx));
m_req.Clear();
auto cq = srv->m_completion_queue.get();
// Request to start processing given requests.
// Using "this" - ie., the memory address of this context - as the tag that uniquely identifies the request.
// In this way, different contexts can serve different requests concurrently.
gpr_log(
GPR_DEBUG,
"request_context<version>::%s -> m_request_func: tag=%p, state=%s",
__func__,
this,
request_state_Name(m_state).c_str());
(srv->m_version_svc.*m_request_func)(srvctx, &m_req, m_res_writer.get(), cq, cq, this);
}
template<>
void falco::grpc::request_context<falco::version::service, falco::version::request, falco::version::response>::process(server* srv)
{
gpr_log(
GPR_DEBUG,
"request_context<version>::%s -> m_process_func: tag=%p, state=%s",
__func__,
this,
request_state_Name(m_state).c_str());
// Create empty response
version::response res;
// Call version service implementation
(srv->*m_process_func)(m_srv_ctx.get(), m_req, res);
// Notify the gRPC runtime that this processing is done
m_state = request_state::FINISH;
// Using "this"- ie., the memory address of this context - to uniquely identify the event.
m_res_writer->Finish(res, ::grpc::Status::OK, this);
}
template<>
void falco::grpc::request_context<falco::version::service, falco::version::request, falco::version::response>::end(server* srv, bool errored)
{
if(errored)
{
gpr_log(
GPR_ERROR,
"request_context<version>::%s -> error replying: tag=%p, state=%s",
__func__,
this,
request_state_Name(m_state).c_str());
}
// Ask to start processing requests
start(srv);
}
template<>
void falco::grpc::request_context<falco::inputs::service, falco::inputs::request, falco::inputs::response>::start(server* srv)
{
m_state = request_state::REQUEST;
m_srv_ctx.reset(new ::grpc::ServerContext);
auto srvctx = m_srv_ctx.get();
m_res_writer.reset(new ::grpc::ServerAsyncResponseWriter<inputs::response>(srvctx));
m_req.Clear();
auto cq = srv->m_completion_queue.get();
// Request to start processing given requests.
// Using "this" - ie., the memory address of this context - as the tag that uniquely identifies the request.
// In this way, different contexts can serve different requests concurrently.
gpr_log(
GPR_DEBUG,
"request_context<inputs>::%s -> m_request_func: tag=%p, state=%s",
__func__,
this,
request_state_Name(m_state).c_str());
(srv->m_inputs_svc.*m_request_func)(srvctx, &m_req, m_res_writer.get(), cq, cq, this);
}
template<>
void falco::grpc::request_context<falco::inputs::service, falco::inputs::request, falco::inputs::response>::process(server* srv)
{
gpr_log(
GPR_DEBUG,
"request_context<inputs>::%s -> m_process_func: tag=%p, state=%s",
__func__,
this,
request_state_Name(m_state).c_str());
inputs::response res;
(srv->*m_process_func)(m_srv_ctx.get(), m_req, res);
// Notify the gRPC runtime that this processing is done
m_state = request_state::FINISH;
// Using "this"- ie., the memory address of this context - to uniquely identify the event.
m_res_writer->Finish(res, ::grpc::Status::OK, this);
}
template<>
void falco::grpc::request_context<falco::inputs::service, falco::inputs::request, falco::inputs::response>::end(server* srv, bool errored)
{
if(errored)
{
gpr_log(
GPR_ERROR,
"request_context<inputs>::%s -> error replying: tag=%p, state=%s",
__func__,
this,
request_state_Name(m_state).c_str());
}
// Ask to start processing requests
start(srv);
}
} // namespace grpc
} // namespace falco

View File

@@ -0,0 +1,95 @@
/*
Copyright (C) 2016-2019 The Falco Authors
This file is part of falco.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#pragma once
#include "grpc_server.h"
namespace falco
{
namespace grpc
{
class request_context_base
{
public:
request_context_base() = default;
~request_context_base() = default;
std::unique_ptr<::grpc::ServerContext> m_srv_ctx;
request_state m_state = request_state::UNKNOWN;
virtual void start(server* srv) = 0;
virtual void process(server* srv) = 0;
virtual void end(server* srv, bool isError) = 0;
};
// The responsibility of `request_stream_context` template class
// is to handle streaming responses.
template<class Service, class Request, class Response>
class request_stream_context : public request_context_base
{
public:
request_stream_context():
m_process_func(nullptr),
m_request_func(nullptr){};
~request_stream_context() = default;
// Pointer to function that does actual processing
void (server::*m_process_func)(const stream_context&, const Request&, Response&);
// Pointer to function that requests the system to start processing given requests
void (Service::AsyncService::*m_request_func)(::grpc::ServerContext*, Request*, ::grpc::ServerAsyncWriter<Response>*, ::grpc::CompletionQueue*, ::grpc::ServerCompletionQueue*, void*);
void start(server* srv);
void process(server* srv);
void end(server* srv, bool isError);
private:
std::unique_ptr<::grpc::ServerAsyncWriter<Response>> m_res_writer;
std::unique_ptr<stream_context> m_stream_ctx;
Request m_req;
};
// The responsibility of `request_context` template class
// is to handle unary responses.
template<class Service, class Request, class Response>
class request_context : public request_context_base
{
public:
request_context():
m_process_func(nullptr),
m_request_func(nullptr){};
~request_context() = default;
// Pointer to function that does actual processing
void (server::*m_process_func)(const context&, const Request&, Response&);
// Pointer to function that requests the system to start processing given requests
void (Service::AsyncService::*m_request_func)(::grpc::ServerContext*, Request*, ::grpc::ServerAsyncResponseWriter<Response>*, ::grpc::CompletionQueue*, ::grpc::ServerCompletionQueue*, void*);
void start(server* srv);
void process(server* srv);
void end(server* srv, bool isError);
private:
std::unique_ptr<::grpc::ServerAsyncResponseWriter<Response>> m_res_writer;
Request m_req;
};
} // namespace grpc
} // namespace falco

View File

@@ -14,90 +14,37 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
#include <unistd.h>
#ifdef GRPC_INCLUDE_IS_GRPCPP
#include <grpcpp/grpcpp.h>
#else
#include <grpc++/grpc++.h>
#endif
#include "logger.h"
#include "grpc_server.h"
#include "grpc_context.h"
#include "grpc_request_context.h"
#include "utils.h"
#include "banned.h"
#define REGISTER_STREAM(req, res, svc, rpc, impl, num) \
std::vector<request_stream_context<req, res>> rpc##_contexts(num); \
for(request_stream_context<req, res> & ctx : rpc##_contexts) \
{ \
ctx.m_process_func = &server::impl; \
ctx.m_request_func = &svc::AsyncService::Request##rpc; \
ctx.start(this); \
#define REGISTER_STREAM(req, res, svc, rpc, impl, num) \
std::vector<request_stream_context<svc, req, res>> rpc##_contexts(num); \
for(request_stream_context<svc, req, res> & c : rpc##_contexts) \
{ \
c.m_process_func = &server::impl; \
c.m_request_func = &svc::AsyncService::Request##rpc; \
c.start(this); \
}
namespace falco
{
namespace grpc
{
template<>
void request_stream_context<falco::output::request, falco::output::response>::start(server* srv)
{
m_state = request_context_base::REQUEST;
m_srv_ctx.reset(new ::grpc::ServerContext);
auto srvctx = m_srv_ctx.get();
m_res_writer.reset(new ::grpc::ServerAsyncWriter<output::response>(srvctx));
m_stream_ctx.reset();
m_req.Clear();
auto cq = srv->m_completion_queue.get();
(srv->m_svc.*m_request_func)(srvctx, &m_req, m_res_writer.get(), cq, cq, this);
}
template<>
void request_stream_context<falco::output::request, falco::output::response>::process(server* srv)
{
// When it is the 1st process call
if(m_state == request_context_base::REQUEST)
{
m_state = request_context_base::WRITE;
m_stream_ctx.reset(new stream_context(m_srv_ctx.get()));
#define REGISTER_UNARY(req, res, svc, rpc, impl, num) \
std::vector<request_context<svc, req, res>> rpc##_contexts(num); \
for(request_context<svc, req, res> & c : rpc##_contexts) \
{ \
c.m_process_func = &server::impl; \
c.m_request_func = &svc::AsyncService::Request##rpc; \
c.start(this); \
}
// Processing
output::response res;
(srv->*m_process_func)(*m_stream_ctx, m_req, res); // subscribe()
// When there still are more responses to stream
if(m_stream_ctx->m_has_more)
{
m_res_writer->Write(res, this);
}
// No more responses to stream
else
{
// Communicate to the gRPC runtime that we have finished.
// The memory address of `this` instance uniquely identifies the event.
m_state = request_context_base::FINISH;
m_res_writer->Finish(::grpc::Status::OK, this);
}
}
template<>
void request_stream_context<falco::output::request, falco::output::response>::end(server* srv, bool errored)
{
if(m_stream_ctx)
{
m_stream_ctx->m_status = errored ? stream_context::ERROR : stream_context::SUCCESS;
// Complete the processing
output::response res;
(srv->*m_process_func)(*m_stream_ctx, m_req, res); // subscribe()
}
start(srv);
}
} // namespace grpc
} // namespace falco
void falco::grpc::server::thread_process(int thread_index)
{
void* tag = nullptr;
@@ -106,17 +53,35 @@ void falco::grpc::server::thread_process(int thread_index)
{
if(tag == nullptr)
{
gpr_log(
GPR_ERROR,
"server::%s -> server completion queue error: tag=(empty)",
__func__);
continue;
}
// Obtain the context for a given tag
request_context_base* ctx = static_cast<request_context_base*>(tag);
gpr_log(
GPR_DEBUG,
"server::%s -> next event: tag=%p, read success=%s, state=%s",
__func__,
tag,
event_read_success ? "true" : "false",
request_state_Name(ctx->m_state).c_str());
// When event has not been read successfully
if(!event_read_success)
{
if(ctx->m_state != request_context_base::REQUEST)
if(ctx->m_state != request_state::REQUEST)
{
gpr_log(
GPR_ERROR,
"server::%s -> server completion queue failing to read: tag=%p",
__func__,
tag);
// End the context with error
ctx->end(this, true);
}
@@ -126,37 +91,71 @@ void falco::grpc::server::thread_process(int thread_index)
// Process the event
switch(ctx->m_state)
{
case request_context_base::REQUEST:
case request_state::REQUEST:
// Completion of m_request_func
case request_context_base::WRITE:
// Completion of ServerAsyncWriter::Write()
case request_state::WRITE:
// Completion of Write()
ctx->process(this);
break;
case request_context_base::FINISH:
// Completion of ServerAsyncWriter::Finish()
case request_state::FINISH:
// Completion of Finish()
ctx->end(this, false);
break;
default:
// todo > log "unkown completion queue event"
gpr_log(
GPR_ERROR,
"server::%s -> unkown completion queue event: tag=%p, state=%s",
__func__,
tag,
request_state_Name(ctx->m_state).c_str());
break;
}
gpr_log(
GPR_DEBUG,
"server::%s -> thread completed: tag=%p, index=%d",
__func__,
tag,
thread_index);
}
}
void falco::grpc::server::init(std::string server_addr, int threadiness, std::string private_key, std::string cert_chain, std::string root_certs)
void falco::grpc::server::init(std::string server_addr, std::string private_key, std::string cert_chain, std::string root_certs, int threadiness, std::string log_level)
{
m_server_addr = server_addr;
m_threadiness = threadiness;
m_private_key = private_key;
m_cert_chain = cert_chain;
m_root_certs = root_certs;
falco::schema::priority logging_level = falco::schema::INFORMATIONAL;
falco::schema::priority_Parse(log_level, &logging_level);
switch(logging_level)
{
case falco::schema::ERROR:
gpr_set_log_verbosity(GPR_LOG_SEVERITY_ERROR);
break;
case falco::schema::DEBUG:
gpr_set_log_verbosity(GPR_LOG_SEVERITY_DEBUG);
break;
case falco::schema::INFORMATIONAL:
default:
// note > info will always enter here since it is != from "informational"
gpr_set_log_verbosity(GPR_LOG_SEVERITY_INFO);
break;
}
// gpr_set_log_function(custom_log);
gpr_log_verbosity_init();
}
// static void custom_log(gpr_log_func_args* args){};
void falco::grpc::server::run()
{
string private_key;
string cert_chain;
string root_certs;
std::string private_key;
std::string cert_chain;
std::string root_certs;
falco::utils::read(m_cert_chain, cert_chain);
falco::utils::read(m_private_key, private_key);
@@ -170,19 +169,23 @@ void falco::grpc::server::run()
::grpc::ServerBuilder builder;
builder.AddListeningPort(m_server_addr, ::grpc::SslServerCredentials(ssl_opts));
builder.RegisterService(&m_svc);
builder.RegisterService(&m_outputs_svc);
builder.RegisterService(&m_version_svc);
builder.RegisterService(&m_inputs_svc);
m_completion_queue = builder.AddCompletionQueue();
m_server = builder.BuildAndStart();
falco_logger::log(LOG_INFO, "Starting gRPC server at " + m_server_addr + "\n");
gpr_log(GPR_INFO, "gRPC server starting: address=%s", m_server_addr.c_str());
// The number of contexts is multiple of the number of threads
// This defines the number of simultaneous completion queue requests of the same type (service::AsyncService::Request##RPC)
// For this approach to be sufficient server::IMPL have to be fast
int context_num = m_threadiness * 10;
REGISTER_STREAM(output::request, output::response, output::service, subscribe, subscribe, context_num)
// todo(leodido) > take a look at thread_stress_test.cc into grpc repository
// register_stream<output::request, output::response>(subscribe, context_num)
REGISTER_UNARY(version::request, version::response, version::service, version, version_impl, context_num)
REGISTER_UNARY(inputs::request, inputs::response, inputs::service, input, input_impl, context_num)
REGISTER_STREAM(outputs::request, outputs::response, outputs::service, outputs, outputs_impl, context_num)
m_threads.resize(m_threadiness);
int thread_idx = 0;
@@ -190,21 +193,23 @@ void falco::grpc::server::run()
{
thread = std::thread(&server::thread_process, this, thread_idx++);
}
gpr_log(GPR_INFO, "gRPC server running: threadiness=%zu", m_threads.size());
while(server_impl::is_running())
{
sleep(1);
}
gpr_log(GPR_INFO, "gRPC server stopping");
stop();
}
void falco::grpc::server::stop()
{
falco_logger::log(LOG_INFO, "Shutting down gRPC server. Waiting until external connections are closed by clients\n");
gpr_log(GPR_INFO, "gRPC server shutting down");
m_server->Shutdown();
m_completion_queue->Shutdown();
falco_logger::log(LOG_INFO, "Waiting for the gRPC threads to complete\n");
gpr_log(GPR_DEBUG, "gRPC server shutting down: waiting for the gRPC threads to complete");
for(std::thread& t : m_threads)
{
if(t.joinable())
@@ -214,7 +219,7 @@ void falco::grpc::server::stop()
}
m_threads.clear();
falco_logger::log(LOG_INFO, "Ignoring all the remaining gRPC events\n");
gpr_log(GPR_DEBUG, "gRPC server shutting down: draining all the remaining gRPC events");
// Ignore remaining events
void* ignore_tag = nullptr;
bool ignore_ok = false;
@@ -222,5 +227,5 @@ void falco::grpc::server::stop()
{
}
falco_logger::log(LOG_INFO, "Shutting down gRPC server complete\n");
gpr_log(GPR_INFO, "gRPC server shutting down: done");
}

View File

@@ -25,28 +25,22 @@ namespace falco
{
namespace grpc
{
class server : public server_impl
{
public:
server()
{
}
server(std::string server_addr, int threadiness, std::string private_key, std::string cert_chain, std::string root_certs):
m_server_addr(server_addr),
m_threadiness(threadiness),
m_private_key(private_key),
m_cert_chain(cert_chain),
m_root_certs(root_certs)
{
}
server() = default;
virtual ~server() = default;
void init(std::string server_addr, int threadiness, std::string private_key, std::string cert_chain, std::string root_certs);
void init(std::string server_addr, std::string private_key, std::string cert_chain, std::string root_certs, int threadiness, std::string log_level);
void thread_process(int thread_index);
void run();
void stop();
output::service::AsyncService m_svc;
outputs::service::AsyncService m_outputs_svc;
version::service::AsyncService m_version_svc;
inputs::service::AsyncService m_inputs_svc;
std::unique_ptr<::grpc::ServerCompletionQueue> m_completion_queue;
private:
@@ -60,51 +54,5 @@ private:
std::vector<std::thread> m_threads;
};
class request_context_base
{
public:
request_context_base() = default;
~request_context_base() = default;
std::unique_ptr<::grpc::ServerContext> m_srv_ctx;
enum : char
{
UNKNOWN = 0,
REQUEST,
WRITE,
FINISH
} m_state = UNKNOWN;
virtual void start(server* srv) = 0;
virtual void process(server* srv) = 0;
virtual void end(server* srv, bool isError) = 0;
};
//
// Template class to handle streaming responses
//
template<class Request, class Response>
class request_stream_context : public request_context_base
{
public:
request_stream_context():
m_process_func(nullptr),
m_request_func(nullptr){};
~request_stream_context() = default;
// Pointer to function that does actual processing
void (server::*m_process_func)(const stream_context&, const Request&, Response&);
// Pointer to function that requests the system to start processing given requests
void (output::service::AsyncService::*m_request_func)(::grpc::ServerContext*, Request*, ::grpc::ServerAsyncWriter<Response>*, ::grpc::CompletionQueue*, ::grpc::ServerCompletionQueue*, void*);
void start(server* srv);
void process(server* srv);
void end(server* srv, bool isError);
private:
std::unique_ptr<::grpc::ServerAsyncWriter<Response>> m_res_writer;
std::unique_ptr<stream_context> m_stream_ctx;
Request m_req;
};
} // namespace grpc
} // namespace falco
} // namespace falco

View File

@@ -14,8 +14,10 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
#include "config_falco.h"
#include "grpc_server_impl.h"
#include "falco_output_queue.h"
#include "banned.h"
bool falco::grpc::server_impl::is_running()
{
@@ -26,21 +28,42 @@ bool falco::grpc::server_impl::is_running()
return true;
}
void falco::grpc::server_impl::subscribe(const stream_context& ctx, const output::request& req, output::response& res)
void falco::grpc::server_impl::outputs_impl(const stream_context& ctx, const outputs::request& req, outputs::response& res)
{
if(ctx.m_status == stream_context::SUCCESS || ctx.m_status == stream_context::ERROR)
std::string client = ctx.peer();
if(ctx.m_status == stream_status::SUCCESS || ctx.m_status == stream_status::ERROR)
{
// Entering here when the streaming completed (request_context_base::FINISH)
// context m_status == stream_context::SUCCESS when the gRPC server shutdown the context
// context m_status == stream_context::ERROR when the gRPC client shutdown the context
gpr_log(
GPR_DEBUG,
"server_impl::%s -> streaming done: %s, client=%s, status=%s, stream=%p",
__func__,
ctx.m_prefix.c_str(),
client.c_str(),
stream_status_Name(ctx.m_status).c_str(),
ctx.m_stream);
ctx.m_stream = nullptr;
}
else
{
// Streaming
if(output::queue::get().try_pop(res) && !req.keepalive())
// Start or continue streaming (m_status == stream_context::STREAMING)
gpr_log(
GPR_DEBUG,
"server_impl::%s -> start or continue streaming: %s, client=%s, status=%s, stream=%p",
__func__,
ctx.m_prefix.c_str(),
client.c_str(),
stream_status_Name(ctx.m_status).c_str(),
ctx.m_stream);
// note(leodido) > set request-specific data on m_stream here, in case it is needed
if(outputs::queue::get().try_pop(res) && !req.keepalive())
{
ctx.m_has_more = true;
return;
}
while(is_running() && !output::queue::get().try_pop(res) && req.keepalive())
while(is_running() && !outputs::queue::get().try_pop(res) && req.keepalive())
{
}
@@ -48,6 +71,36 @@ void falco::grpc::server_impl::subscribe(const stream_context& ctx, const output
}
}
void falco::grpc::server_impl::version_impl(const context& ctx, const version::request& req, version::response& res)
{
gpr_log(GPR_DEBUG, "server_impl::%s -> replying: %s, client=%s", __func__, ctx.m_prefix.c_str(), ctx.peer().c_str());
auto& build = *res.mutable_build();
build = FALCO_VERSION_BUILD;
auto& prerelease = *res.mutable_prerelease();
prerelease = FALCO_VERSION_PRERELEASE;
auto& version = *res.mutable_version();
version = FALCO_VERSION;
res.set_major(FALCO_VERSION_MAJOR);
res.set_minor(FALCO_VERSION_MINOR);
res.set_patch(FALCO_VERSION_PATCH);
}
void falco::grpc::server_impl::input_impl(const context& ctx, const inputs::request& req, inputs::response& res)
{
std::string client = ctx.peer();
gpr_log(GPR_DEBUG, "server_impl::%s -> replying: %s, client=%s", __func__, ctx.m_prefix.c_str(), client.c_str());
// todo(leodido) > implement
// retrieve metadata
// if type = K8S_AUDIT
// ...
// if type = SYSCALL
// ...
}
void falco::grpc::server_impl::shutdown()
{
m_stop = true;

View File

@@ -17,7 +17,9 @@ limitations under the License.
#pragma once
#include <atomic>
#include "output.grpc.pb.h"
#include "outputs.grpc.pb.h"
#include "version.grpc.pb.h"
#include "inputs.grpc.pb.h"
#include "grpc_context.h"
namespace falco
@@ -35,7 +37,11 @@ public:
protected:
bool is_running();
void subscribe(const stream_context& ctx, const output::request& req, output::response& res);
void outputs_impl(const stream_context& ctx, const outputs::request& req, outputs::response& res);
void version_impl(const context& ctx, const version::request& req, version::response& res);
void input_impl(const context& ctx, const inputs::request& req, inputs::response& res);
private:
std::atomic<bool> m_stop{false};

View File

@@ -0,0 +1,21 @@
syntax = "proto3";
// import "event.proto";
import "google/protobuf/any.proto";
package falco.inputs;
option go_package = "github.com/falcosecurity/client-go/pkg/api/inputs";
// service service { rpc input(request) returns (response); }
// message request { repeated falco.event.event data = 1; }
// message response {};
service service { rpc input(request) returns (response); }
message request { repeated google.protobuf.Any events = 1; }
message response {};

View File

@@ -19,6 +19,7 @@ limitations under the License.
#include "chisel_api.h"
#include "falco_common.h"
#include "banned.h"
const static struct luaL_reg ll_falco [] =
{
@@ -158,5 +159,3 @@ void falco_logger::log(int priority, const string msg)
}
}
}

View File

@@ -3,18 +3,18 @@ syntax = "proto3";
import "google/protobuf/timestamp.proto";
import "schema.proto";
package falco.output;
package falco.outputs;
option go_package = "github.com/falcosecurity/client-go/pkg/api/output";
option go_package = "github.com/falcosecurity/client-go/pkg/api/outputs";
// The `subscribe` service defines the RPC call
// The `outputs` service defines a server-streaming RPC call
// to perform an output `request` which will lead to obtain an output `response`.
service service {
rpc subscribe(request) returns (stream response);
rpc outputs(request) returns (stream response);
}
// The `request` message is the logical representation of the request model.
// It is the input of the `subscribe` service.
// It is the input of the `outputs` service.
// It is used to configure the kind of subscription to the gRPC streaming server.
//
// By default the request asks to the server to only receive the accumulated events.

View File

@@ -18,6 +18,7 @@ limitations under the License.
#include <signal.h>
#include "statsfilewriter.h"
#include "banned.h"
using namespace std;

View File

@@ -15,6 +15,7 @@ limitations under the License.
*/
#include "utils.h"
#include "banned.h"
void falco::utils::read(const std::string& filename, std::string& data)
{

View File

@@ -0,0 +1,29 @@
syntax = "proto3";
package falco.version;
option go_package = "github.com/falcosecurity/client-go/pkg/api/version";
// This service defines a RPC call
// to request the Falco version.
service service {
rpc version(request) returns (response);
}
// The `request` message is an empty one.
message request
{
}
// The `response` message contains the version of Falco.
// It provides the whole version as a string and also
// its parts as per semver 2.0 specification (https://semver.org).
message response
{
string version = 1;
uint32 major = 2;
uint32 minor = 3;
uint32 patch = 4;
string prerelease = 5;
string build = 6;
}

View File

@@ -20,6 +20,7 @@ limitations under the License.
#include "falco_common.h"
#include "webserver.h"
#include "json_evt.h"
#include "banned.h"
using json = nlohmann::json;
using namespace std;