137 lines
3.7 KiB
Go
137 lines
3.7 KiB
Go
|
// Licensed to Elasticsearch B.V. under one or more contributor
|
||
|
// license agreements. See the NOTICE file distributed with
|
||
|
// this work for additional information regarding copyright
|
||
|
// ownership. Elasticsearch B.V. licenses this file to you 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.
|
||
|
|
||
|
package seccomp
|
||
|
|
||
|
import (
|
||
|
"runtime"
|
||
|
|
||
|
"github.com/pkg/errors"
|
||
|
|
||
|
"github.com/elastic/beats/libbeat/common"
|
||
|
"github.com/elastic/beats/libbeat/logp"
|
||
|
"github.com/elastic/go-seccomp-bpf"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
defaultPolicy *seccomp.Policy
|
||
|
registeredPolicy *seccomp.Policy
|
||
|
)
|
||
|
|
||
|
// MustRegisterPolicy registers a seccomp policy to use instead of the default
|
||
|
// policy. This can be used to register an application specific seccomp policy
|
||
|
// that is tailored to the specific system calls that the application requires.
|
||
|
// It panics if a policy has already been registered or if the given policy
|
||
|
// is invalid.
|
||
|
func MustRegisterPolicy(p *seccomp.Policy) {
|
||
|
if p == nil {
|
||
|
panic(errors.New("seccomp policy cannot be nil"))
|
||
|
}
|
||
|
|
||
|
if registeredPolicy != nil {
|
||
|
panic(errors.New("a seccomp policy is already registered"))
|
||
|
}
|
||
|
|
||
|
// Ensure that the policy is valid and usable.
|
||
|
if _, err := p.Assemble(); err != nil {
|
||
|
panic(errors.Wrap(err, "failed to register seccomp policy"))
|
||
|
}
|
||
|
registeredPolicy = p
|
||
|
}
|
||
|
|
||
|
// LoadFilter loads a seccomp system call filter into the kernel for this
|
||
|
// process. This feature is only available on Linux 3.17+. If c is nil or does
|
||
|
// not contain a seccomp policy then a default policy will be used.
|
||
|
//
|
||
|
// An error is returned if there is a config validation problem. Otherwise any
|
||
|
// errors interfacing with the kernel are logged (i.e. it is non-fatal if
|
||
|
// seccomp cannot be setup).
|
||
|
//
|
||
|
// Policy precedence order (highest to lowest):
|
||
|
// - Policy values from config
|
||
|
// - Application registered policy
|
||
|
// - Default policy (a simple blacklist)
|
||
|
func LoadFilter(c *common.Config) error {
|
||
|
// Bail out if seccomp.enabled=false.
|
||
|
if c != nil && !c.Enabled() {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
p, err := getPolicy(c)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
loadFilter(p)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// loadFilter loads a system call filter.
|
||
|
func loadFilter(p *seccomp.Policy) {
|
||
|
log := logp.NewLogger("seccomp")
|
||
|
|
||
|
if runtime.GOOS != "linux" {
|
||
|
log.Debug("Syscall filtering is only supported on Linux")
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if !seccomp.Supported() {
|
||
|
log.Info("Syscall filter could not be installed because the kernel " +
|
||
|
"does not support seccomp")
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if p == nil {
|
||
|
log.Debug("No seccomp policy is defined")
|
||
|
return
|
||
|
}
|
||
|
|
||
|
filter := seccomp.Filter{
|
||
|
NoNewPrivs: true,
|
||
|
Flag: seccomp.FilterFlagTSync,
|
||
|
Policy: *p,
|
||
|
}
|
||
|
|
||
|
log.Debugw("Loading syscall filter", "seccomp_filter", filter)
|
||
|
if err := seccomp.LoadFilter(filter); err != nil {
|
||
|
log.Warn("Syscall filter could not be installed", "error", err,
|
||
|
"seccomp_filter", filter)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
log.Infow("Syscall filter successfully installed")
|
||
|
}
|
||
|
|
||
|
func getPolicy(c *common.Config) (*seccomp.Policy, error) {
|
||
|
policy := defaultPolicy
|
||
|
if registeredPolicy != nil {
|
||
|
policy = registeredPolicy
|
||
|
}
|
||
|
|
||
|
if c != nil && (c.HasField("default_action") || c.HasField("syscalls")) {
|
||
|
if policy == nil {
|
||
|
policy = &seccomp.Policy{}
|
||
|
}
|
||
|
|
||
|
if err := c.Unpack(policy); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return policy, nil
|
||
|
}
|