Skip to content

Commit

Permalink
Add a configurable seccomp filter on Linux
Browse files Browse the repository at this point in the history
The adds a default seccomp (Secure Computing) filter on Linux that prohibits execve, execveat, fork, and vfork system calls for the Beat process. The seccomp filter policy is configurable as well. You can create your own whitelist or blacklist policy with specific actions. It uses github.com/elastic/go-seccomp-bpf.

Whitelist Example

```
seccomp:
  default_action: errno
  syscalls:
  - action: allow
    names:
    - open
    - close
    - read
    - exit
```

Blacklist Example

```
seccomp:
  default_action: allow
  syscalls:
  - action: log
    names:
    - execve
    - execveat
    - fork
    - vfork
  - action: kill_process     # Requires kernel 4.14+.
    names:
    - connect
    - accept
    - sendto
    - recvfrom
    - sendmsg
    - recvmsg
    - bind
    - listen
```

Closes elastic#5213

Decisions I Made

- The default policy is a blacklist because it was the most simple to start with. Whitelisting is recommended because it is more robust. `man seccomp` states "A blacklist will have to be updated whenever a potentially dangerous system call is added (or a dangerous flag or option if those are blacklisted), and it is often possible to alter the representation of a value without altering its meaning, leading to a blacklist bypass."

- I chose to not implement argument filtering. It would be useful to have for more granular policies, but I'd rather wait to see how the policies are used and see if argument filtering is required.

- The code only makes use of the `seccomp` syscall to install the filter. It does not fallback to the `prctl(2)` `PR_SET_SECCOMP` operation because it does not support flags. The `SECCOMP_FILTER_FLAG_TSYNC` flag is necessary in Go because we have little control over when threads are started, and there are no guarantees that the filter would be installed before other threads start.
  • Loading branch information
andrewkroh authored and adriansr committed May 7, 2018
1 parent 08d9d08 commit 219fc1c
Show file tree
Hide file tree
Showing 22 changed files with 283 additions and 156 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// Template, add newest changes here

=== Beats version HEAD
https://github.com/elastic/beats/compare/v6.0.0-beta2...master[Check the HEAD diff]
https://github.com/elastic/beats/compare/v6.2.3...master[Check the HEAD diff]

==== Breaking changes

Expand Down Expand Up @@ -119,6 +119,8 @@ https://github.com/elastic/beats/compare/v6.0.0-beta2...master[Check the HEAD di
- Do not log errors if X-Pack Monitoring is enabled but Elastisearch X-Pack is not. {pull}6627[6627]
- Add rename processor. {pull}6292[6292]
- Add IP-addresses and MAC-addresses to add_host_metadata. {pull}6878[6878]
- Add a default seccomp (secure computing) filter on Linux that prohibits
execve, execveat, fork, and vfork syscalls. A custom policy can be configured. {issue}5213[5213]

*Auditbeat*

Expand Down
17 changes: 17 additions & 0 deletions auditbeat/auditbeat.reference.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1084,3 +1084,20 @@ logging.files:

# Port on which the HTTP endpoint will bind. Default is 5066.
#http.port: 5066

#============================= Process Security ================================

# Enable or disable seccomp system call filtering on Linux. Default is enabled.
seccomp.enabled: true

# The default seccomp policy. This policy blacklists system calls that allow
# process creation.
seccomp:
default_action: allow
syscalls:
- action: errno
names:
- execve
- execveat
- fork
- vfork
4 changes: 1 addition & 3 deletions auditbeat/docs/index.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,7 @@ include::./fields.asciidoc[]

include::../../libbeat/docs/monitoring/monitoring-beats.asciidoc[]

include::./securing-auditbeat.asciidoc[]

include::../../libbeat/docs/security/securing-beats.asciidoc[]
include::../../libbeat/docs/shared-securing-beat.asciidoc[]

include::./troubleshooting.asciidoc[]

Expand Down
4 changes: 1 addition & 3 deletions filebeat/docs/index.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,7 @@ include::./fields.asciidoc[]

include::../../libbeat/docs/monitoring/monitoring-beats.asciidoc[]

include::./securing-filebeat.asciidoc[]

include::../../libbeat/docs/security/securing-beats.asciidoc[]
include::../../libbeat/docs/shared-securing-beat.asciidoc[]

include::./troubleshooting.asciidoc[]

Expand Down
27 changes: 0 additions & 27 deletions filebeat/docs/securing-filebeat.asciidoc

This file was deleted.

17 changes: 17 additions & 0 deletions filebeat/filebeat.reference.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1626,3 +1626,20 @@ logging.files:

# Port on which the HTTP endpoint will bind. Default is 5066.
#http.port: 5066

#============================= Process Security ================================

# Enable or disable seccomp system call filtering on Linux. Default is enabled.
seccomp.enabled: true

# The default seccomp policy. This policy blacklists system calls that allow
# process creation.
seccomp:
default_action: allow
syscalls:
- action: errno
names:
- execve
- execveat
- fork
- vfork
4 changes: 1 addition & 3 deletions heartbeat/docs/index.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,7 @@ include::./fields.asciidoc[]

include::../../libbeat/docs/monitoring/monitoring-beats.asciidoc[]

include::./securing-heartbeat.asciidoc[]

include::../../libbeat/docs/security/securing-beats.asciidoc[]
include::../../libbeat/docs/shared-securing-beat.asciidoc[]

include::./troubleshooting.asciidoc[]

Expand Down
28 changes: 0 additions & 28 deletions heartbeat/docs/securing-heartbeat.asciidoc

This file was deleted.

17 changes: 17 additions & 0 deletions heartbeat/heartbeat.reference.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1193,3 +1193,20 @@ logging.files:

# Port on which the HTTP endpoint will bind. Default is 5066.
#http.port: 5066

#============================= Process Security ================================

# Enable or disable seccomp system call filtering on Linux. Default is enabled.
seccomp.enabled: true

# The default seccomp policy. This policy blacklists system calls that allow
# process creation.
seccomp:
default_action: allow
syscalls:
- action: errno
names:
- execve
- execveat
- fork
- vfork
17 changes: 17 additions & 0 deletions libbeat/_meta/config.reference.yml
Original file line number Diff line number Diff line change
Expand Up @@ -979,3 +979,20 @@ logging.files:

# Port on which the HTTP endpoint will bind. Default is 5066.
#http.port: 5066

#============================= Process Security ================================

# Enable or disable seccomp system call filtering on Linux. Default is enabled.
seccomp.enabled: true

