Skip to content

Commit

Permalink
Add seccomp whitelist policy
Browse files Browse the repository at this point in the history
This PR adds to the seccomp enhancement in elastic#6832 by adding a whitelist policy.

The policies are derived from a combination of static analysis of the object code and runtime profiling (to see what the cgo linked libraries are doing). The policies also account for the system calls used while running the system tests with coverage and race detection.

Closes elastic#5213
  • Loading branch information
andrewkroh authored and stevea78 committed May 20, 2018
1 parent bdbf20c commit cab44bc
Show file tree
Hide file tree
Showing 21 changed files with 624 additions and 159 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ https://github.com/elastic/beats/compare/v6.2.3...master[Check the HEAD diff]
- 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]
- Added a seccomp (secure computing) filter on Linux that whitelists the
necessary system calls used by each Beat. {issue}5213[5213]
- Update Sarama to v1.16.0, adding better support for kafka 0.11, 1.0, and 1.1 {pull}7025[7025]
- Ship fields.yml as part of the binary {pull}4834[4834]
- Added options to dev-tools/cmd/dashboards/export_dashboard.go: -indexPattern to include index-pattern in output, -quiet to be quiet. {pull}7101[7101]
Expand Down
14 changes: 1 addition & 13 deletions auditbeat/auditbeat.reference.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1088,16 +1088,4 @@ logging.files:
#============================= 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
#seccomp.enabled: true
8 changes: 5 additions & 3 deletions auditbeat/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package cmd
import (
"github.com/spf13/pflag"

"github.com/elastic/beats/metricbeat/beater"

"github.com/elastic/beats/auditbeat/core"
cmd "github.com/elastic/beats/libbeat/cmd"
"github.com/elastic/beats/libbeat/cmd"
"github.com/elastic/beats/metricbeat/beater"
"github.com/elastic/beats/metricbeat/mb/module"

// Register includes.
_ "github.com/elastic/beats/auditbeat/include"
)

// Name of the beat (auditbeat).
Expand Down
8 changes: 8 additions & 0 deletions auditbeat/include/list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package include

import (
// Include all Auditbeat modules so that they register their
// factories with the global registry.
_ "github.com/elastic/beats/auditbeat/module/auditd"
_ "github.com/elastic/beats/auditbeat/module/file_integrity"
)
14 changes: 1 addition & 13 deletions filebeat/filebeat.reference.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1644,16 +1644,4 @@ logging.files:
#============================= 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
#seccomp.enabled: true
14 changes: 1 addition & 13 deletions heartbeat/heartbeat.reference.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1197,16 +1197,4 @@ logging.files:
#============================= 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
#seccomp.enabled: true
14 changes: 1 addition & 13 deletions libbeat/_meta/config.reference.yml
Original file line number Diff line number Diff line change
Expand Up @@ -983,16 +983,4 @@ logging.files:
#============================= 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
#seccomp.enabled: true
57 changes: 3 additions & 54 deletions libbeat/cmd/instance/beat.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/elastic/beats/libbeat/common"
"github.com/elastic/beats/libbeat/common/cfgwarn"
"github.com/elastic/beats/libbeat/common/file"
"github.com/elastic/beats/libbeat/common/seccomp"
"github.com/elastic/beats/libbeat/dashboards"
"github.com/elastic/beats/libbeat/keystore"
"github.com/elastic/beats/libbeat/logp"
Expand All @@ -40,7 +41,6 @@ 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 @@ -288,10 +288,8 @@ 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
}
if err = seccomp.LoadFilter(b.Config.Seccomp); err != nil {
return err
}

beater, err := b.createBeater(bt)
Expand Down Expand Up @@ -786,52 +784,3 @@ 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
}
112 changes: 112 additions & 0 deletions libbeat/common/seccomp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Package seccomp

Package seccomp loads a Linux seccomp BPF filter that controls what system calls
the process can use. Here is a description of the files in this directory.