# The default seccomp policy. This policy blacklists system calls that allow
# process creation.
seccomp:
default_action: allow
syscalls:
- action: errno
names:
- execve
- execveat
- fork
- vfork
61 changes: 59 additions & 2 deletions libbeat/cmd/instance/beat.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import (
svc "github.com/elastic/beats/libbeat/service"
"github.com/elastic/beats/libbeat/template"
"github.com/elastic/beats/libbeat/version"
"github.com/elastic/go-seccomp-bpf"
"github.com/elastic/go-sysinfo"
"github.com/elastic/go-sysinfo/types"

Expand Down Expand Up @@ -76,8 +77,9 @@ type beatConfig struct {
// instance internal configs

// beat top-level settings
Name string `config:"name"`
MaxProcs int `config:"max_procs"`
Name string `config:"name"`
MaxProcs int `config:"max_procs"`
Seccomp *common.Config `config:"seccomp"`

// beat internal components configurations
HTTP *common.Config `config:"http"`
Expand Down Expand Up @@ -279,6 +281,12 @@ func (b *Beat) launch(bt beat.Creator) error {
svc.BeforeRun()
defer svc.Cleanup()

if b.Config.Seccomp == nil || b.Config.Seccomp.Enabled() {
if err = loadSeccompFilter(b.Config.Seccomp); err != nil {
return err
}
}

beater, err := b.createBeater(bt)
if err != nil {
return err
Expand Down Expand Up @@ -771,3 +779,52 @@ func logSystemInfo(info beat.Info) {
}
}
}

// loadSeccompFilter loads a seccomp system call filter into the kernel for
// this process. This feature is only available on Linux and our implementation
// requires Linux 3.17 or newer. This only returns an error if there is a
// configuration problem. An errors interfacing with the kernel are only logged.
func loadSeccompFilter(c *common.Config) error {
if runtime.GOOS != "linux" {
return nil
}

filter := seccomp.Filter{
NoNewPrivs: true,
Flag: seccomp.FilterFlagTSync,
Policy: seccomp.Policy{
DefaultAction: seccomp.ActionAllow,
Syscalls: []seccomp.SyscallGroup{
{
Action: seccomp.ActionErrno,
Names: []string{
"execve",
"fork",
"vfork",
"execveat",
},
},
},
},
}

if c != nil && (c.HasField("default_profile") || c.HasField("syscalls")) {
var p seccomp.Policy
if err := c.Unpack(&p); err != nil {
return err
}
filter.Policy = p
}

log := logp.L().With("seccomp_filter", filter)
if err := seccomp.LoadFilter(filter); err != nil {
log.Warnf("seccomp BPF filter could not be installed (perhaps the "+
"kernel doesn't support this feature): %v", err)

// Only log the error. This is a non-fatal issue.
return nil
}

log.Infow("seccomp BPF filter successfully installed")
return nil
}
86 changes: 86 additions & 0 deletions libbeat/docs/security/linux-seccomp.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
[[linux-seccomp]]
== Using Linux Secure Computing Mode (seccomp)

beta[]

On Linux 3.17 and later, {beatname_uc} can take advantage of secure computing
mode, also known as seccomp. Seccomp restricts the system calls that a process
can issue. Specifically {beatname_uc} can load a seccomp BPF filter at process
start-up that drops the privileges to invoke specific system calls. Once a
filter is loaded by the process it cannot be removed.

The kernel exposes a large number of system calls that are not used by
{beatname_uc}. By installing a seccomp filter, you can limit the total kernel
surface exposed to {beatname_uc} (principle of least privilege). This minimizes
the impact of unknown vulnerabilities that might be found in the process.

The filter is expressed as a Berkeley Packet Filter (BPF) program. The BPF
program is generated based on a policy defined in the {beatname_uc}
configuration. If you don't specify a policy, {beatname_uc} uses a minimal
default blacklist policy that prohibits `execve`, `execveat`, `fork`, and
`vfork` syscalls. This is the default policy.

[source,yaml]
----
seccomp:
default_action: allow <1>
syscalls:
- action: errno <2>
names: <3>
- execve
- execveat
- fork
- vfork
----
<1> If the system call being invoked by the process does not match one of the
names below then it will be allowed.
<2> If the system call being invoked matches one of the names below then an
error will be returned to caller. This is known as a blacklist policy.
<3> These are system calls being prohibited.

[float]
[[seccomp-policy-config]]
=== Seccomp Policy Configuration

These are the configuration options for a seccomp policy.

*`enabled`*:: On Linux, this option is enabled by default. To disable seccomp
filter loading, set this option to `false`.

*`default_action`*:: The default action to take when none of the defined system
calls match. See <<seccomp-policy-config-action,action>> for the full list of
values. This is required.

*`syscalls`*:: Each object in this list must contain an `action` and a list of
system call `names`. The list must contain at least one item.

*`names`*:: A list of system call names. The system call name must exist for
the runtime architecture, otherwise an error will be logged and the filter will
not be installed. At least one system call must be defined.

[[seccomp-policy-config-action]]
*`action`*:: The action to take when any of the system calls listed in `names`
is executed. This is required. These are the available action values. The
actions that are available depend on the kernel version.

- `errno` - The system call will return `EPERM` (permission denied) to the
caller.
- `trace` - The kernel will notify a `ptrace` tracer. If no tracer is present
then the system call fails with `ENOSYS` (function not implemented).
- `trap` - The kernel will send a `SIGSYS` signal to the calling thread and not
execute the system call.
- `kill_thread` - The kernel will immediately terminate the thread. Other
threads will continue to execute.
- `kill_process` - The kernel will terminate the process. Available in Linux
4.14 and later.
- `log` - The kernel will log the system call before executing it. Available in
Linux 4.14 and later. (This does not go to the Beat's log.)
- `allow` - The kernel will allow the system call to execute.

[float]
=== Auditbeat Reports Seccomp Violations

You can use Auditbeat to report any seccomp violations that occur on the system.
The kernel generates an event for each violation and Auditbeat reports the
event. The `event.action` value will be `violated-seccomp-policy` and the event
will contain information about the process and system call.
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
[partintro]

--
The following topics describe how to secure communication between {beatname_uc}
and other products in the Elastic stack:
The following topics provide information about securing the {beatname_uc}
process and securing communication between {beatname_uc} and other products in
the Elastic stack:

* <<securing-communication-elasticsearch>>
* <<configuring-ssl-logstash>>
* <<securing-beats>>
* <<linux-seccomp>>

//sets block macro for https.asciidoc included in next section

Expand All @@ -18,11 +20,15 @@ and other products in the Elastic stack:
[[securing-communication-elasticsearch]]
== Secure communication with Elasticsearch

include::../../libbeat/docs/https.asciidoc[]
include::./https.asciidoc[]

//sets block macro for shared-ssl-logstash-config.asciidoc included in next section

[[configuring-ssl-logstash]]
== Secure communication with Logstash by using SSL

include::../../libbeat/docs/shared-ssl-logstash-config.asciidoc[]
include::./shared-ssl-logstash-config.asciidoc[]

include::./security/securing-beats.asciidoc[]

include::./security/linux-seccomp.asciidoc[]
Loading

0 comments on commit 219fc1c

Please sign in to comment.