| File | Description |
|--------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| seccomp.go | Contains the code for registering application specific policies and for loading the seccomp BPF filter. |
| policy.go.tpl | This is a Go text/template used to generate code for a whitelist seccomp BPF policy. The template is used when running `make seccomp` and `make seccomp-package`. The tool that reads the template file is the [seccomp-profiler](https://github.com/elastic/go-seccomp-bpf/tree/master/cmd/seccomp-profiler). |
| seccomp-profiler-blacklist.txt | A list of system calls that are filtered from the resulting policy even if they are detected as being used in a binary. For example if the os/exec package is included by a dependency it will cause several system calls to be included such as execve, ptrace, and chroot. The system calls are never actually used so we want them removed from the profile. |
| seccomp-profiler-allow.txt | A list of system calls that are always included in the resulting policy. System calls that are made from CGO or linked libraries (such as libpthread) are not detected by seccomp-profiler and must be manually added to the list. Tools like `strace -c` and Auditbeat (where event.action=violated-seccomp-policy) can be used to find missing system calls. System calls from any architecture may be added to the list because it is automatically filtered based on architecture. |
| policy_linux_$arch.go | This is a default policy provided by libbeat. It is used when a Beat does not register its own application specific policy with `seccomp.MustRegisterPolicy()` (e.g. community Beats).|

## Developing a Whitelist Policy

Policy files can be generated for amd64 and 386 architectures (our tooling is
currently limited to these architectures). You can generate a policy by building
the packages and then profiling the resulting binaries. This ensures that the
profiles are built based on the binaries you plan to release. The policies are
stored at `$beatname/include/seccomp_linux_$goarch.go`.

```sh
make package && make seccomp-package
```

If you are developing on Linux you can profile the binary produced by `make`.
It will only generate a profile for the current architecture.

```sh
make && make seccomp
```

You should thoroughly test the policy as described below and add any additional
syscalls that are detected.

The `include` package must be imported by the Beat such that the policy is
registered as a side-effect.

```go
import (
_ "github.com/user/beatname/include"
)
```

## Testing Seccomp Policies

### Linux Auditing

Seccomp violations are reported by Linux kernel's audit subsystem. So you can run
Auditbeat to look for system call denials. With this config Auditbeat will
report only seccomp events.

```yaml
auditbeat.modules:
- module: auditd
processors:
- drop_event.when.not.equals.event.type: seccomp

output.console.pretty: true

logging.level: warning
```
Then start Auditbeat and it will log events to stdout.
`sudo auditbeat -e`

### strace

Another profiling option is `strace -c`. This will record all system calls used
by the Beat. Then this list can be used to steer the development of a policy.

```sh
sudo strace -c ./metricbeat -strict.perms=false
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
79.75 0.002521 97 26 futex
2.97 0.000094 3 34 mmap
2.69 0.000085 1 120 rt_sigaction
2.25 0.000071 18 4 open
1.96 0.000062 12 5 1 openat
1.68 0.000053 5 11 read
1.46 0.000046 4 12 getrandom
1.42 0.000045 4 11 mprotect
1.08 0.000034 6 6 fstat
0.85 0.000027 14 2 munmap
0.70 0.000022 6 4 clone
0.57 0.000018 18 1 ioctl
0.47 0.000015 2 8 close
0.41 0.000013 2 8 2 epoll_ctl
0.38 0.000012 1 11 rt_sigprocmask
0.22 0.000007 7 1 newfstatat
0.19 0.000006 6 1 write
0.16 0.000005 1 6 fcntl
0.13 0.000004 1 3 brk
0.13 0.000004 1 5 5 access
0.13 0.000004 4 1 sched_getaffinity
0.09 0.000003 2 2 sigaltstack
0.06 0.000002 2 1 getcwd
0.06 0.000002 2 1 getrlimit
0.06 0.000002 2 1 arch_prctl
0.06 0.000002 2 1 gettid
0.03 0.000001 1 1 set_tid_address
0.03 0.000001 1 1 set_robust_list
0.00 0.000000 0 1 execve
0.00 0.000000 0 1 getuid
0.00 0.000000 0 1 getgid
0.00 0.000000 0 1 readlinkat
0.00 0.000000 0 1 epoll_create1
------ ----------- ----------- --------- --------- ----------------
100.00 0.003161 293 8 total
```
27 changes: 27 additions & 0 deletions libbeat/common/seccomp/policy.go.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Code generated by seccomp-profiler - DO NOT EDIT.

// {{ printf "+build linux,"}}{{.GOARCH}}

package {{.Package}}

import (
"github.com/elastic/go-seccomp-bpf"

beat "github.com/elastic/beats/libbeat/common/seccomp"
)

func init() {
beat.MustRegisterPolicy(&seccomp.Policy{
DefaultAction: seccomp.ActionErrno,
Syscalls: []seccomp.SyscallGroup{
{
Action: seccomp.ActionAllow,
Names: []string{
{{- range $syscall := .SyscallNames}}
"{{ $syscall }}",
{{- end}}
},
},
},
})
}
Loading

0 comments on commit cab44bc

Please sign in to comment.