Switch to containers/common for seccomp
seccomp/containers-golang is deprecated and we should switch to containers/common/pkg/seccomp instead. Signed-off-by: Sascha Grunert <sgrunert@suse.com>
This commit is contained in:
parent
ee6973ecfe
commit
d2ed7bc155
7
go.mod
7
go.mod
|
@ -4,10 +4,10 @@ go 1.12
|
|||
|
||||
require (
|
||||
github.com/containernetworking/cni v0.7.2-0.20190904153231-83439463f784
|
||||
github.com/containers/common v0.20.3
|
||||
github.com/containers/common v0.21.0
|
||||
github.com/containers/image/v5 v5.5.2
|
||||
github.com/containers/ocicrypt v1.0.3
|
||||
github.com/containers/storage v1.23.0
|
||||
github.com/containers/storage v1.23.3
|
||||
github.com/docker/distribution v2.7.1+incompatible
|
||||
github.com/docker/go-units v0.4.0
|
||||
github.com/docker/libnetwork v0.8.0-dev.2.0.20190625141545-5a177b73e316
|
||||
|
@ -26,8 +26,7 @@ require (
|
|||
github.com/opencontainers/selinux v1.6.0
|
||||
github.com/openshift/imagebuilder v1.1.6
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/seccomp/containers-golang v0.6.0
|
||||
github.com/seccomp/libseccomp-golang v0.9.1
|
||||
github.com/seccomp/libseccomp-golang v0.9.2-0.20200616122406-847368b35ebf
|
||||
github.com/sirupsen/logrus v1.6.0
|
||||
github.com/spf13/cobra v0.0.7
|
||||
github.com/spf13/pflag v1.0.5
|
||||
|
|
19
go.sum
19
go.sum
|
@ -52,10 +52,8 @@ github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDG
|
|||
github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
|
||||
github.com/containernetworking/cni v0.7.2-0.20190904153231-83439463f784 h1:rqUVLD8I859xRgUx/WMC3v7QAFqbLKZbs+0kqYboRJc=
|
||||
github.com/containernetworking/cni v0.7.2-0.20190904153231-83439463f784/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
|
||||
github.com/containers/common v0.20.3 h1:d8vSReNkrySKE3ZPya2vt6Wc/xuQiB30pNXTYHz2iHM=
|
||||
github.com/containers/common v0.20.3/go.mod h1:+NUHV8V5Kmo260ja9Dxtr8ialrDnK4RNzyeEbSgmLac=
|
||||
github.com/containers/image/v5 v5.5.1 h1:h1FCOXH6Ux9/p/E4rndsQOC4yAdRU0msRTfLVeQ7FDQ=
|
||||
github.com/containers/image/v5 v5.5.1/go.mod h1:4PyNYR0nwlGq/ybVJD9hWlhmIsNra4Q8uOQX2s6E2uM=
|
||||
github.com/containers/common v0.21.0 h1:v2U9MrGw0vMgefQf0/uJYBsSnengxLbSORYqhCVEBs0=
|
||||
github.com/containers/common v0.21.0/go.mod h1:8w8SVwc+P2p1MOnRMbSKNWXt1Iwd2bKFu2LLZx55DTM=
|
||||
github.com/containers/image/v5 v5.5.2 h1:fv7FArz0zUnjH0W0l8t90CqWFlFcQrPP6Pug+9dUtVI=
|
||||
github.com/containers/image/v5 v5.5.2/go.mod h1:4PyNYR0nwlGq/ybVJD9hWlhmIsNra4Q8uOQX2s6E2uM=
|
||||
github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b h1:Q8ePgVfHDplZ7U33NwHZkrVELsZP5fYj9pM5WBZB2GE=
|
||||
|
@ -66,8 +64,8 @@ github.com/containers/ocicrypt v1.0.3 h1:vYgl+RZ9Q3DPMuTfxmN+qp0X2Bj52uuY2vnt6Gz
|
|||
github.com/containers/ocicrypt v1.0.3/go.mod h1:CUBa+8MRNL/VkpxYIpaMtgn1WgXGyvPQj8jcy0EVG6g=
|
||||
github.com/containers/storage v1.20.2 h1:tw/uKRPDnmVrluIzer3dawTFG/bTJLP8IEUyHFhltYk=
|
||||
github.com/containers/storage v1.20.2/go.mod h1:oOB9Ie8OVPojvoaKWEGSEtHbXUAs+tSyr7RO7ZGteMc=
|
||||
github.com/containers/storage v1.23.0 h1:gYyNkBiihC2FvGiHOjOjpnfojYwgxpLVooTUlmD6pxs=
|
||||
github.com/containers/storage v1.23.0/go.mod h1:I1EIAA7B4OwWRSA0b4yq2AW1wjvvfcY0zLWQuwTa4zw=
|
||||
github.com/containers/storage v1.23.3 h1:6ZeQi+xKBXrbUXSSZvSs8HuKoNCPfRkXR4f+8TkiMsI=
|
||||
github.com/containers/storage v1.23.3/go.mod h1:0azTMiuBhArp/VUmH1o4DJAGaaH+qLtEu17pJ/iKJCg=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
|
@ -187,8 +185,8 @@ github.com/klauspost/compress v1.10.7 h1:7rix8v8GpI3ZBb0nSozFRgbtXKv+hOe+qfEpZqy
|
|||
github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.10.8 h1:eLeJ3dr/Y9+XRfJT4l+8ZjmtB5RPJhucH2HeCV5+IZY=
|
||||
github.com/klauspost/compress v1.10.8/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.10.10 h1:a/y8CglcM7gLGYmlbP/stPE5sR3hbhFRUjCBfd/0B3I=
|
||||
github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.10.11 h1:K9z59aO18Aywg2b/WSgBaUX99mHy2BES18Cr5lBKZHk=
|
||||
github.com/klauspost/compress v1.10.11/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/pgzip v1.2.4 h1:TQ7CNpYKovDOmqzRHKxJh0BeaBI7UdQZYc6p7pMQh1A=
|
||||
github.com/klauspost/pgzip v1.2.4/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||
|
@ -306,10 +304,10 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T
|
|||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/seccomp/containers-golang v0.6.0 h1:VWPMMIDr8pAtNjCX0WvLEEK9EQi5lAm4HtJbDtAtFvQ=
|
||||
github.com/seccomp/containers-golang v0.6.0/go.mod h1:Dd9mONHvW4YdbSzdm23yf2CFw0iqvqLhO0mEFvPIvm4=
|
||||
github.com/seccomp/libseccomp-golang v0.9.1 h1:NJjM5DNFOs0s3kYE1WUOr6G8V97sdt46rlXTMfXGWBo=
|
||||
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
|
||||
github.com/seccomp/libseccomp-golang v0.9.2-0.20200616122406-847368b35ebf h1:b0+ZBD3rohnkQ4q5duD1+RyTXTg9yk+qTOPMSQtapO0=
|
||||
github.com/seccomp/libseccomp-golang v0.9.2-0.20200616122406-847368b35ebf/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
|
@ -437,7 +435,6 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1 h1:sIky/MyNRSHTrdxfsiUSS4WIAMvInbeXljJz+jDjeYE=
|
||||
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
|
|
@ -5,9 +5,9 @@ package buildah
|
|||
import (
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/containers/common/pkg/seccomp"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
seccomp "github.com/seccomp/containers-golang"
|
||||
)
|
||||
|
||||
func setupSeccomp(spec *specs.Spec, seccompProfilePath string) error {
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/containers/common/pkg/apparmor/internal/supported"
|
||||
"github.com/containers/storage/pkg/unshare"
|
||||
runcaa "github.com/opencontainers/runc/libcontainer/apparmor"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -22,12 +23,11 @@ import (
|
|||
// profileDirectory is the file store for apparmor profiles and macros.
|
||||
var profileDirectory = "/etc/apparmor.d"
|
||||
|
||||
// IsEnabled returns true if AppArmor is enabled on the host.
|
||||
// IsEnabled returns true if AppArmor is enabled on the host. It also checks
|
||||
// for the existence of the `apparmor_parser` binary, which will be required to
|
||||
// apply profiles.
|
||||
func IsEnabled() bool {
|
||||
if unshare.IsRootless() {
|
||||
return false
|
||||
}
|
||||
return runcaa.IsEnabled()
|
||||
return supported.NewAppArmorVerifier().IsSupported() == nil
|
||||
}
|
||||
|
||||
// profileData holds information about the given profile for generation.
|
||||
|
@ -43,7 +43,7 @@ type profileData struct {
|
|||
}
|
||||
|
||||
// generateDefault creates an apparmor profile from ProfileData.
|
||||
func (p *profileData) generateDefault(out io.Writer) error {
|
||||
func (p *profileData) generateDefault(apparmorParserPath string, out io.Writer) error {
|
||||
compiled, err := template.New("apparmor_profile").Parse(defaultProfileTemplate)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "create AppArmor profile from template")
|
||||
|
@ -59,7 +59,7 @@ func (p *profileData) generateDefault(out io.Writer) error {
|
|||
p.InnerImports = append(p.InnerImports, "#include <abstractions/base>")
|
||||
}
|
||||
|
||||
ver, err := getAAParserVersion()
|
||||
ver, err := getAAParserVersion(apparmorParserPath)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "get AppArmor version")
|
||||
}
|
||||
|
@ -85,18 +85,23 @@ func InstallDefault(name string) error {
|
|||
Name: name,
|
||||
}
|
||||
|
||||
cmd := exec.Command("apparmor_parser", "-Kr")
|
||||
apparmorParserPath, err := supported.NewAppArmorVerifier().FindAppArmorParserBinary()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "find `apparmor_parser` binary")
|
||||
}
|
||||
|
||||
cmd := exec.Command(apparmorParserPath, "-Kr")
|
||||
pipe, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "execute apparmor_parser")
|
||||
return errors.Wrapf(err, "execute %s", apparmorParserPath)
|
||||
}
|
||||
if err := cmd.Start(); err != nil {
|
||||
if pipeErr := pipe.Close(); pipeErr != nil {
|
||||
logrus.Errorf("unable to close AppArmor pipe: %q", pipeErr)
|
||||
}
|
||||
return errors.Wrap(err, "start apparmor_parser command")
|
||||
return errors.Wrapf(err, "start %s command", apparmorParserPath)
|
||||
}
|
||||
if err := p.generateDefault(pipe); err != nil {
|
||||
if err := p.generateDefault(apparmorParserPath, pipe); err != nil {
|
||||
if pipeErr := pipe.Close(); pipeErr != nil {
|
||||
logrus.Errorf("unable to close AppArmor pipe: %q", pipeErr)
|
||||
}
|
||||
|
@ -118,11 +123,17 @@ func InstallDefault(name string) error {
|
|||
// generation fails.
|
||||
func DefaultContent(name string) ([]byte, error) {
|
||||
p := profileData{Name: name}
|
||||
var bytes bytes.Buffer
|
||||
if err := p.generateDefault(&bytes); err != nil {
|
||||
buffer := &bytes.Buffer{}
|
||||
|
||||
apparmorParserPath, err := supported.NewAppArmorVerifier().FindAppArmorParserBinary()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "find `apparmor_parser` binary")
|
||||
}
|
||||
|
||||
if err := p.generateDefault(apparmorParserPath, buffer); err != nil {
|
||||
return nil, errors.Wrap(err, "generate default AppAmor profile")
|
||||
}
|
||||
return bytes.Bytes(), nil
|
||||
return buffer.Bytes(), nil
|
||||
}
|
||||
|
||||
// IsLoaded checks if a profile with the given name has been loaded into the
|
||||
|
@ -159,8 +170,8 @@ func IsLoaded(name string) (bool, error) {
|
|||
}
|
||||
|
||||
// execAAParser runs `apparmor_parser` with the passed arguments.
|
||||
func execAAParser(dir string, args ...string) (string, error) {
|
||||
c := exec.Command("apparmor_parser", args...)
|
||||
func execAAParser(apparmorParserPath, dir string, args ...string) (string, error) {
|
||||
c := exec.Command(apparmorParserPath, args...)
|
||||
c.Dir = dir
|
||||
|
||||
output, err := c.Output()
|
||||
|
@ -172,8 +183,8 @@ func execAAParser(dir string, args ...string) (string, error) {
|
|||
}
|
||||
|
||||
// getAAParserVersion returns the major and minor version of apparmor_parser.
|
||||
func getAAParserVersion() (int, error) {
|
||||
output, err := execAAParser("", "--version")
|
||||
func getAAParserVersion(apparmorParserPath string) (int, error) {
|
||||
output, err := execAAParser(apparmorParserPath, "", "--version")
|
||||
if err != nil {
|
||||
return -1, errors.Wrap(err, "execute apparmor_parser")
|
||||
}
|
||||
|
|
113
vendor/github.com/containers/common/pkg/apparmor/internal/supported/supported.go
generated
vendored
Normal file
113
vendor/github.com/containers/common/pkg/apparmor/internal/supported/supported.go
generated
vendored
Normal file
|
@ -0,0 +1,113 @@
|
|||
package supported
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/containers/storage/pkg/unshare"
|
||||
runcaa "github.com/opencontainers/runc/libcontainer/apparmor"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 -generate
|
||||
|
||||
// ApparmorVerifier is the global struct for verifying if AppAmor is available
|
||||
// on the system.
|
||||
type ApparmorVerifier struct {
|
||||
impl verifierImpl
|
||||
parserBinaryPath string
|
||||
}
|
||||
|
||||
var (
|
||||
singleton *ApparmorVerifier
|
||||
once sync.Once
|
||||
)
|
||||
|
||||
// NewAppArmorVerifier can be used to retrieve a new ApparmorVerifier instance.
|
||||
func NewAppArmorVerifier() *ApparmorVerifier {
|
||||
once.Do(func() {
|
||||
singleton = &ApparmorVerifier{impl: &defaultVerifier{}}
|
||||
})
|
||||
return singleton
|
||||
}
|
||||
|
||||
// IsSupported returns nil if AppAmor is supported by the host system.
|
||||
// The method will error if:
|
||||
// - the process runs in rootless mode
|
||||
// - AppArmor is disabled by the host system
|
||||
// - the `apparmor_parser` binary is not discoverable
|
||||
func (a *ApparmorVerifier) IsSupported() error {
|
||||
if a.impl.UnshareIsRootless() {
|
||||
return errors.New("AppAmor is not supported on rootless containers")
|
||||
}
|
||||
if !a.impl.RuncIsEnabled() {
|
||||
return errors.New("AppArmor not supported by the host system")
|
||||
}
|
||||
|
||||
_, err := a.FindAppArmorParserBinary()
|
||||
return err
|
||||
}
|
||||
|
||||
// FindAppArmorParserBinary returns the `apparmor_parser` binary either from
|
||||
// `/sbin` or from `$PATH`. It returns an error if the binary could not be
|
||||
// found.
|
||||
func (a *ApparmorVerifier) FindAppArmorParserBinary() (string, error) {
|
||||
// Use the memoized path if available
|
||||
if a.parserBinaryPath != "" {
|
||||
logrus.Debugf("Using %s binary", a.parserBinaryPath)
|
||||
return a.parserBinaryPath, nil
|
||||
}
|
||||
|
||||
const (
|
||||
binary = "apparmor_parser"
|
||||
sbin = "/sbin"
|
||||
)
|
||||
|
||||
// `/sbin` is not always in `$PATH`, so we check it explicitly
|
||||
sbinBinaryPath := filepath.Join(sbin, binary)
|
||||
if _, err := a.impl.OsStat(sbinBinaryPath); err == nil {
|
||||
logrus.Debugf("Found %s binary in %s", binary, sbinBinaryPath)
|
||||
a.parserBinaryPath = sbinBinaryPath
|
||||
return sbinBinaryPath, nil
|
||||
}
|
||||
|
||||
// Fallback to checking $PATH
|
||||
if path, err := a.impl.ExecLookPath(binary); err == nil {
|
||||
logrus.Debugf("Found %s binary in %s", binary, path)
|
||||
a.parserBinaryPath = path
|
||||
return path, nil
|
||||
}
|
||||
|
||||
return "", errors.Errorf(
|
||||
"%s binary neither found in %s nor $PATH", binary, sbin,
|
||||
)
|
||||
}
|
||||
|
||||
//counterfeiter:generate . verifierImpl
|
||||
type verifierImpl interface {
|
||||
UnshareIsRootless() bool
|
||||
RuncIsEnabled() bool
|
||||
OsStat(name string) (os.FileInfo, error)
|
||||
ExecLookPath(file string) (string, error)
|
||||
}
|
||||
|
||||
type defaultVerifier struct{}
|
||||
|
||||
func (d *defaultVerifier) UnshareIsRootless() bool {
|
||||
return unshare.IsRootless()
|
||||
}
|
||||
|
||||
func (d *defaultVerifier) RuncIsEnabled() bool {
|
||||
return runcaa.IsEnabled()
|
||||
}
|
||||
|
||||
func (d *defaultVerifier) OsStat(name string) (os.FileInfo, error) {
|
||||
return os.Stat(name)
|
||||
}
|
||||
|
||||
func (d *defaultVerifier) ExecLookPath(file string) (string, error) {
|
||||
return exec.LookPath(file)
|
||||
}
|
|
@ -40,8 +40,8 @@ func CheckAuthFile(authfile string) error {
|
|||
// data with the original parameter.
|
||||
func systemContextWithOptions(sys *types.SystemContext, authFile, certDir string) *types.SystemContext {
|
||||
if sys != nil {
|
||||
copy := *sys
|
||||
sys = ©
|
||||
sysCopy := *sys
|
||||
sys = &sysCopy
|
||||
} else {
|
||||
sys = &types.SystemContext{}
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ func Login(ctx context.Context, systemContext *types.SystemContext, opts *LoginO
|
|||
|
||||
if err = docker.CheckAuth(ctx, systemContext, username, password, server); err == nil {
|
||||
// Write the new credentials to the authfile
|
||||
if err = config.SetAuthentication(systemContext, server, username, password); err != nil {
|
||||
if err := config.SetAuthentication(systemContext, server, username, password); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -156,8 +156,7 @@ func getRegistryName(server string) string {
|
|||
// getUserAndPass gets the username and password from STDIN if not given
|
||||
// using the -u and -p flags. If the username prompt is left empty, the
|
||||
// displayed userFromAuthFile will be used instead.
|
||||
func getUserAndPass(opts *LoginOptions, password, userFromAuthFile string) (string, string, error) {
|
||||
var err error
|
||||
func getUserAndPass(opts *LoginOptions, password, userFromAuthFile string) (user, pass string, err error) {
|
||||
reader := bufio.NewReader(opts.Stdin)
|
||||
username := opts.Username
|
||||
if username == "" {
|
||||
|
|
|
@ -612,11 +612,11 @@ func (c *ContainersConfig) Validate() error {
|
|||
}
|
||||
|
||||
if c.LogSizeMax >= 0 && c.LogSizeMax < OCIBufSize {
|
||||
return fmt.Errorf("log size max should be negative or >= %d", OCIBufSize)
|
||||
return errors.Errorf("log size max should be negative or >= %d", OCIBufSize)
|
||||
}
|
||||
|
||||
if _, err := units.FromHumanSize(c.ShmSize); err != nil {
|
||||
return fmt.Errorf("invalid --shm-size %s, %q", c.ShmSize, err)
|
||||
return errors.Errorf("invalid --shm-size %s, %q", c.ShmSize, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -759,15 +759,13 @@ func (c *Config) Capabilities(user string, addCapabilities, dropCapabilities []s
|
|||
// '/dev/sdc:/dev/xvdc"
|
||||
// '/dev/sdc:/dev/xvdc:rwm"
|
||||
// '/dev/sdc:rm"
|
||||
func Device(device string) (string, string, string, error) {
|
||||
src := ""
|
||||
dst := ""
|
||||
permissions := "rwm"
|
||||
func Device(device string) (src, dst, permissions string, err error) {
|
||||
permissions = "rwm"
|
||||
split := strings.Split(device, ":")
|
||||
switch len(split) {
|
||||
case 3:
|
||||
if !IsValidDeviceMode(split[2]) {
|
||||
return "", "", "", fmt.Errorf("invalid device mode: %s", split[2])
|
||||
return "", "", "", errors.Errorf("invalid device mode: %s", split[2])
|
||||
}
|
||||
permissions = split[2]
|
||||
fallthrough
|
||||
|
@ -775,19 +773,19 @@ func Device(device string) (string, string, string, error) {
|
|||
if IsValidDeviceMode(split[1]) {
|
||||
permissions = split[1]
|
||||
} else {
|
||||
if len(split[1]) == 0 || split[1][0] != '/' {
|
||||
return "", "", "", fmt.Errorf("invalid device mode: %s", split[1])
|
||||
if split[1] == "" || split[1][0] != '/' {
|
||||
return "", "", "", errors.Errorf("invalid device mode: %s", split[1])
|
||||
}
|
||||
dst = split[1]
|
||||
}
|
||||
fallthrough
|
||||
case 1:
|
||||
if !strings.HasPrefix(split[0], "/dev/") {
|
||||
return "", "", "", fmt.Errorf("invalid device mode: %s", split[0])
|
||||
return "", "", "", errors.Errorf("invalid device mode: %s", split[0])
|
||||
}
|
||||
src = split[0]
|
||||
default:
|
||||
return "", "", "", fmt.Errorf("invalid device specification: %s", device)
|
||||
return "", "", "", errors.Errorf("invalid device specification: %s", device)
|
||||
}
|
||||
|
||||
if dst == "" {
|
||||
|
@ -908,21 +906,6 @@ func Path() string {
|
|||
return OverrideContainersConfig
|
||||
}
|
||||
|
||||
func customConfigFile() (string, error) {
|
||||
path := os.Getenv("CONTAINERS_CONF")
|
||||
if path != "" {
|
||||
return path, nil
|
||||
}
|
||||
if unshare.IsRootless() {
|
||||
path, err := rootlessConfigPath()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
return OverrideContainersConfig, nil
|
||||
}
|
||||
|
||||
// ReadCustomConfig reads the custom config and only generates a config based on it
|
||||
// If the custom config file does not exists, function will return an empty config
|
||||
func ReadCustomConfig() (*Config, error) {
|
||||
|
@ -943,7 +926,7 @@ func ReadCustomConfig() (*Config, error) {
|
|||
|
||||
newConfig := &Config{}
|
||||
if _, err := os.Stat(path); err == nil {
|
||||
if err = readConfigFromFile(path, newConfig); err != nil {
|
||||
if err := readConfigFromFile(path, newConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
|
@ -990,13 +973,12 @@ func Reload() (*Config, error) {
|
|||
return defConfig()
|
||||
}
|
||||
|
||||
func (c *Config) ActiveDestination() (string, string, error) {
|
||||
func (c *Config) ActiveDestination() (uri, identity string, err error) {
|
||||
if uri, found := os.LookupEnv("CONTAINER_HOST"); found {
|
||||
var ident string
|
||||
if v, found := os.LookupEnv("CONTAINER_SSHKEY"); found {
|
||||
ident = v
|
||||
identity = v
|
||||
}
|
||||
return uri, ident, nil
|
||||
return uri, identity, nil
|
||||
}
|
||||
|
||||
switch {
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
func customConfigFile() (string, error) {
|
||||
if path, found := os.LookupEnv("CONTAINERS_CONF"); found {
|
||||
return path, nil
|
||||
}
|
||||
return rootlessConfigPath()
|
||||
}
|
|
@ -1,7 +1,26 @@
|
|||
package config
|
||||
|
||||
import selinux "github.com/opencontainers/selinux/go-selinux"
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/containers/storage/pkg/unshare"
|
||||
selinux "github.com/opencontainers/selinux/go-selinux"
|
||||
)
|
||||
|
||||
func selinuxEnabled() bool {
|
||||
return selinux.GetEnabled()
|
||||
}
|
||||
|
||||
func customConfigFile() (string, error) {
|
||||
if path, found := os.LookupEnv("CONTAINERS_CONF"); found {
|
||||
return path, nil
|
||||
}
|
||||
if unshare.IsRootless() {
|
||||
path, err := rootlessConfigPath()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
return OverrideContainersConfig, nil
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
|
@ -11,6 +10,7 @@ import (
|
|||
"syscall"
|
||||
|
||||
units "github.com/docker/go-units"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// isDirectory tests whether the given path exists and is a directory. It
|
||||
|
@ -43,13 +43,13 @@ func (c *EngineConfig) validatePaths() error {
|
|||
// shift between runs or even parts of the program. - The OCI runtime
|
||||
// uses a different working directory than we do, for example.
|
||||
if c.StaticDir != "" && !filepath.IsAbs(c.StaticDir) {
|
||||
return fmt.Errorf("static directory must be an absolute path - instead got %q", c.StaticDir)
|
||||
return errors.Errorf("static directory must be an absolute path - instead got %q", c.StaticDir)
|
||||
}
|
||||
if c.TmpDir != "" && !filepath.IsAbs(c.TmpDir) {
|
||||
return fmt.Errorf("temporary directory must be an absolute path - instead got %q", c.TmpDir)
|
||||
return errors.Errorf("temporary directory must be an absolute path - instead got %q", c.TmpDir)
|
||||
}
|
||||
if c.VolumePath != "" && !filepath.IsAbs(c.VolumePath) {
|
||||
return fmt.Errorf("volume path must be an absolute path - instead got %q", c.VolumePath)
|
||||
return errors.Errorf("volume path must be an absolute path - instead got %q", c.VolumePath)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ func (c *ContainersConfig) validateUlimits() error {
|
|||
for _, u := range c.DefaultUlimits {
|
||||
ul, err := units.ParseUlimit(u)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unrecognized ulimit %s: %v", u, err)
|
||||
return errors.Wrapf(err, "unrecognized ulimit %s", u)
|
||||
}
|
||||
_, err = ul.GetRlimit()
|
||||
if err != nil {
|
||||
|
@ -96,8 +96,8 @@ func (c *ContainersConfig) validateTZ() error {
|
|||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf(
|
||||
"unable to find timezone %s in paths: %s",
|
||||
return errors.Errorf(
|
||||
"find timezone %s in paths: %s",
|
||||
c.TZ, strings.Join(lookupPaths, ", "),
|
||||
)
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ func (c *ContainersConfig) validateTZ() error {
|
|||
func (c *ContainersConfig) validateUmask() error {
|
||||
validUmask := regexp.MustCompile(`^[0-7]{1,4}$`)
|
||||
if !validUmask.MatchString(c.Umask) {
|
||||
return fmt.Errorf("Not a valid Umask %s", c.Umask)
|
||||
return errors.Errorf("not a valid umask %s", c.Umask)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
package config
|
||||
|
||||
import "os"
|
||||
|
||||
func customConfigFile() (string, error) {
|
||||
if path, found := os.LookupEnv("CONTAINERS_CONF"); found {
|
||||
return path, nil
|
||||
}
|
||||
return os.Getenv("APPDATA") + "\\containers\\containers.conf", nil
|
||||
}
|
|
@ -92,7 +92,7 @@
|
|||
# Ulimits has limits for non privileged container engines.
|
||||
#
|
||||
# default_ulimits = [
|
||||
# "nofile"="1280:2560",
|
||||
# "nofile=1280:2560",
|
||||
# ]
|
||||
|
||||
# List of default DNS options to be added to /etc/resolv.conf inside of the container.
|
||||
|
|
|
@ -32,10 +32,8 @@ func getDefaultProcessLimits() []string {
|
|||
defaultLimits := []string{}
|
||||
if err := unix.Setrlimit(unix.RLIMIT_NPROC, &rlim); err == nil {
|
||||
defaultLimits = append(defaultLimits, fmt.Sprintf("nproc=%d:%d", rlim.Cur, rlim.Max))
|
||||
} else {
|
||||
if err := unix.Setrlimit(unix.RLIMIT_NPROC, &oldrlim); err == nil {
|
||||
defaultLimits = append(defaultLimits, fmt.Sprintf("nproc=%d:%d", oldrlim.Cur, oldrlim.Max))
|
||||
}
|
||||
} else if err := unix.Setrlimit(unix.RLIMIT_NPROC, &oldrlim); err == nil {
|
||||
defaultLimits = append(defaultLimits, fmt.Sprintf("nproc=%d:%d", oldrlim.Cur, oldrlim.Max))
|
||||
}
|
||||
return defaultLimits
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package config
|
|||
/* libpodConfig.go contains deprecated functionality and should not be used any longer */
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
@ -168,7 +167,7 @@ type ConfigFromLibpod struct {
|
|||
// EventsLogFilePath is where the events log is stored.
|
||||
EventsLogFilePath string `toml:"events_logfile_path,omitempty"`
|
||||
|
||||
//DetachKeys is the sequence of keys used to detach a container.
|
||||
// DetachKeys is the sequence of keys used to detach a container.
|
||||
DetachKeys string `toml:"detach_keys,omitempty"`
|
||||
|
||||
// SDNotify tells Libpod to allow containers to notify the host systemd of
|
||||
|
@ -247,7 +246,7 @@ func readLibpodConfigFromFile(path string, config *ConfigFromLibpod) (*ConfigFro
|
|||
logrus.Debugf("Reading configuration file %q", path)
|
||||
_, err := toml.DecodeFile(path, config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to decode configuration %v: %v", path, err)
|
||||
return nil, errors.Wrapf(err, "decode configuration %s", path)
|
||||
}
|
||||
|
||||
return config, err
|
||||
|
|
|
@ -49,7 +49,7 @@ func getRuntimeDir() (string, error) {
|
|||
if runtimeDir == "" {
|
||||
home := os.Getenv("HOME")
|
||||
if home == "" {
|
||||
rootlessRuntimeDirError = fmt.Errorf("neither XDG_RUNTIME_DIR nor HOME was set non-empty")
|
||||
rootlessRuntimeDirError = errors.New("neither XDG_RUNTIME_DIR nor HOME was set non-empty")
|
||||
return
|
||||
}
|
||||
resolvedHome, err := filepath.EvalSymlinks(home)
|
||||
|
|
|
@ -2,6 +2,7 @@ package retry
|
|||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"math"
|
||||
"net"
|
||||
"net/url"
|
||||
|
@ -17,7 +18,8 @@ import (
|
|||
|
||||
// RetryOptions defines the option to retry
|
||||
type RetryOptions struct {
|
||||
MaxRetry int // The number of times to possibly retry
|
||||
MaxRetry int // The number of times to possibly retry
|
||||
Delay time.Duration // The delay to use between retries, if set
|
||||
}
|
||||
|
||||
// RetryIfNecessary retries the operation in exponential backoff with the retryOptions
|
||||
|
@ -25,6 +27,9 @@ func RetryIfNecessary(ctx context.Context, operation func() error, retryOptions
|
|||
err := operation()
|
||||
for attempt := 0; err != nil && isRetryable(err) && attempt < retryOptions.MaxRetry; attempt++ {
|
||||
delay := time.Duration(int(math.Pow(2, float64(attempt)))) * time.Second
|
||||
if retryOptions.Delay != 0 {
|
||||
delay = retryOptions.Delay
|
||||
}
|
||||
logrus.Infof("Warning: failed, retrying in %s ... (%d/%d)", delay, attempt+1, retryOptions.MaxRetry)
|
||||
select {
|
||||
case <-time.After(delay):
|
||||
|
@ -58,7 +63,10 @@ func isRetryable(err error) bool {
|
|||
return true
|
||||
case *net.OpError:
|
||||
return isRetryable(e.Err)
|
||||
case *url.Error:
|
||||
case *url.Error: // This includes errors returned by the net/http client.
|
||||
if e.Err == io.EOF { // Happens when a server accepts a HTTP connection and sends EOF
|
||||
return true
|
||||
}
|
||||
return isRetryable(e.Err)
|
||||
case syscall.Errno:
|
||||
return e != syscall.ECONNREFUSED
|
||||
|
|
|
@ -0,0 +1,196 @@
|
|||
// NOTE: this package has originally been copied from
|
||||
// github.com/opencontainers/runc and modified to work for other use cases
|
||||
|
||||
package seccomp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
goArchToSeccompArchMap = map[string]Arch{
|
||||
"386": ArchX86,
|
||||
"amd64": ArchX86_64,
|
||||
"amd64p32": ArchX32,
|
||||
"arm": ArchARM,
|
||||
"arm64": ArchAARCH64,
|
||||
"mips": ArchMIPS,
|
||||
"mips64": ArchMIPS64,
|
||||
"mips64le": ArchMIPSEL64,
|
||||
"mips64p32": ArchMIPS64N32,
|
||||
"mips64p32le": ArchMIPSEL64N32,
|
||||
"mipsle": ArchMIPSEL,
|
||||
"ppc": ArchPPC,
|
||||
"ppc64": ArchPPC64,
|
||||
"ppc64le": ArchPPC64LE,
|
||||
"s390": ArchS390,
|
||||
"s390x": ArchS390X,
|
||||
}
|
||||
specArchToLibseccompArchMap = map[specs.Arch]string{
|
||||
specs.ArchX86: "x86",
|
||||
specs.ArchX86_64: "amd64",
|
||||
specs.ArchX32: "x32",
|
||||
specs.ArchARM: "arm",
|
||||
specs.ArchAARCH64: "arm64",
|
||||
specs.ArchMIPS: "mips",
|
||||
specs.ArchMIPS64: "mips64",
|
||||
specs.ArchMIPS64N32: "mips64n32",
|
||||
specs.ArchMIPSEL: "mipsel",
|
||||
specs.ArchMIPSEL64: "mipsel64",
|
||||
specs.ArchMIPSEL64N32: "mipsel64n32",
|
||||
specs.ArchPPC: "ppc",
|
||||
specs.ArchPPC64: "ppc64",
|
||||
specs.ArchPPC64LE: "ppc64le",
|
||||
specs.ArchS390: "s390",
|
||||
specs.ArchS390X: "s390x",
|
||||
}
|
||||
specArchToSeccompArchMap = map[specs.Arch]Arch{
|
||||
specs.ArchX86: ArchX86,
|
||||
specs.ArchX86_64: ArchX86_64,
|
||||
specs.ArchX32: ArchX32,
|
||||
specs.ArchARM: ArchARM,
|
||||
specs.ArchAARCH64: ArchAARCH64,
|
||||
specs.ArchMIPS: ArchMIPS,
|
||||
specs.ArchMIPS64: ArchMIPS64,
|
||||
specs.ArchMIPS64N32: ArchMIPS64N32,
|
||||
specs.ArchMIPSEL: ArchMIPSEL,
|
||||
specs.ArchMIPSEL64: ArchMIPSEL64,
|
||||
specs.ArchMIPSEL64N32: ArchMIPSEL64N32,
|
||||
specs.ArchPPC: ArchPPC,
|
||||
specs.ArchPPC64: ArchPPC64,
|
||||
specs.ArchPPC64LE: ArchPPC64LE,
|
||||
specs.ArchS390: ArchS390,
|
||||
specs.ArchS390X: ArchS390X,
|
||||
}
|
||||
specActionToSeccompActionMap = map[specs.LinuxSeccompAction]Action{
|
||||
specs.ActKill: ActKill,
|
||||
// TODO: wait for this PR to get merged:
|
||||
// https://github.com/opencontainers/runtime-spec/pull/1064
|
||||
// specs.ActKillProcess ActKillProcess,
|
||||
// specs.ActKillThread ActKillThread,
|
||||
specs.ActErrno: ActErrno,
|
||||
specs.ActTrap: ActTrap,
|
||||
specs.ActAllow: ActAllow,
|
||||
specs.ActTrace: ActTrace,
|
||||
specs.ActLog: ActLog,
|
||||
}
|
||||
specOperatorToSeccompOperatorMap = map[specs.LinuxSeccompOperator]Operator{
|
||||
specs.OpNotEqual: OpNotEqual,
|
||||
specs.OpLessThan: OpLessThan,
|
||||
specs.OpLessEqual: OpLessEqual,
|
||||
specs.OpEqualTo: OpEqualTo,
|
||||
specs.OpGreaterEqual: OpGreaterEqual,
|
||||
specs.OpGreaterThan: OpGreaterThan,
|
||||
specs.OpMaskedEqual: OpMaskedEqual,
|
||||
}
|
||||
)
|
||||
|
||||
// GoArchToSeccompArch converts a runtime.GOARCH to a seccomp `Arch`. The
|
||||
// function returns an error if the architecture conversion is not supported.
|
||||
func GoArchToSeccompArch(goArch string) (Arch, error) {
|
||||
arch, ok := goArchToSeccompArchMap[goArch]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("unsupported go arch provided: %s", goArch)
|
||||
}
|
||||
return arch, nil
|
||||
}
|
||||
|
||||
// specToSeccomp converts a `LinuxSeccomp` spec into a `Seccomp` struct.
|
||||
func specToSeccomp(spec *specs.LinuxSeccomp) (*Seccomp, error) {
|
||||
res := &Seccomp{
|
||||
Syscalls: []*Syscall{},
|
||||
}
|
||||
|
||||
for _, arch := range spec.Architectures {
|
||||
newArch, err := specArchToSeccompArch(arch)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "convert spec arch")
|
||||
}
|
||||
res.Architectures = append(res.Architectures, newArch)
|
||||
}
|
||||
|
||||
// Convert default action
|
||||
newDefaultAction, err := specActionToSeccompAction(spec.DefaultAction)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "convert default action")
|
||||
}
|
||||
res.DefaultAction = newDefaultAction
|
||||
|
||||
// Loop through all syscall blocks and convert them to the internal format
|
||||
for _, call := range spec.Syscalls {
|
||||
newAction, err := specActionToSeccompAction(call.Action)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "convert action")
|
||||
}
|
||||
|
||||
for _, name := range call.Names {
|
||||
newCall := Syscall{
|
||||
Name: name,
|
||||
Action: newAction,
|
||||
ErrnoRet: call.ErrnoRet,
|
||||
Args: []*Arg{},
|
||||
}
|
||||
|
||||
// Loop through all the arguments of the syscall and convert them
|
||||
for _, arg := range call.Args {
|
||||
newOp, err := specOperatorToSeccompOperator(arg.Op)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "convert operator")
|
||||
}
|
||||
|
||||
newArg := Arg{
|
||||
Index: arg.Index,
|
||||
Value: arg.Value,
|
||||
ValueTwo: arg.ValueTwo,
|
||||
Op: newOp,
|
||||
}
|
||||
|
||||
newCall.Args = append(newCall.Args, &newArg)
|
||||
}
|
||||
res.Syscalls = append(res.Syscalls, &newCall)
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// specArchToLibseccompArch converts a spec arch into a libseccomp one.
|
||||
func specArchToLibseccompArch(arch specs.Arch) (string, error) {
|
||||
if res, ok := specArchToLibseccompArchMap[arch]; ok {
|
||||
return res, nil
|
||||
}
|
||||
return "", errors.Errorf(
|
||||
"architecture %q is not valid for libseccomp", arch,
|
||||
)
|
||||
}
|
||||
|
||||
// specArchToSeccompArch converts a spec arch into an internal one.
|
||||
func specArchToSeccompArch(arch specs.Arch) (Arch, error) {
|
||||
if res, ok := specArchToSeccompArchMap[arch]; ok {
|
||||
return res, nil
|
||||
}
|
||||
return "", errors.Errorf("architecture %q is not valid", arch)
|
||||
}
|
||||
|
||||
// specActionToSeccompAction converts a spec action into a seccomp one.
|
||||
func specActionToSeccompAction(action specs.LinuxSeccompAction) (Action, error) {
|
||||
if res, ok := specActionToSeccompActionMap[action]; ok {
|
||||
return res, nil
|
||||
}
|
||||
return "", errors.Errorf(
|
||||
"spec action %q is not valid internal action", action,
|
||||
)
|
||||
}
|
||||
|
||||
// specOperatorToSeccompOperator converts a spec operator into a seccomp one.
|
||||
func specOperatorToSeccompOperator(operator specs.LinuxSeccompOperator) (Operator, error) {
|
||||
if op, ok := specOperatorToSeccompOperatorMap[operator]; ok {
|
||||
return op, nil
|
||||
}
|
||||
return "", errors.Errorf(
|
||||
"spec operator %q is not a valid internal operator", operator,
|
||||
)
|
||||
}
|
|
@ -0,0 +1,237 @@
|
|||
// +build seccomp
|
||||
|
||||
// NOTE: this package has originally been copied from
|
||||
// github.com/opencontainers/runc and modified to work for other use cases
|
||||
|
||||
package seccomp
|
||||
|
||||
import (
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
libseccomp "github.com/seccomp/libseccomp-golang"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// NOTE: this package has originally been copied from
|
||||
// github.com/opencontainers/runc and modified to work for other use cases
|
||||
|
||||
var (
|
||||
// ErrSpecNil is a possible return error from BuildFilter() and occurs if
|
||||
// the provided spec is nil.
|
||||
ErrSpecNil = errors.New("spec is nil")
|
||||
|
||||
// ErrSpecEmpty is a possible return error from BuildFilter() and occurs if
|
||||
// the provided spec has neither a DefaultAction nor any syscalls.
|
||||
ErrSpecEmpty = errors.New("spec contains neither a default action nor any syscalls")
|
||||
)
|
||||
|
||||
// BuildFilter does a basic validation for the provided seccomp profile
|
||||
// string and returns a filter for it.
|
||||
func BuildFilter(spec *specs.LinuxSeccomp) (*libseccomp.ScmpFilter, error) {
|
||||
// Sanity checking to allow consumers to act accordingly
|
||||
if spec == nil {
|
||||
return nil, ErrSpecNil
|
||||
}
|
||||
if spec.DefaultAction == "" && len(spec.Syscalls) == 0 {
|
||||
return nil, ErrSpecEmpty
|
||||
}
|
||||
|
||||
profile, err := specToSeccomp(spec)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "convert spec to seccomp profile")
|
||||
}
|
||||
|
||||
defaultAction, err := toAction(profile.DefaultAction, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "convert default action %s", profile.DefaultAction)
|
||||
}
|
||||
|
||||
filter, err := libseccomp.NewFilter(defaultAction)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "create filter for default action %s", defaultAction)
|
||||
}
|
||||
|
||||
// Add extra architectures
|
||||
for _, arch := range spec.Architectures {
|
||||
libseccompArch, err := specArchToLibseccompArch(arch)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "convert spec arch")
|
||||
}
|
||||
|
||||
scmpArch, err := libseccomp.GetArchFromString(libseccompArch)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "validate Seccomp architecture %s", arch)
|
||||
}
|
||||
|
||||
if err := filter.AddArch(scmpArch); err != nil {
|
||||
return nil, errors.Wrap(err, "add architecture to seccomp filter")
|
||||
}
|
||||
}
|
||||
|
||||
// Unset no new privs bit
|
||||
if err := filter.SetNoNewPrivsBit(false); err != nil {
|
||||
return nil, errors.Wrap(err, "set no new privileges flag")
|
||||
}
|
||||
|
||||
// Add a rule for each syscall
|
||||
for _, call := range profile.Syscalls {
|
||||
if call == nil {
|
||||
return nil, errors.New("encountered nil syscall while initializing seccomp")
|
||||
}
|
||||
|
||||
if err = matchSyscall(filter, call); err != nil {
|
||||
return nil, errors.Wrap(err, "filter matches syscall")
|
||||
}
|
||||
}
|
||||
|
||||
return filter, nil
|
||||
}
|
||||
|
||||
func matchSyscall(filter *libseccomp.ScmpFilter, call *Syscall) error {
|
||||
if call == nil || filter == nil {
|
||||
return errors.New("cannot use nil as syscall to block")
|
||||
}
|
||||
|
||||
if call.Name == "" {
|
||||
return errors.New("empty string is not a valid syscall")
|
||||
}
|
||||
|
||||
// If we can't resolve the syscall, assume it's not supported on this kernel
|
||||
// Ignore it, don't error out
|
||||
callNum, err := libseccomp.GetSyscallFromName(call.Name)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert the call's action to the libseccomp equivalent
|
||||
callAct, err := toAction(call.Action, call.ErrnoRet)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "convert action %s", call.Action)
|
||||
}
|
||||
|
||||
// Unconditional match - just add the rule
|
||||
if len(call.Args) == 0 {
|
||||
if err = filter.AddRule(callNum, callAct); err != nil {
|
||||
return errors.Wrapf(err, "add seccomp filter rule for syscall %s", call.Name)
|
||||
}
|
||||
} else {
|
||||
// Linux system calls can have at most 6 arguments
|
||||
const syscallMaxArguments int = 6
|
||||
|
||||
// If two or more arguments have the same condition,
|
||||
// Revert to old behavior, adding each condition as a separate rule
|
||||
argCounts := make([]uint, syscallMaxArguments)
|
||||
conditions := []libseccomp.ScmpCondition{}
|
||||
|
||||
for _, cond := range call.Args {
|
||||
newCond, err := toCondition(cond)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "create seccomp syscall condition for syscall %s", call.Name)
|
||||
}
|
||||
|
||||
argCounts[cond.Index] += 1
|
||||
|
||||
conditions = append(conditions, newCond)
|
||||
}
|
||||
|
||||
hasMultipleArgs := false
|
||||
for _, count := range argCounts {
|
||||
if count > 1 {
|
||||
hasMultipleArgs = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if hasMultipleArgs {
|
||||
// Revert to old behavior
|
||||
// Add each condition attached to a separate rule
|
||||
for _, cond := range conditions {
|
||||
condArr := []libseccomp.ScmpCondition{cond}
|
||||
|
||||
if err = filter.AddRuleConditional(callNum, callAct, condArr); err != nil {
|
||||
return errors.Wrapf(err, "add seccomp rule for syscall %s", call.Name)
|
||||
}
|
||||
}
|
||||
} else if err = filter.AddRuleConditional(callNum, callAct, conditions); err != nil {
|
||||
// No conditions share same argument
|
||||
// Use new, proper behavior
|
||||
return errors.Wrapf(err, "add seccomp rule for syscall %s", call.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// toAction converts an internal `Action` type to a `libseccomp.ScmpAction`
|
||||
// type.
|
||||
func toAction(act Action, errnoRet *uint) (libseccomp.ScmpAction, error) {
|
||||
switch act {
|
||||
case ActKill:
|
||||
return libseccomp.ActKill, nil
|
||||
case ActKillProcess:
|
||||
return libseccomp.ActKillProcess, nil
|
||||
case ActErrno:
|
||||
if errnoRet != nil {
|
||||
return libseccomp.ActErrno.SetReturnCode(int16(*errnoRet)), nil
|
||||
}
|
||||
return libseccomp.ActErrno.SetReturnCode(int16(unix.EPERM)), nil
|
||||
case ActTrap:
|
||||
return libseccomp.ActTrap, nil
|
||||
case ActAllow:
|
||||
return libseccomp.ActAllow, nil
|
||||
case ActTrace:
|
||||
if errnoRet != nil {
|
||||
return libseccomp.ActTrace.SetReturnCode(int16(*errnoRet)), nil
|
||||
}
|
||||
return libseccomp.ActTrace.SetReturnCode(int16(unix.EPERM)), nil
|
||||
case ActLog:
|
||||
return libseccomp.ActLog, nil
|
||||
default:
|
||||
return libseccomp.ActInvalid, errors.Errorf("invalid action %s", act)
|
||||
}
|
||||
}
|
||||
|
||||
// toCondition converts an internal `Arg` type to a `libseccomp.ScmpCondition`
|
||||
// type.
|
||||
func toCondition(arg *Arg) (cond libseccomp.ScmpCondition, err error) {
|
||||
if arg == nil {
|
||||
return cond, errors.New("cannot convert nil to syscall condition")
|
||||
}
|
||||
|
||||
op, err := toCompareOp(arg.Op)
|
||||
if err != nil {
|
||||
return cond, errors.Wrap(err, "convert compare operator")
|
||||
}
|
||||
|
||||
condition, err := libseccomp.MakeCondition(
|
||||
arg.Index, op, arg.Value, arg.ValueTwo,
|
||||
)
|
||||
if err != nil {
|
||||
return cond, errors.Wrap(err, "make condition")
|
||||
}
|
||||
|
||||
return condition, nil
|
||||
}
|
||||
|
||||
// toCompareOp converts an internal `Operator` type to a
|
||||
// `libseccomp.ScmpCompareOp`.
|
||||
func toCompareOp(op Operator) (libseccomp.ScmpCompareOp, error) {
|
||||
switch op {
|
||||
case OpEqualTo:
|
||||
return libseccomp.CompareEqual, nil
|
||||
case OpNotEqual:
|
||||
return libseccomp.CompareNotEqual, nil
|
||||
case OpGreaterThan:
|
||||
return libseccomp.CompareGreater, nil
|
||||
case OpGreaterEqual:
|
||||
return libseccomp.CompareGreaterEqual, nil
|
||||
case OpLessThan:
|
||||
return libseccomp.CompareLess, nil
|
||||
case OpLessEqual:
|
||||
return libseccomp.CompareLessOrEqual, nil
|
||||
case OpMaskedEqual:
|
||||
return libseccomp.CompareMaskedEqual, nil
|
||||
default:
|
||||
return libseccomp.CompareInvalid, errors.Errorf("invalid operator %s", op)
|
||||
}
|
||||
}
|
|
@ -1,10 +1,8 @@
|
|||
// +build seccomp
|
||||
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Copyright 2013-2018 Docker, Inc.
|
||||
|
||||
package seccomp // import "github.com/seccomp/containers-golang"
|
||||
package seccomp
|
||||
|
||||
import (
|
||||
"syscall"
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
// Copyright 2013-2018 Docker, Inc.
|
||||
|
||||
package seccomp // import "github.com/seccomp/containers-golang"
|
||||
package seccomp
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
@ -13,7 +13,6 @@ import (
|
|||
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
libseccomp "github.com/seccomp/libseccomp-golang"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
//go:generate go run -tags 'seccomp' generate.go
|
||||
|
@ -123,7 +122,7 @@ Loop:
|
|||
}
|
||||
if len(call.Excludes.Caps) > 0 {
|
||||
for _, c := range call.Excludes.Caps {
|
||||
if inSlice(rs.Process.Capabilities.Bounding, c) {
|
||||
if rs != nil && rs.Process != nil && rs.Process.Capabilities != nil && inSlice(rs.Process.Capabilities.Bounding, c) {
|
||||
continue Loop
|
||||
}
|
||||
}
|
||||
|
@ -135,7 +134,7 @@ Loop:
|
|||
}
|
||||
if len(call.Includes.Caps) > 0 {
|
||||
for _, c := range call.Includes.Caps {
|
||||
if !inSlice(rs.Process.Capabilities.Bounding, c) {
|
||||
if rs != nil && rs.Process != nil && rs.Process.Capabilities != nil && !inSlice(rs.Process.Capabilities.Bounding, c) {
|
||||
continue Loop
|
||||
}
|
||||
}
|
||||
|
@ -180,12 +179,5 @@ func createSpecsSyscall(names []string, action Action, args []*Arg, errnoRet *ui
|
|||
|
||||
// IsEnabled returns true if seccomp is enabled for the host.
|
||||
func IsEnabled() bool {
|
||||
// Check if Seccomp is supported, via CONFIG_SECCOMP.
|
||||
if err := unix.Prctl(unix.PR_GET_SECCOMP, 0, 0, 0, 0); err != unix.EINVAL {
|
||||
// Make sure the kernel has CONFIG_SECCOMP_FILTER.
|
||||
if err := unix.Prctl(unix.PR_SET_SECCOMP, unix.SECCOMP_MODE_FILTER, 0, 0, 0); err != unix.EINVAL {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return IsSupported()
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
// Copyright 2013-2018 Docker, Inc.
|
||||
|
||||
package seccomp // import "github.com/seccomp/containers-golang"
|
||||
package seccomp
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
@ -14,11 +14,6 @@ import (
|
|||
|
||||
var errNotSupported = errors.New("seccomp not enabled in this build")
|
||||
|
||||
// DefaultProfile returns a nil pointer on unsupported systems.
|
||||
func DefaultProfile() *Seccomp {
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadProfile returns an error on unsuppored systems
|
||||
func LoadProfile(body string, rs *specs.Spec) (*specs.LinuxSeccomp, error) {
|
||||
return nil, errNotSupported
|
|
@ -0,0 +1,72 @@
|
|||
package seccomp
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
perrors "github.com/pkg/errors"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const statusFilePath = "/proc/self/status"
|
||||
|
||||
// IsSupported returns true if the system has been configured to support
|
||||
// seccomp.
|
||||
func IsSupported() bool {
|
||||
// Since Linux 3.8, the Seccomp field of the /proc/[pid]/status file
|
||||
// provides a method of obtaining the same information, without the risk
|
||||
// that the process is killed; see proc(5).
|
||||
status, err := parseStatusFile(statusFilePath)
|
||||
if err == nil {
|
||||
_, ok := status["Seccomp"]
|
||||
return ok
|
||||
}
|
||||
|
||||
// PR_GET_SECCOMP (since Linux 2.6.23)
|
||||
// Return (as the function result) the secure computing mode of the calling
|
||||
// thread. If the caller is not in secure computing mode, this operation
|
||||
// returns 0; if the caller is in strict secure computing mode, then the
|
||||
// prctl() call will cause a SIGKILL signal to be sent to the process. If
|
||||
// the caller is in filter mode, and this system call is allowed by the
|
||||
// seccomp filters, it returns 2; otherwise, the process is killed with a
|
||||
// SIGKILL signal. This operation is available only if the kernel is
|
||||
// configured with CONFIG_SECCOMP enabled.
|
||||
if err := unix.Prctl(unix.PR_GET_SECCOMP, 0, 0, 0, 0); !errors.Is(err, unix.EINVAL) {
|
||||
// Make sure the kernel has CONFIG_SECCOMP_FILTER.
|
||||
if err := unix.Prctl(unix.PR_SET_SECCOMP, unix.SECCOMP_MODE_FILTER, 0, 0, 0); !errors.Is(err, unix.EINVAL) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// parseStatusFile reads the provided `file` into a map of strings.
|
||||
func parseStatusFile(file string) (map[string]string, error) {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return nil, perrors.Wrapf(err, "open status file %s", file)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
status := make(map[string]string)
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
text := scanner.Text()
|
||||
parts := strings.SplitN(text, ":", 2)
|
||||
|
||||
if len(parts) <= 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
status[strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1])
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, perrors.Wrapf(err, "scan status file %s", file)
|
||||
}
|
||||
|
||||
return status, nil
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package seccomp // import "github.com/seccomp/containers-golang"
|
||||
package seccomp
|
||||
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
@ -27,6 +27,7 @@ type Arch string
|
|||
// Additional architectures permitted to be used for system calls
|
||||
// By default only the native architecture of the kernel is permitted
|
||||
const (
|
||||
ArchNative Arch = "SCMP_ARCH_NATIVE"
|
||||
ArchX86 Arch = "SCMP_ARCH_X86"
|
||||
ArchX86_64 Arch = "SCMP_ARCH_X86_64"
|
||||
ArchX32 Arch = "SCMP_ARCH_X32"
|
||||
|
@ -43,6 +44,9 @@ const (
|
|||
ArchPPC64LE Arch = "SCMP_ARCH_PPC64LE"
|
||||
ArchS390 Arch = "SCMP_ARCH_S390"
|
||||
ArchS390X Arch = "SCMP_ARCH_S390X"
|
||||
ArchPARISC Arch = "SCMP_ARCH_PARISC"
|
||||
ArchPARISC64 Arch = "SCMP_ARCH_PARISC64"
|
||||
ArchRISCV64 Arch = "SCMP_ARCH_RISCV64"
|
||||
)
|
||||
|
||||
// Action taken upon Seccomp rule match
|
||||
|
@ -50,11 +54,19 @@ type Action string
|
|||
|
||||
// Define actions for Seccomp rules
|
||||
const (
|
||||
ActKill Action = "SCMP_ACT_KILL"
|
||||
ActTrap Action = "SCMP_ACT_TRAP"
|
||||
ActErrno Action = "SCMP_ACT_ERRNO"
|
||||
ActTrace Action = "SCMP_ACT_TRACE"
|
||||
ActAllow Action = "SCMP_ACT_ALLOW"
|
||||
// ActKill results in termination of the thread that made the system call.
|
||||
ActKill Action = "SCMP_ACT_KILL"
|
||||
// ActKillProcess results in termination of the entire process.
|
||||
ActKillProcess Action = "SCMP_ACT_KILL_PROCESS"
|
||||
// ActKillThread kills the thread that violated the rule. It is the same as
|
||||
// ActKill. All other threads from the same thread group will continue to
|
||||
// execute.
|
||||
ActKillThread Action = "SCMP_ACT_KILL_THREAD"
|
||||
ActTrap Action = "SCMP_ACT_TRAP"
|
||||
ActErrno Action = "SCMP_ACT_ERRNO"
|
||||
ActTrace Action = "SCMP_ACT_TRACE"
|
||||
ActAllow Action = "SCMP_ACT_ALLOW"
|
||||
ActLog Action = "SCMP_ACT_LOG"
|
||||
)
|
||||
|
||||
// Operator used to match syscall arguments in Seccomp
|
|
@ -0,0 +1,29 @@
|
|||
// +build seccomp
|
||||
|
||||
package seccomp
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// ValidateProfile does a basic validation for the provided seccomp profile
|
||||
// string.
|
||||
func ValidateProfile(content string) error {
|
||||
profile := &Seccomp{}
|
||||
if err := json.Unmarshal([]byte(content), &profile); err != nil {
|
||||
return errors.Wrap(err, "decoding seccomp profile")
|
||||
}
|
||||
|
||||
spec, err := setupSeccomp(profile, nil)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "create seccomp spec")
|
||||
}
|
||||
|
||||
if _, err := BuildFilter(spec); err != nil {
|
||||
return errors.Wrap(err, "build seccomp filter")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package version
|
||||
|
||||
// Version is the version of the build.
|
||||
const Version = "0.20.3"
|
||||
const Version = "0.21.0"
|
||||
|
|
|
@ -106,7 +106,7 @@ lint_task:
|
|||
env:
|
||||
CIRRUS_WORKING_DIR: "/go/src/github.com/containers/storage"
|
||||
container:
|
||||
image: golang:1.13
|
||||
image: golang:1.15
|
||||
modules_cache:
|
||||
fingerprint_script: cat go.sum
|
||||
folder: $GOPATH/pkg/mod
|
||||
|
@ -142,7 +142,7 @@ meta_task:
|
|||
|
||||
vendor_task:
|
||||
container:
|
||||
image: golang:1.14
|
||||
image: golang:1.15
|
||||
modules_cache:
|
||||
fingerprint_script: cat go.sum
|
||||
folder: $GOPATH/pkg/mod
|
||||
|
@ -157,6 +157,6 @@ success_task:
|
|||
- meta
|
||||
- vendor
|
||||
container:
|
||||
image: golang:1.14
|
||||
image: golang:1.15
|
||||
clone_script: 'mkdir -p "$CIRRUS_WORKING_DIR"' # Source code not needed
|
||||
script: /bin/true
|
||||
|
|
|
@ -1 +1 @@
|
|||
1.23.1-dev
|
||||
1.23.3
|
||||
|
|
|
@ -143,10 +143,6 @@ func DirCopy(srcDir, dstDir string, copyMode Mode, copyXattrs bool) error {
|
|||
}
|
||||
|
||||
dstPath := filepath.Join(dstDir, relPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stat, ok := f.Sys().(*syscall.Stat_t)
|
||||
if !ok {
|
||||
return fmt.Errorf("Unable to get raw syscall.Stat_t data for %s", srcPath)
|
||||
|
|
|
@ -51,6 +51,10 @@ func (c *RefCounter) incdec(path string, infoOp func(minfo *minfo)) int {
|
|||
if c.checker.IsMounted(path) {
|
||||
m.count++
|
||||
}
|
||||
} else if !c.checker.IsMounted(path) {
|
||||
// if the unmount was performed outside of this process (e.g. conmon cleanup)
|
||||
//the ref counter would lose track of it. Check if it is still mounted.
|
||||
m.count = 0
|
||||
}
|
||||
infoOp(m)
|
||||
count := m.count
|
||||
|
|
|
@ -274,22 +274,28 @@ func parseOptions(options []string) (*overlayOptions, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key = strings.ToLower(key)
|
||||
switch key {
|
||||
case ".override_kernel_check", "overlay.override_kernel_check", "overlay2.override_kernel_check":
|
||||
trimkey := strings.ToLower(key)
|
||||
trimkey = strings.TrimPrefix(trimkey, "overlay.")
|
||||
trimkey = strings.TrimPrefix(trimkey, "overlay2.")
|
||||
trimkey = strings.TrimPrefix(trimkey, ".")
|
||||
switch trimkey {
|
||||
case "override_kernel_check":
|
||||
logrus.Warnf("overlay: override_kernel_check option was specified, but is no longer necessary")
|
||||
case ".mountopt", "overlay.mountopt", "overlay2.mountopt":
|
||||
case "mountopt":
|
||||
o.mountOptions = val
|
||||
case ".size", "overlay.size", "overlay2.size":
|
||||
case "size":
|
||||
logrus.Debugf("overlay: size=%s", val)
|
||||
size, err := units.RAMInBytes(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
o.quota.Size = uint64(size)
|
||||
case ".imagestore", "overlay.imagestore", "overlay2.imagestore":
|
||||
case "imagestore", "additionalimagestore":
|
||||
logrus.Debugf("overlay: imagestore=%s", val)
|
||||
// Additional read only image stores to use for lower paths
|
||||
if val == "" {
|
||||
continue
|
||||
}
|
||||
for _, store := range strings.Split(val, ",") {
|
||||
store = filepath.Clean(store)
|
||||
if !filepath.IsAbs(store) {
|
||||
|
@ -304,17 +310,17 @@ func parseOptions(options []string) (*overlayOptions, error) {
|
|||
}
|
||||
o.imageStores = append(o.imageStores, store)
|
||||
}
|
||||
case ".mount_program", "overlay.mount_program", "overlay2.mount_program":
|
||||
case "mount_program":
|
||||
logrus.Debugf("overlay: mount_program=%s", val)
|
||||
_, err := os.Stat(val)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("overlay: can't stat program %s: %v", val, err)
|
||||
}
|
||||
o.mountProgram = val
|
||||
case "overlay2.skip_mount_home", "overlay.skip_mount_home", ".skip_mount_home":
|
||||
case "skip_mount_home":
|
||||
logrus.Debugf("overlay: skip_mount_home=%s", val)
|
||||
o.skipMountHome, err = strconv.ParseBool(val)
|
||||
case ".ignore_chown_errors", "overlay2.ignore_chown_errors", "overlay.ignore_chown_errors":
|
||||
case "ignore_chown_errors":
|
||||
logrus.Debugf("overlay: ignore_chown_errors=%s", val)
|
||||
o.ignoreChownErrors, err = strconv.ParseBool(val)
|
||||
if err != nil {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
go 1.15
|
||||
|
||||
module github.com/containers/storage
|
||||
|
||||
require (
|
||||
|
@ -6,10 +8,11 @@ require (
|
|||
github.com/Microsoft/hcsshim v0.8.9
|
||||
github.com/docker/go-units v0.4.0
|
||||
github.com/hashicorp/go-multierror v1.1.0
|
||||
github.com/klauspost/compress v1.10.10
|
||||
github.com/klauspost/compress v1.10.11
|
||||
github.com/klauspost/pgzip v1.2.4
|
||||
github.com/mattn/go-shellwords v1.0.10
|
||||
github.com/mistifyio/go-zfs v2.1.1+incompatible
|
||||
github.com/moby/sys/mountinfo v0.1.3
|
||||
github.com/opencontainers/go-digest v1.0.0
|
||||
github.com/opencontainers/runc v1.0.0-rc91
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2
|
||||
|
@ -25,5 +28,3 @@ require (
|
|||
golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775
|
||||
gotest.tools v2.2.0+incompatible
|
||||
)
|
||||
|
||||
go 1.13
|
||||
|
|
|
@ -62,8 +62,8 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
|
|||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.10.10 h1:a/y8CglcM7gLGYmlbP/stPE5sR3hbhFRUjCBfd/0B3I=
|
||||
github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.10.11 h1:K9z59aO18Aywg2b/WSgBaUX99mHy2BES18Cr5lBKZHk=
|
||||
github.com/klauspost/compress v1.10.11/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/pgzip v1.2.4 h1:TQ7CNpYKovDOmqzRHKxJh0BeaBI7UdQZYc6p7pMQh1A=
|
||||
github.com/klauspost/pgzip v1.2.4/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
|
|
|
@ -4,8 +4,6 @@ import (
|
|||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/storage/pkg/fileutils"
|
||||
)
|
||||
|
||||
// mountError holds an error from a mount or unmount operation
|
||||
|
@ -43,33 +41,6 @@ func (e *mountError) Cause() error {
|
|||
return e.err
|
||||
}
|
||||
|
||||
// GetMounts retrieves a list of mounts for the current running process.
|
||||
func GetMounts() ([]*Info, error) {
|
||||
return parseMountTable()
|
||||
}
|
||||
|
||||
// Mounted determines if a specified mountpoint has been mounted.
|
||||
// On Linux it looks at /proc/self/mountinfo and on Solaris at mnttab.
|
||||
func Mounted(mountpoint string) (bool, error) {
|
||||
entries, err := parseMountTable()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
mountpoint, err = fileutils.ReadSymlinkedPath(mountpoint)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Search the table for the mountpoint
|
||||
for _, e := range entries {
|
||||
if e.Mountpoint == mountpoint {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Mount will mount filesystem according to the specified configuration, on the
|
||||
// condition that the target path is *not* already mounted. Options must be
|
||||
// specified like the mount or fstab unix commands: "opt1=val1,opt2=val2". See
|
||||
|
|
|
@ -1,40 +1,21 @@
|
|||
package mount
|
||||
|
||||
// Info reveals information about a particular mounted filesystem. This
|
||||
// struct is populated from the content in the /proc/<pid>/mountinfo file.
|
||||
type Info struct {
|
||||
// ID is a unique identifier of the mount (may be reused after umount).
|
||||
ID int
|
||||
import (
|
||||
"github.com/containers/storage/pkg/fileutils"
|
||||
"github.com/moby/sys/mountinfo"
|
||||
)
|
||||
|
||||
// Parent indicates the ID of the mount parent (or of self for the top of the
|
||||
// mount tree).
|
||||
Parent int
|
||||
type Info = mountinfo.Info
|
||||
|
||||
// Major indicates one half of the device ID which identifies the device class.
|
||||
Major int
|
||||
|
||||
// Minor indicates one half of the device ID which identifies a specific
|
||||
// instance of device.
|
||||
Minor int
|
||||
|
||||
// Root of the mount within the filesystem.
|
||||
Root string
|
||||
|
||||
// Mountpoint indicates the mount point relative to the process's root.
|
||||
Mountpoint string
|
||||
|
||||
// Opts represents mount-specific options.
|
||||
Opts string
|
||||
|
||||
// Optional represents optional fields.
|
||||
Optional string
|
||||
|
||||
// Fstype indicates the type of filesystem, such as EXT3.
|
||||
Fstype string
|
||||
|
||||
// Source indicates filesystem specific information or "none".
|
||||
Source string
|
||||
|
||||
// VfsOpts represents per super block options.
|
||||
VfsOpts string
|
||||
func GetMounts() ([]*Info, error) {
|
||||
return mountinfo.GetMounts(nil)
|
||||
}
|
||||
|
||||
// Mounted determines if a specified mountpoint has been mounted.
|
||||
func Mounted(mountpoint string) (bool, error) {
|
||||
mountpoint, err := fileutils.ReadSymlinkedPath(mountpoint)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return mountinfo.Mounted(mountpoint)
|
||||
}
|
||||
|
|
|
@ -1,120 +1,5 @@
|
|||
package mount
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
import "github.com/moby/sys/mountinfo"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Parse /proc/self/mountinfo because comparing Dev and ino does not work from
|
||||
// bind mounts
|
||||
func parseMountTable() ([]*Info, error) {
|
||||
f, err := os.Open("/proc/self/mountinfo")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
return parseInfoFile(f)
|
||||
}
|
||||
|
||||
func parseInfoFile(r io.Reader) ([]*Info, error) {
|
||||
s := bufio.NewScanner(r)
|
||||
out := []*Info{}
|
||||
|
||||
for s.Scan() {
|
||||
/*
|
||||
36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
|
||||
(0)(1)(2) (3) (4) (5) (6) (7) (8) (9) (10)
|
||||
|
||||
(0) mount ID: unique identifier of the mount (may be reused after umount)
|
||||
(1) parent ID: ID of parent (or of self for the top of the mount tree)
|
||||
(2) major:minor: value of st_dev for files on filesystem
|
||||
(3) root: root of the mount within the filesystem
|
||||
(4) mount point: mount point relative to the process's root
|
||||
(5) mount options: per mount options
|
||||
(6) optional fields: zero or more fields of the form "tag[:value]"
|
||||
(7) separator: marks the end of the optional fields
|
||||
(8) filesystem type: name of filesystem of the form "type[.subtype]"
|
||||
(9) mount source: filesystem specific information or "none"
|
||||
(10) super options: per super block options
|
||||
*/
|
||||
text := s.Text()
|
||||
fields := strings.Split(text, " ")
|
||||
numFields := len(fields)
|
||||
if numFields < 10 {
|
||||
// should be at least 10 fields
|
||||
return nil, errors.Errorf("Parsing %q failed: not enough fields (%d)", text, numFields)
|
||||
}
|
||||
|
||||
p := &Info{}
|
||||
// ignore any number parsing errors, there should not be any
|
||||
p.ID, _ = strconv.Atoi(fields[0])
|
||||
p.Parent, _ = strconv.Atoi(fields[1])
|
||||
mm := strings.Split(fields[2], ":")
|
||||
if len(mm) != 2 {
|
||||
return nil, fmt.Errorf("Parsing %q failed: unexpected minor:major pair %s", text, mm)
|
||||
}
|
||||
p.Major, _ = strconv.Atoi(mm[0])
|
||||
p.Minor, _ = strconv.Atoi(mm[1])
|
||||
p.Root = fields[3]
|
||||
p.Mountpoint = fields[4]
|
||||
p.Opts = fields[5]
|
||||
|
||||
// one or more optional fields, when a separator (-)
|
||||
i := 6
|
||||
for ; i < numFields && fields[i] != "-"; i++ {
|
||||
switch i {
|
||||
case 6:
|
||||
p.Optional = string(fields[6])
|
||||
default:
|
||||
/* NOTE there might be more optional fields before the separator,
|
||||
such as fields[7] or fields[8], although as of Linux kernel 5.5
|
||||
the only known ones are mount propagation flags in fields[6].
|
||||
The correct behavior is to ignore any unknown optional fields.
|
||||
*/
|
||||
}
|
||||
}
|
||||
if i == numFields {
|
||||
return nil, fmt.Errorf("Parsing %q failed: missing - separator", text)
|
||||
}
|
||||
|
||||
// There should be 3 fields after the separator...
|
||||
if i+4 > numFields {
|
||||
return nil, fmt.Errorf("Parsing %q failed: not enough fields after a - separator", text)
|
||||
}
|
||||
// ... but in Linux <= 3.9 mounting a cifs with spaces in a share name
|
||||
// (like "//serv/My Documents") _may_ end up having a space in the last field
|
||||
// of mountinfo (like "unc=//serv/My Documents"). Since kernel 3.10-rc1, cifs
|
||||
// option unc= is ignored, so a space should not appear. In here we ignore
|
||||
// those "extra" fields caused by extra spaces.
|
||||
p.Fstype = fields[i+1]
|
||||
p.Source = fields[i+2]
|
||||
p.VfsOpts = fields[i+3]
|
||||
|
||||
out = append(out, p)
|
||||
}
|
||||
if err := s.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// PidMountInfo collects the mounts for a specific process ID. If the process
|
||||
// ID is unknown, it is better to use `GetMounts` which will inspect
|
||||
// "/proc/self/mountinfo" instead.
|
||||
func PidMountInfo(pid int) ([]*Info, error) {
|
||||
f, err := os.Open(fmt.Sprintf("/proc/%d/mountinfo", pid))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
return parseInfoFile(f)
|
||||
}
|
||||
var PidMountInfo = mountinfo.PidMountInfo
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
// +build !linux
|
||||
|
||||
package mount
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func parseMountTable() ([]*Info, error) {
|
||||
return nil, fmt.Errorf("mount.parseMountTable is not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
|
@ -2630,6 +2630,9 @@ func (s *store) mount(id string, options drivers.MountOpts) (string, error) {
|
|||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
s.graphLock.Lock()
|
||||
defer s.graphLock.Unlock()
|
||||
rlstore.Lock()
|
||||
defer rlstore.Unlock()
|
||||
if modified, err := rlstore.Modified(); modified || err != nil {
|
||||
|
|
|
@ -43,6 +43,11 @@ func (b *bitWriter) addBits16Clean(value uint16, bits uint8) {
|
|||
func (b *bitWriter) encSymbol(ct cTable, symbol byte) {
|
||||
enc := ct[symbol]
|
||||
b.bitContainer |= uint64(enc.val) << (b.nBits & 63)
|
||||
if false {
|
||||
if enc.nBits == 0 {
|
||||
panic("nbits 0")
|
||||
}
|
||||
}
|
||||
b.nBits += enc.nBits
|
||||
}
|
||||
|
||||
|
@ -54,6 +59,14 @@ func (b *bitWriter) encTwoSymbols(ct cTable, av, bv byte) {
|
|||
sh := b.nBits & 63
|
||||
combined := uint64(encA.val) | (uint64(encB.val) << (encA.nBits & 63))
|
||||
b.bitContainer |= combined << sh
|
||||
if false {
|
||||
if encA.nBits == 0 {
|
||||
panic("nbitsA 0")
|
||||
}
|
||||
if encB.nBits == 0 {
|
||||
panic("nbitsB 0")
|
||||
}
|
||||
}
|
||||
b.nBits += encA.nBits + encB.nBits
|
||||
}
|
||||
|
||||
|
|
|
@ -77,8 +77,11 @@ func compress(in []byte, s *Scratch, compressor func(src []byte) ([]byte, error)
|
|||
// Each symbol present maximum once or too well distributed.
|
||||
return nil, false, ErrIncompressible
|
||||
}
|
||||
|
||||
if s.Reuse == ReusePolicyPrefer && canReuse {
|
||||
if s.Reuse == ReusePolicyMust && !canReuse {
|
||||
// We must reuse, but we can't.
|
||||
return nil, false, ErrIncompressible
|
||||
}
|
||||
if (s.Reuse == ReusePolicyPrefer || s.Reuse == ReusePolicyMust) && canReuse {
|
||||
keepTable := s.cTable
|
||||
keepTL := s.actualTableLog
|
||||
s.cTable = s.prevTable
|
||||
|
@ -90,6 +93,9 @@ func compress(in []byte, s *Scratch, compressor func(src []byte) ([]byte, error)
|
|||
s.OutData = s.Out
|
||||
return s.Out, true, nil
|
||||
}
|
||||
if s.Reuse == ReusePolicyMust {
|
||||
return nil, false, ErrIncompressible
|
||||
}
|
||||
// Do not attempt to re-use later.
|
||||
s.prevTable = s.prevTable[:0]
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ const use8BitTables = true
|
|||
// The size of the input may be larger than the table definition.
|
||||
// Any content remaining after the table definition will be returned.
|
||||
// If no Scratch is provided a new one is allocated.
|
||||
// The returned Scratch can be used for decoding input using this table.
|
||||
// The returned Scratch can be used for encoding or decoding input using this table.
|
||||
func ReadTable(in []byte, s *Scratch) (s2 *Scratch, remain []byte, err error) {
|
||||
s, err = s.prepare(in)
|
||||
if err != nil {
|
||||
|
@ -58,8 +58,8 @@ func ReadTable(in []byte, s *Scratch) (s2 *Scratch, remain []byte, err error) {
|
|||
s.symbolLen = uint16(oSize)
|
||||
in = in[iSize:]
|
||||
} else {
|
||||
if len(in) <= int(iSize) {
|
||||
return s, nil, errors.New("input too small for table")
|
||||
if len(in) < int(iSize) {
|
||||
return s, nil, fmt.Errorf("input too small for table, want %d bytes, have %d", iSize, len(in))
|
||||
}
|
||||
// FSE compressed weights
|
||||
s.fse.DecompressLimit = 255
|
||||
|
@ -138,15 +138,33 @@ func ReadTable(in []byte, s *Scratch) (s2 *Scratch, remain []byte, err error) {
|
|||
if len(s.dt.single) != tSize {
|
||||
s.dt.single = make([]dEntrySingle, tSize)
|
||||
}
|
||||
cTable := s.prevTable
|
||||
if cap(cTable) < maxSymbolValue+1 {
|
||||
cTable = make([]cTableEntry, 0, maxSymbolValue+1)
|
||||
}
|
||||
cTable = cTable[:maxSymbolValue+1]
|
||||
s.prevTable = cTable[:s.symbolLen]
|
||||
s.prevTableLog = s.actualTableLog
|
||||
|
||||
for n, w := range s.huffWeight[:s.symbolLen] {
|
||||
if w == 0 {
|
||||
cTable[n] = cTableEntry{
|
||||
val: 0,
|
||||
nBits: 0,
|
||||
}
|
||||
continue
|
||||
}
|
||||
length := (uint32(1) << w) >> 1
|
||||
d := dEntrySingle{
|
||||
entry: uint16(s.actualTableLog+1-w) | (uint16(n) << 8),
|
||||
}
|
||||
|
||||
rank := &rankStats[w]
|
||||
cTable[n] = cTableEntry{
|
||||
val: uint16(*rank >> (w - 1)),
|
||||
nBits: uint8(d.entry),
|
||||
}
|
||||
|
||||
single := s.dt.single[*rank : *rank+length]
|
||||
for i := range single {
|
||||
single[i] = d
|
||||
|
|
|
@ -55,6 +55,9 @@ const (
|
|||
// ReusePolicyNone will disable re-use of tables.
|
||||
// This is slightly faster than ReusePolicyAllow but may produce larger output.
|
||||
ReusePolicyNone
|
||||
|
||||
// ReusePolicyMust must allow reuse and produce smaller output.
|
||||
ReusePolicyMust
|
||||
)
|
||||
|
||||
type Scratch struct {
|
||||
|
|
|
@ -295,7 +295,7 @@ func (b *blockEnc) encodeRaw(a []byte) {
|
|||
b.output = bh.appendTo(b.output[:0])
|
||||
b.output = append(b.output, a...)
|
||||
if debug {
|
||||
println("Adding RAW block, length", len(a))
|
||||
println("Adding RAW block, length", len(a), "last:", b.last)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -308,7 +308,7 @@ func (b *blockEnc) encodeRawTo(dst, src []byte) []byte {
|
|||
dst = bh.appendTo(dst)
|
||||
dst = append(dst, src...)
|
||||
if debug {
|
||||
println("Adding RAW block, length", len(src))
|
||||
println("Adding RAW block, length", len(src), "last:", b.last)
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
@ -322,7 +322,7 @@ func (b *blockEnc) encodeLits(raw bool) error {
|
|||
// Don't compress extremely small blocks
|
||||
if len(b.literals) < 32 || raw {
|
||||
if debug {
|
||||
println("Adding RAW block, length", len(b.literals))
|
||||
println("Adding RAW block, length", len(b.literals), "last:", b.last)
|
||||
}
|
||||
bh.setType(blockTypeRaw)
|
||||
b.output = bh.appendTo(b.output)
|
||||
|
@ -349,7 +349,7 @@ func (b *blockEnc) encodeLits(raw bool) error {
|
|||
switch err {
|
||||
case huff0.ErrIncompressible:
|
||||
if debug {
|
||||
println("Adding RAW block, length", len(b.literals))
|
||||
println("Adding RAW block, length", len(b.literals), "last:", b.last)
|
||||
}
|
||||
bh.setType(blockTypeRaw)
|
||||
b.output = bh.appendTo(b.output)
|
||||
|
|
|
@ -190,6 +190,7 @@ func (e *Encoder) nextBlock(final bool) error {
|
|||
s.filling = s.filling[:0]
|
||||
s.headerWritten = true
|
||||
s.fullFrameWritten = true
|
||||
s.eofWritten = true
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
@ -175,7 +176,18 @@
|
|||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2018-2019 github.com/seccomp authors.
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
|
@ -0,0 +1,3 @@
|
|||
module github.com/moby/sys/mountinfo
|
||||
|
||||
go 1.14
|
|
@ -0,0 +1,67 @@
|
|||
package mountinfo
|
||||
|
||||
import "io"
|
||||
|
||||
// GetMounts retrieves a list of mounts for the current running process,
|
||||
// with an optional filter applied (use nil for no filter).
|
||||
func GetMounts(f FilterFunc) ([]*Info, error) {
|
||||
return parseMountTable(f)
|
||||
}
|
||||
|
||||
// GetMountsFromReader retrieves a list of mounts from the
|
||||
// reader provided, with an optional filter applied (use nil
|
||||
// for no filter). This can be useful in tests or benchmarks
|
||||
// that provide a fake mountinfo data.
|
||||
func GetMountsFromReader(reader io.Reader, f FilterFunc) ([]*Info, error) {
|
||||
return parseInfoFile(reader, f)
|
||||
}
|
||||
|
||||
// Mounted determines if a specified mountpoint has been mounted.
|
||||
// On Linux it looks at /proc/self/mountinfo.
|
||||
func Mounted(mountpoint string) (bool, error) {
|
||||
entries, err := GetMounts(SingleEntryFilter(mountpoint))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return len(entries) > 0, nil
|
||||
}
|
||||
|
||||
// Info reveals information about a particular mounted filesystem. This
|
||||
// struct is populated from the content in the /proc/<pid>/mountinfo file.
|
||||
type Info struct {
|
||||
// ID is a unique identifier of the mount (may be reused after umount).
|
||||
ID int
|
||||
|
||||
// Parent indicates the ID of the mount parent (or of self for the top of the
|
||||
// mount tree).
|
||||
Parent int
|
||||
|
||||
// Major indicates one half of the device ID which identifies the device class.
|
||||
Major int
|
||||
|
||||
// Minor indicates one half of the device ID which identifies a specific
|
||||
// instance of device.
|
||||
Minor int
|
||||
|
||||
// Root of the mount within the filesystem.
|
||||
Root string
|
||||
|
||||
// Mountpoint indicates the mount point relative to the process's root.
|
||||
Mountpoint string
|
||||
|
||||
// Opts represents mount-specific options.
|
||||
Opts string
|
||||
|
||||
// Optional represents optional fields.
|
||||
Optional string
|
||||
|
||||
// Fstype indicates the type of filesystem, such as EXT3.
|
||||
Fstype string
|
||||
|
||||
// Source indicates filesystem specific information or "none".
|
||||
Source string
|
||||
|
||||
// VfsOpts represents per super block options.
|
||||
VfsOpts string
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package mountinfo
|
||||
|
||||
import "strings"
|
||||
|
||||
// FilterFunc is a type defining a callback function for GetMount(),
|
||||
// used to filter out mountinfo entries we're not interested in,
|
||||
// and/or stop further processing if we found what we wanted.
|
||||
//
|
||||
// It takes a pointer to the Info struct (not fully populated,
|
||||
// currently only Mountpoint, Fstype, Source, and (on Linux)
|
||||
// VfsOpts are filled in), and returns two booleans:
|
||||
//
|
||||
// - skip: true if the entry should be skipped
|
||||
// - stop: true if parsing should be stopped after the entry
|
||||
type FilterFunc func(*Info) (skip, stop bool)
|
||||
|
||||
// PrefixFilter discards all entries whose mount points
|
||||
// do not start with a specific prefix
|
||||
func PrefixFilter(prefix string) FilterFunc {
|
||||
return func(m *Info) (bool, bool) {
|
||||
skip := !strings.HasPrefix(m.Mountpoint, prefix)
|
||||
return skip, false
|
||||
}
|
||||
}
|
||||
|
||||
// SingleEntryFilter looks for a specific entry
|
||||
func SingleEntryFilter(mp string) FilterFunc {
|
||||
return func(m *Info) (bool, bool) {
|
||||
if m.Mountpoint == mp {
|
||||
return false, true // don't skip, stop now
|
||||
}
|
||||
return true, false // skip, keep going
|
||||
}
|
||||
}
|
||||
|
||||
// ParentsFilter returns all entries whose mount points
|
||||
// can be parents of a path specified, discarding others.
|
||||
//
|
||||
// For example, given `/var/lib/docker/something`, entries
|
||||
// like `/var/lib/docker`, `/var` and `/` are returned.
|
||||
func ParentsFilter(path string) FilterFunc {
|
||||
return func(m *Info) (bool, bool) {
|
||||
skip := !strings.HasPrefix(path, m.Mountpoint)
|
||||
return skip, false
|
||||
}
|
||||
}
|
||||
|
||||
// FstypeFilter returns all entries that match provided fstype(s).
|
||||
func FstypeFilter(fstype ...string) FilterFunc {
|
||||
return func(m *Info) (bool, bool) {
|
||||
for _, t := range fstype {
|
||||
if m.Fstype == t {
|
||||
return false, false // don't skeep, keep going
|
||||
}
|
||||
}
|
||||
return true, false // skip, keep going
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package mount
|
||||
package mountinfo
|
||||
|
||||
/*
|
||||
#include <sys/param.h>
|
||||
|
@ -13,9 +13,8 @@ import (
|
|||
"unsafe"
|
||||
)
|
||||
|
||||
// Parse /proc/self/mountinfo because comparing Dev and ino does not work from
|
||||
// bind mounts.
|
||||
func parseMountTable() ([]*Info, error) {
|
||||
// parseMountTable returns information about mounted filesystems
|
||||
func parseMountTable(filter FilterFunc) ([]*Info, error) {
|
||||
var rawEntries *C.struct_statfs
|
||||
|
||||
count := int(C.getmntinfo(&rawEntries, C.MNT_WAIT))
|
||||
|
@ -32,10 +31,23 @@ func parseMountTable() ([]*Info, error) {
|
|||
var out []*Info
|
||||
for _, entry := range entries {
|
||||
var mountinfo Info
|
||||
var skip, stop bool
|
||||
mountinfo.Mountpoint = C.GoString(&entry.f_mntonname[0])
|
||||
mountinfo.Source = C.GoString(&entry.f_mntfromname[0])
|
||||
mountinfo.Fstype = C.GoString(&entry.f_fstypename[0])
|
||||
mountinfo.Source = C.GoString(&entry.f_mntfromname[0])
|
||||
|
||||
if filter != nil {
|
||||
// filter out entries we're not interested in
|
||||
skip, stop = filter(&mountinfo)
|
||||
if skip {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
out = append(out, &mountinfo)
|
||||
if stop {
|
||||
break
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
// +build go1.13
|
||||
|
||||
package mountinfo
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func parseInfoFile(r io.Reader, filter FilterFunc) ([]*Info, error) {
|
||||
s := bufio.NewScanner(r)
|
||||
out := []*Info{}
|
||||
var err error
|
||||
for s.Scan() {
|
||||
if err = s.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
/*
|
||||
See http://man7.org/linux/man-pages/man5/proc.5.html
|
||||
|
||||
36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
|
||||
(1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11)
|
||||
|
||||
(1) mount ID: unique identifier of the mount (may be reused after umount)
|
||||
(2) parent ID: ID of parent (or of self for the top of the mount tree)
|
||||
(3) major:minor: value of st_dev for files on filesystem
|
||||
(4) root: root of the mount within the filesystem
|
||||
(5) mount point: mount point relative to the process's root
|
||||
(6) mount options: per mount options
|
||||
(7) optional fields: zero or more fields of the form "tag[:value]"
|
||||
(8) separator: marks the end of the optional fields
|
||||
(9) filesystem type: name of filesystem of the form "type[.subtype]"
|
||||
(10) mount source: filesystem specific information or "none"
|
||||
(11) super options: per super block options
|
||||
|
||||
In other words, we have:
|
||||
* 6 mandatory fields (1)..(6)
|
||||
* 0 or more optional fields (7)
|
||||
* a separator field (8)
|
||||
* 3 mandatory fields (9)..(11)
|
||||
*/
|
||||
|
||||
text := s.Text()
|
||||
fields := strings.Split(text, " ")
|
||||
numFields := len(fields)
|
||||
if numFields < 10 {
|
||||
// should be at least 10 fields
|
||||
return nil, fmt.Errorf("Parsing '%s' failed: not enough fields (%d)", text, numFields)
|
||||
}
|
||||
|
||||
// separator field
|
||||
sepIdx := numFields - 4
|
||||
// In Linux <= 3.9 mounting a cifs with spaces in a share
|
||||
// name (like "//srv/My Docs") _may_ end up having a space
|
||||
// in the last field of mountinfo (like "unc=//serv/My Docs").
|
||||
// Since kernel 3.10-rc1, cifs option "unc=" is ignored,
|
||||
// so spaces should not appear.
|
||||
//
|
||||
// Check for a separator, and work around the spaces bug
|
||||
for fields[sepIdx] != "-" {
|
||||
sepIdx--
|
||||
if sepIdx == 5 {
|
||||
return nil, fmt.Errorf("Parsing '%s' failed: missing - separator", text)
|
||||
}
|
||||
}
|
||||
|
||||
p := &Info{}
|
||||
|
||||
// Fill in the fields that a filter might check
|
||||
p.Mountpoint, err = strconv.Unquote(`"` + fields[4] + `"`)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Parsing '%s' failed: unable to unquote mount point field: %w", fields[4], err)
|
||||
}
|
||||
p.Fstype = fields[sepIdx+1]
|
||||
p.Source = fields[sepIdx+2]
|
||||
p.VfsOpts = fields[sepIdx+3]
|
||||
|
||||
// Run a filter soon so we can skip parsing/adding entries
|
||||
// the caller is not interested in
|
||||
var skip, stop bool
|
||||
if filter != nil {
|
||||
skip, stop = filter(p)
|
||||
if skip {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in the rest of the fields
|
||||
|
||||
// ignore any numbers parsing errors, as there should not be any
|
||||
p.ID, _ = strconv.Atoi(fields[0])
|
||||
p.Parent, _ = strconv.Atoi(fields[1])
|
||||
mm := strings.Split(fields[2], ":")
|
||||
if len(mm) != 2 {
|
||||
return nil, fmt.Errorf("Parsing '%s' failed: unexpected minor:major pair %s", text, mm)
|
||||
}
|
||||
p.Major, _ = strconv.Atoi(mm[0])
|
||||
p.Minor, _ = strconv.Atoi(mm[1])
|
||||
|
||||
p.Root, err = strconv.Unquote(`"` + fields[3] + `"`)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Parsing '%s' failed: unable to unquote root field: %w", fields[3], err)
|
||||
}
|
||||
|
||||
p.Opts = fields[5]
|
||||
|
||||
// zero or more optional fields
|
||||
switch {
|
||||
case sepIdx == 6:
|
||||
// zero, do nothing
|
||||
case sepIdx == 7:
|
||||
p.Optional = fields[6]
|
||||
default:
|
||||
p.Optional = strings.Join(fields[6:sepIdx-1], " ")
|
||||
}
|
||||
|
||||
out = append(out, p)
|
||||
if stop {
|
||||
break
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Parse /proc/self/mountinfo because comparing Dev and ino does not work from
|
||||
// bind mounts
|
||||
func parseMountTable(filter FilterFunc) ([]*Info, error) {
|
||||
f, err := os.Open("/proc/self/mountinfo")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
return parseInfoFile(f, filter)
|
||||
}
|
||||
|
||||
// PidMountInfo collects the mounts for a specific process ID. If the process
|
||||
// ID is unknown, it is better to use `GetMounts` which will inspect
|
||||
// "/proc/self/mountinfo" instead.
|
||||
func PidMountInfo(pid int) ([]*Info, error) {
|
||||
f, err := os.Open(fmt.Sprintf("/proc/%d/mountinfo", pid))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
return parseInfoFile(f, nil)
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
// +build !windows,!linux,!freebsd freebsd,!cgo
|
||||
|
||||
package mountinfo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func parseMountTable(_ FilterFunc) ([]*Info, error) {
|
||||
return nil, fmt.Errorf("mount.parseMountTable is not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
|
||||
func parseInfoFile(_ io.Reader, f FilterFunc) ([]*Info, error) {
|
||||
return parseMountTable(f)
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package mountinfo
|
||||
|
||||
import "io"
|
||||
|
||||
func parseMountTable(_ FilterFunc) ([]*Info, error) {
|
||||
// Do NOT return an error!
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func parseInfoFile(_ io.Reader, f FilterFunc) ([]*Info, error) {
|
||||
return parseMountTable(f)
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
*.orig
|
||||
generate
|
|
@ -1,32 +0,0 @@
|
|||
export GO111MODULE=off
|
||||
|
||||
TAGS ?= seccomp
|
||||
BUILDFLAGS := -tags "$(AUTOTAGS) $(TAGS)"
|
||||
GO := go
|
||||
PACKAGE := github.com/seccomp/containers-golang
|
||||
|
||||
sources := $(wildcard *.go)
|
||||
|
||||
.PHONY: seccomp.json
|
||||
seccomp.json: $(sources)
|
||||
$(GO) build -compiler gc $(BUILDFLAGS) ./cmd/generate.go
|
||||
$(GO) build -compiler gc ./cmd/generate.go
|
||||
$(GO) run ${BUILDFLAGS} cmd/generate.go
|
||||
|
||||
all: seccomp.json
|
||||
|
||||
.PHONY: test-unit
|
||||
test-unit:
|
||||
$(GO) test -v $(BUILDFLAGS) $(shell $(GO) list ./... | grep -v ^$(PACKAGE)/vendor)
|
||||
$(GO) test -v $(shell $(GO) list ./... | grep -v ^$(PACKAGE)/vendor)
|
||||
|
||||
.PHONY: vendor
|
||||
vendor:
|
||||
export GO111MODULE=on \
|
||||
$(GO) mod tidy && \
|
||||
$(GO) mod vendor && \
|
||||
$(GO) mod verify
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f generate
|
|
@ -1,29 +0,0 @@
|
|||
# containers-golang
|
||||
|
||||
[](https://circleci.com/gh/seccomp/containers-golang)
|
||||
|
||||
`containers-golang` is a set of Go libraries used by container runtimes to generate and load seccomp mappings into the kernel.
|
||||
|
||||
seccomp (short for secure computing mode) is a BPF based syscall filter language and present a more conventional function-call based filtering interface that should be familiar to, and easily adopted by, application developers.
|
||||
|
||||
## Building
|
||||
make - Generates seccomp.json file, which contains the whitelisted syscalls that can be used by container runtime engines like [CRI-O][cri-o], [Buildah][buildah], [Podman][podman] and [Docker][docker], and container runtimes like OCI [Runc][runc] to controll the syscalls available to containers.
|
||||
|
||||
### Supported build tags
|
||||
|
||||
`seccomp`
|
||||
|
||||
## Contributing
|
||||
|
||||
When developing this library, please use `make` (or `make … BUILDTAGS=…`) to take advantage of the tests and validation.
|
||||
|
||||
## Contact
|
||||
|
||||
- IRC: #[containers](irc://irc.freenode.net:6667/#containers) on freenode.net
|
||||
|
||||
[cri-o]: https://github.com/kubernetes-incubator/cri-o/pulls
|
||||
[buildah]: https://github.com/projectatomic/buildah
|
||||
[podman]: https://github.com/projectatomic/podman
|
||||
[docker]: https://github.com/docker/docker
|
||||
[runc]: https://github.com/opencontainers/runc
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
package seccomp // import "github.com/seccomp/containers-golang"
|
||||
|
||||
import "fmt"
|
||||
|
||||
var goArchToSeccompArchMap = map[string]Arch{
|
||||
"386": ArchX86,
|
||||
"amd64": ArchX86_64,
|
||||
"amd64p32": ArchX32,
|
||||
"arm": ArchARM,
|
||||
"arm64": ArchAARCH64,
|
||||
"mips": ArchMIPS,
|
||||
"mips64": ArchMIPS64,
|
||||
"mips64le": ArchMIPSEL64,
|
||||
"mips64p32": ArchMIPS64N32,
|
||||
"mips64p32le": ArchMIPSEL64N32,
|
||||
"mipsle": ArchMIPSEL,
|
||||
"ppc": ArchPPC,
|
||||
"ppc64": ArchPPC64,
|
||||
"ppc64le": ArchPPC64LE,
|
||||
"s390": ArchS390,
|
||||
"s390x": ArchS390X,
|
||||
}
|
||||
|
||||
// GoArchToSeccompArch converts a runtime.GOARCH to a seccomp `Arch`. The
|
||||
// function returns an error if the architecture conversion is not supported.
|
||||
func GoArchToSeccompArch(goArch string) (Arch, error) {
|
||||
arch, ok := goArchToSeccompArchMap[goArch]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("unsupported go arch provided: %s", goArch)
|
||||
}
|
||||
return arch, nil
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
module github.com/seccomp/containers-golang
|
||||
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/blang/semver v3.5.1+incompatible // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.0 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20200710190001-3e4195d92445
|
||||
github.com/opencontainers/runtime-tools v0.9.0
|
||||
github.com/opencontainers/selinux v1.6.0 // indirect
|
||||
github.com/seccomp/libseccomp-golang v0.9.1
|
||||
github.com/sirupsen/logrus v1.6.0 // indirect
|
||||
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666
|
||||
)
|
|
@ -1,66 +0,0 @@
|
|||
github.com/blang/semver v1.1.0 h1:ol1rO7QQB5uy7umSNV7VAmLugfLRD+17sYJujRNYPhg=
|
||||
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
|
||||
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
|
||||
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/opencontainers/runtime-spec v0.1.2-0.20190618234442-a950415649c7 h1:Dliu5QO+4JYWu/yMshaMU7G3JN2POGpwjJN7gjy10Go=
|
||||
github.com/opencontainers/runtime-spec v0.1.2-0.20190618234442-a950415649c7/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-spec v1.0.1 h1:wY4pOY8fBdSIvs9+IDHC55thBuEulhzfSgKeC1yFvzQ=
|
||||
github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-spec v1.0.2-0.20191007145322-19e92ca81777 h1:7CkKaORyxoXsM8z56r+M0wf3uCpVGVqx4CWq7oJ/4DY=
|
||||
github.com/opencontainers/runtime-spec v1.0.2-0.20191007145322-19e92ca81777/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2 h1:9mv9SC7GWmRWE0J/+oD8w3GsN2KYGKtg6uwLN7hfP5E=
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20200710190001-3e4195d92445 h1:y8cfsJRmn8g3VkM4IDpusKSgMUZEXhudm/BuYANLozE=
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20200710190001-3e4195d92445/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-tools v0.9.0 h1:FYgwVsKRI/H9hU32MJ/4MLOzXWodKK5zsQavY8NPMkU=
|
||||
github.com/opencontainers/runtime-tools v0.9.0/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
|
||||
github.com/opencontainers/selinux v1.2.2 h1:Kx9J6eDG5/24A6DtUquGSpJQ+m2MUTahn4FtGEe8bFg=
|
||||
github.com/opencontainers/selinux v1.2.2/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs=
|
||||
github.com/opencontainers/selinux v1.3.0 h1:xsI95WzPZu5exzA6JzkLSfdr/DilzOhCJOqGe5TgR0g=
|
||||
github.com/opencontainers/selinux v1.3.0/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs=
|
||||
github.com/opencontainers/selinux v1.6.0 h1:+bIAS/Za3q5FTwWym4fTB0vObnfCf3G/NC7K6Jx62mY=
|
||||
github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/seccomp/libseccomp-golang v0.9.1 h1:NJjM5DNFOs0s3kYE1WUOr6G8V97sdt46rlXTMfXGWBo=
|
||||
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
|
||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 h1:b6uOv7YOFK0TYG7HtkIgExQo+2RdLuwRft63jn2HWj8=
|
||||
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243 h1:R43TdZy32XXSXjJn7M/HhALJ9imq6ztLnChfYJpVDnM=
|
||||
github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v1.1.0 h1:ngVtJC9TY/lg0AA/1k48FYhBrhRoFlEmWzsehpNAaZg=
|
||||
github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190921190940-14da1ac737cc h1:EinpED/Eb9JUgDi6pkoFjw+tz69c3lHUZr2+Va84S0w=
|
||||
golang.org/x/sys v0.0.0-20190921190940-14da1ac737cc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666 h1:gVCS+QOncANNPlmlO1AhlU3oxs4V9z+gTtPwIk3p2N8=
|
||||
golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
@ -0,0 +1,37 @@
|
|||
# Travis CI configuration for libseccomp-golang
|
||||
|
||||
# https://docs.travis-ci.com/user/reference/bionic
|
||||
# https://wiki.ubuntu.com/Releases
|
||||
|
||||
dist: bionic
|
||||
sudo: false
|
||||
|
||||
notifications:
|
||||
email:
|
||||
on_success: always
|
||||
on_failure: always
|
||||
|
||||
arch:
|
||||
- amd64
|
||||
|
||||
os:
|
||||
- linux
|
||||
|
||||
language: go
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- build-essential
|
||||
# TODO: use the main libseccomp git repo instead of a distro package
|
||||
- libseccomp2
|
||||
- libseccomp-dev
|
||||
|
||||
install:
|
||||
- go get -u golang.org/x/lint/golint
|
||||
|
||||
# run all of the tests independently, fail if any of the tests error
|
||||
script:
|
||||
- make check-syntax
|
||||
- make lint
|
||||
- make check
|
|
@ -8,11 +8,11 @@ to the rules described here, but by following the instructions below you
|
|||
should have a much easier time getting your work merged with the upstream
|
||||
project.
|
||||
|
||||
* Test Your Code
|
||||
## Test Your Code Using Existing Tests
|
||||
|
||||
There are two possible tests you can run to verify your code. The first test
|
||||
is used to check the formatting and coding style of your changes, you can run
|
||||
the test with the following command:
|
||||
There are two possible tests you can run to verify your code. The first
|
||||
test is used to check the formatting and coding style of your changes, you
|
||||
can run the test with the following command:
|
||||
|
||||
# make check-syntax
|
||||
|
||||
|
@ -27,30 +27,13 @@ with the following command:
|
|||
|
||||
... if there are any faults or errors they will be displayed.
|
||||
|
||||
* Generate the Patch(es)
|
||||
## Add New Tests for New Functionality
|
||||
|
||||
Depending on how you decided to work with the libseccomp code base and what
|
||||
tools you are using there are different ways to generate your patch(es).
|
||||
However, regardless of what tools you use, you should always generate your
|
||||
patches using the "unified" diff/patch format and the patches should always
|
||||
apply to the libseccomp source tree using the following command from the top
|
||||
directory of the libseccomp sources:
|
||||
Any submissions which add functionality, or significantly change the existing
|
||||
code, should include additional tests to verify the proper operation of the
|
||||
proposed changes.
|
||||
|
||||
# patch -p1 < changes.patch
|
||||
|
||||
If you are not using git, stacked git (stgit), or some other tool which can
|
||||
generate patch files for you automatically, you may find the following command
|
||||
helpful in generating patches, where "libseccomp.orig/" is the unmodified
|
||||
source code directory and "libseccomp/" is the source code directory with your
|
||||
changes:
|
||||
|
||||
# diff -purN libseccomp-golang.orig/ libseccomp-golang/
|
||||
|
||||
When in doubt please generate your patch and try applying it to an unmodified
|
||||
copy of the libseccomp sources; if it fails for you, it will fail for the rest
|
||||
of us.
|
||||
|
||||
* Explain Your Work
|
||||
## Explain Your Work
|
||||
|
||||
At the top of every patch you should include a description of the problem you
|
||||
are trying to solve, how you solved it, and why you chose the solution you
|
||||
|
@ -59,7 +42,7 @@ if you can describe/include a reproducer for the problem in the description as
|
|||
well as instructions on how to test for the bug and verify that it has been
|
||||
fixed.
|
||||
|
||||
* Sign Your Work
|
||||
## Sign Your Work
|
||||
|
||||
The sign-off is a simple line at the end of the patch description, which
|
||||
certifies that you wrote it or otherwise have the right to pass it on as an
|
||||
|
@ -97,16 +80,49 @@ your real name, saying:
|
|||
|
||||
Signed-off-by: Random J Developer <random@developer.example.org>
|
||||
|
||||
* Email Your Patch(es)
|
||||
You can add this to your commit description in `git` with `git commit -s`
|
||||
|
||||
## Post Your Patches Upstream
|
||||
|
||||
The libseccomp project accepts both GitHub pull requests and patches sent via
|
||||
the mailing list. GitHub pull requests are preferred. This sections below
|
||||
explain how to contribute via either method. Please read each step and perform
|
||||
all steps that apply to your chosen contribution method.
|
||||
|
||||
### Submitting via Email
|
||||
|
||||
Depending on how you decided to work with the libseccomp code base and what
|
||||
tools you are using there are different ways to generate your patch(es).
|
||||
However, regardless of what tools you use, you should always generate your
|
||||
patches using the "unified" diff/patch format and the patches should always
|
||||
apply to the libseccomp source tree using the following command from the top
|
||||
directory of the libseccomp sources:
|
||||
|
||||
# patch -p1 < changes.patch
|
||||
|
||||
If you are not using git, stacked git (stgit), or some other tool which can
|
||||
generate patch files for you automatically, you may find the following command
|
||||
helpful in generating patches, where "libseccomp.orig/" is the unmodified
|
||||
source code directory and "libseccomp/" is the source code directory with your
|
||||
changes:
|
||||
|
||||
# diff -purN libseccomp.orig/ libseccomp/
|
||||
|
||||
When in doubt please generate your patch and try applying it to an unmodified
|
||||
copy of the libseccomp sources; if it fails for you, it will fail for the rest
|
||||
of us.
|
||||
|
||||
Finally, you will need to email your patches to the mailing list so they can
|
||||
be reviewed and potentially merged into the main libseccomp-golang repository.
|
||||
When sending patches to the mailing list it is important to send your email in
|
||||
text form, no HTML mail please, and ensure that your email client does not
|
||||
mangle your patches. It should be possible to save your raw email to disk and
|
||||
apply it directly to the libseccomp source code; if that fails then you likely
|
||||
have a problem with your email client. When in doubt try a test first by
|
||||
sending yourself an email with your patch and attempting to apply the emailed
|
||||
patch to the libseccomp-golang repository; if it fails for you, it will fail
|
||||
for the rest of us trying to test your patch and include it in the main
|
||||
libseccomp-golang repository.
|
||||
be reviewed and potentially merged into the main libseccomp repository. When
|
||||
sending patches to the mailing list it is important to send your email in text
|
||||
form, no HTML mail please, and ensure that your email client does not mangle
|
||||
your patches. It should be possible to save your raw email to disk and apply
|
||||
it directly to the libseccomp source code; if that fails then you likely have
|
||||
a problem with your email client. When in doubt try a test first by sending
|
||||
yourself an email with your patch and attempting to apply the emailed patch to
|
||||
the libseccomp repository; if it fails for you, it will fail for the rest of
|
||||
us trying to test your patch and include it in the main libseccomp repository.
|
||||
|
||||
### Submitting via GitHub
|
||||
|
||||
See [this guide](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request) if you've never done this before.
|
|
@ -1,7 +1,8 @@
|
|||
libseccomp-golang: Go Language Bindings for the libseccomp Project
|
||||

|
||||
===============================================================================
|
||||
https://github.com/seccomp/libseccomp-golang
|
||||
https://github.com/seccomp/libseccomp
|
||||
|
||||
[](https://travis-ci.org/seccomp/libseccomp-golang)
|
||||
|
||||
The libseccomp library provides an easy to use, platform independent, interface
|
||||
to the Linux Kernel's syscall filtering mechanism. The libseccomp API is
|
||||
|
@ -12,40 +13,39 @@ be familiar to, and easily adopted by, application developers.
|
|||
The libseccomp-golang library provides a Go based interface to the libseccomp
|
||||
library.
|
||||
|
||||
* Online Resources
|
||||
## Online Resources
|
||||
|
||||
The library source repository currently lives on GitHub at the following URLs:
|
||||
|
||||
-> https://github.com/seccomp/libseccomp-golang
|
||||
-> https://github.com/seccomp/libseccomp
|
||||
* https://github.com/seccomp/libseccomp-golang
|
||||
* https://github.com/seccomp/libseccomp
|
||||
|
||||
The project mailing list is currently hosted on Google Groups at the URL below,
|
||||
please note that a Google account is not required to subscribe to the mailing
|
||||
list.
|
||||
|
||||
-> https://groups.google.com/d/forum/libseccomp
|
||||
* https://groups.google.com/d/forum/libseccomp
|
||||
|
||||
Documentation is also available at:
|
||||
|
||||
-> https://godoc.org/github.com/seccomp/libseccomp-golang
|
||||
* https://godoc.org/github.com/seccomp/libseccomp-golang
|
||||
|
||||
* Installing the package
|
||||
## Installing the package
|
||||
|
||||
The libseccomp-golang bindings require at least Go v1.2.1 and GCC v4.8.4;
|
||||
earlier versions may yield unpredictable results. If you meet these
|
||||
requirements you can install this package using the command below:
|
||||
|
||||
$ go get github.com/seccomp/libseccomp-golang
|
||||
# go get github.com/seccomp/libseccomp-golang
|
||||
|
||||
* Testing the Library
|
||||
## Testing the Library
|
||||
|
||||
A number of tests and lint related recipes are provided in the Makefile, if
|
||||
you want to run the standard regression tests, you can excute the following:
|
||||
|
||||
$ make check
|
||||
# make check
|
||||
|
||||
In order to execute the 'make lint' recipe the 'golint' tool is needed, it
|
||||
can be found at:
|
||||
|
||||
-> https://github.com/golang/lint
|
||||
|
||||
* https://github.com/golang/lint
|
|
@ -0,0 +1,3 @@
|
|||
module github.com/seccomp/libseccomp-golang
|
||||
|
||||
go 1.14
|
|
@ -0,0 +1,23 @@
|
|||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7 h1:EBZoQjiKKPaLbPrbpssUfuHtwM6KV/vb4U85g/cigFY=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200313205530-4303120df7d8 h1:gkI/wGGwpcG5W4hLCzZNGxA4wzWBGGDStRI1MrjDl2Q=
|
||||
golang.org/x/tools v0.0.0-20200313205530-4303120df7d8/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
@ -125,7 +125,8 @@ const (
|
|||
// ActInvalid is a placeholder to ensure uninitialized ScmpAction
|
||||
// variables are invalid
|
||||
ActInvalid ScmpAction = iota
|
||||
// ActKill kills the process
|
||||
// ActKill kills the thread that violated the rule. It is the same as ActKillThread.
|
||||
// All other threads from the same thread group will continue to execute.
|
||||
ActKill ScmpAction = iota
|
||||
// ActTrap throws SIGSYS
|
||||
ActTrap ScmpAction = iota
|
||||
|
@ -141,6 +142,14 @@ const (
|
|||
// This action is only usable when libseccomp API level 3 or higher is
|
||||
// supported.
|
||||
ActLog ScmpAction = iota
|
||||
// ActKillThread kills the thread that violated the rule. It is the same as ActKill.
|
||||
// All other threads from the same thread group will continue to execute.
|
||||
ActKillThread ScmpAction = iota
|
||||
// ActKillProcess kills the process that violated the rule.
|
||||
// All threads in the thread group are also terminated.
|
||||
// This action is only usable when libseccomp API level 3 or higher is
|
||||
// supported.
|
||||
ActKillProcess ScmpAction = iota
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -290,8 +299,10 @@ func (a ScmpCompareOp) String() string {
|
|||
// String returns a string representation of a seccomp match action
|
||||
func (a ScmpAction) String() string {
|
||||
switch a & 0xFFFF {
|
||||
case ActKill:
|
||||
return "Action: Kill Process"
|
||||
case ActKill, ActKillThread:
|
||||
return "Action: Kill thread"
|
||||
case ActKillProcess:
|
||||
return "Action: Kill process"
|
||||
case ActTrap:
|
||||
return "Action: Send SIGSYS"
|
||||
case ActErrno:
|
||||
|
@ -334,23 +345,23 @@ func GetLibraryVersion() (major, minor, micro uint) {
|
|||
return verMajor, verMinor, verMicro
|
||||
}
|
||||
|
||||
// GetApi returns the API level supported by the system.
|
||||
// GetAPI returns the API level supported by the system.
|
||||
// Returns a positive int containing the API level, or 0 with an error if the
|
||||
// API level could not be detected due to the library being older than v2.4.0.
|
||||
// See the seccomp_api_get(3) man page for details on available API levels:
|
||||
// https://github.com/seccomp/libseccomp/blob/master/doc/man/man3/seccomp_api_get.3
|
||||
func GetApi() (uint, error) {
|
||||
return getApi()
|
||||
func GetAPI() (uint, error) {
|
||||
return getAPI()
|
||||
}
|
||||
|
||||
// SetApi forcibly sets the API level. General use of this function is strongly
|
||||
// SetAPI forcibly sets the API level. General use of this function is strongly
|
||||
// discouraged.
|
||||
// Returns an error if the API level could not be set. An error is always
|
||||
// returned if the library is older than v2.4.0
|
||||
// See the seccomp_api_get(3) man page for details on available API levels:
|
||||
// https://github.com/seccomp/libseccomp/blob/master/doc/man/man3/seccomp_api_get.3
|
||||
func SetApi(api uint) error {
|
||||
return setApi(api)
|
||||
func SetAPI(api uint) error {
|
||||
return setAPI(api)
|
||||
}
|
||||
|
||||
// Syscall functions
|
||||
|
@ -552,9 +563,8 @@ func (f *ScmpFilter) Reset(defaultAction ScmpAction) error {
|
|||
return errBadFilter
|
||||
}
|
||||
|
||||
retCode := C.seccomp_reset(f.filterCtx, defaultAction.toNative())
|
||||
if retCode != 0 {
|
||||
return syscall.Errno(-1 * retCode)
|
||||
if retCode := C.seccomp_reset(f.filterCtx, defaultAction.toNative()); retCode != 0 {
|
||||
return errRc(retCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -600,11 +610,12 @@ func (f *ScmpFilter) Merge(src *ScmpFilter) error {
|
|||
}
|
||||
|
||||
// Merge the filters
|
||||
retCode := C.seccomp_merge(f.filterCtx, src.filterCtx)
|
||||
if syscall.Errno(-1*retCode) == syscall.EINVAL {
|
||||
return fmt.Errorf("filters could not be merged due to a mismatch in attributes or invalid filter")
|
||||
} else if retCode != 0 {
|
||||
return syscall.Errno(-1 * retCode)
|
||||
if retCode := C.seccomp_merge(f.filterCtx, src.filterCtx); retCode != 0 {
|
||||
e := errRc(retCode)
|
||||
if e == syscall.EINVAL {
|
||||
return fmt.Errorf("filters could not be merged due to a mismatch in attributes or invalid filter")
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
src.valid = false
|
||||
|
@ -633,12 +644,13 @@ func (f *ScmpFilter) IsArchPresent(arch ScmpArch) (bool, error) {
|
|||
return false, errBadFilter
|
||||
}
|
||||
|
||||
retCode := C.seccomp_arch_exist(f.filterCtx, arch.toNative())
|
||||
if syscall.Errno(-1*retCode) == syscall.EEXIST {
|
||||
// -EEXIST is "arch not present"
|
||||
return false, nil
|
||||
} else if retCode != 0 {
|
||||
return false, syscall.Errno(-1 * retCode)
|
||||
if retCode := C.seccomp_arch_exist(f.filterCtx, arch.toNative()); retCode != 0 {
|
||||
e := errRc(retCode)
|
||||
if e == syscall.EEXIST {
|
||||
// -EEXIST is "arch not present"
|
||||
return false, nil
|
||||
}
|
||||
return false, e
|
||||
}
|
||||
|
||||
return true, nil
|
||||
|
@ -661,9 +673,10 @@ func (f *ScmpFilter) AddArch(arch ScmpArch) error {
|
|||
// Libseccomp returns -EEXIST if the specified architecture is already
|
||||
// present. Succeed silently in this case, as it's not fatal, and the
|
||||
// architecture is present already.
|
||||
retCode := C.seccomp_arch_add(f.filterCtx, arch.toNative())
|
||||
if retCode != 0 && syscall.Errno(-1*retCode) != syscall.EEXIST {
|
||||
return syscall.Errno(-1 * retCode)
|
||||
if retCode := C.seccomp_arch_add(f.filterCtx, arch.toNative()); retCode != 0 {
|
||||
if e := errRc(retCode); e != syscall.EEXIST {
|
||||
return e
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -686,9 +699,10 @@ func (f *ScmpFilter) RemoveArch(arch ScmpArch) error {
|
|||
// Similar to AddArch, -EEXIST is returned if the arch is not present
|
||||
// Succeed silently in that case, this is not fatal and the architecture
|
||||
// is not present in the filter after RemoveArch
|
||||
retCode := C.seccomp_arch_remove(f.filterCtx, arch.toNative())
|
||||
if retCode != 0 && syscall.Errno(-1*retCode) != syscall.EEXIST {
|
||||
return syscall.Errno(-1 * retCode)
|
||||
if retCode := C.seccomp_arch_remove(f.filterCtx, arch.toNative()); retCode != 0 {
|
||||
if e := errRc(retCode); e != syscall.EEXIST {
|
||||
return e
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -705,7 +719,7 @@ func (f *ScmpFilter) Load() error {
|
|||
}
|
||||
|
||||
if retCode := C.seccomp_load(f.filterCtx); retCode != 0 {
|
||||
return syscall.Errno(-1 * retCode)
|
||||
return errRc(retCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -764,7 +778,7 @@ func (f *ScmpFilter) GetNoNewPrivsBit() (bool, error) {
|
|||
func (f *ScmpFilter) GetLogBit() (bool, error) {
|
||||
log, err := f.getFilterAttr(filterAttrLog)
|
||||
if err != nil {
|
||||
api, apiErr := getApi()
|
||||
api, apiErr := getAPI()
|
||||
if (apiErr != nil && api == 0) || (apiErr == nil && api < 3) {
|
||||
return false, fmt.Errorf("getting the log bit is only supported in libseccomp 2.4.0 and newer with API level 3 or higher")
|
||||
}
|
||||
|
@ -818,7 +832,7 @@ func (f *ScmpFilter) SetLogBit(state bool) error {
|
|||
|
||||
err := f.setFilterAttr(filterAttrLog, toSet)
|
||||
if err != nil {
|
||||
api, apiErr := getApi()
|
||||
api, apiErr := getAPI()
|
||||
if (apiErr != nil && api == 0) || (apiErr == nil && api < 3) {
|
||||
return fmt.Errorf("setting the log bit is only supported in libseccomp 2.4.0 and newer with API level 3 or higher")
|
||||
}
|
||||
|
@ -842,7 +856,7 @@ func (f *ScmpFilter) SetSyscallPriority(call ScmpSyscall, priority uint8) error
|
|||
|
||||
if retCode := C.seccomp_syscall_priority(f.filterCtx, C.int(call),
|
||||
C.uint8_t(priority)); retCode != 0 {
|
||||
return syscall.Errno(-1 * retCode)
|
||||
return errRc(retCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -907,7 +921,7 @@ func (f *ScmpFilter) ExportPFC(file *os.File) error {
|
|||
}
|
||||
|
||||
if retCode := C.seccomp_export_pfc(f.filterCtx, C.int(fd)); retCode != 0 {
|
||||
return syscall.Errno(-1 * retCode)
|
||||
return errRc(retCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -928,7 +942,7 @@ func (f *ScmpFilter) ExportBPF(file *os.File) error {
|
|||
}
|
||||
|
||||
if retCode := C.seccomp_export_bpf(f.filterCtx, C.int(fd)); retCode != 0 {
|
||||
return syscall.Errno(-1 * retCode)
|
||||
return errRc(retCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -72,7 +72,17 @@ const uint32_t C_ARCH_S390X = SCMP_ARCH_S390X;
|
|||
#define SCMP_ACT_LOG 0x7ffc0000U
|
||||
#endif
|
||||
|
||||
#ifndef SCMP_ACT_KILL_PROCESS
|
||||
#define SCMP_ACT_KILL_PROCESS 0x80000000U
|
||||
#endif
|
||||
|
||||
#ifndef SCMP_ACT_KILL_THREAD
|
||||
#define SCMP_ACT_KILL_THREAD 0x00000000U
|
||||
#endif
|
||||
|
||||
const uint32_t C_ACT_KILL = SCMP_ACT_KILL;
|
||||
const uint32_t C_ACT_KILL_PROCESS = SCMP_ACT_KILL_PROCESS;
|
||||
const uint32_t C_ACT_KILL_THREAD = SCMP_ACT_KILL_THREAD;
|
||||
const uint32_t C_ACT_TRAP = SCMP_ACT_TRAP;
|
||||
const uint32_t C_ACT_ERRNO = SCMP_ACT_ERRNO(0);
|
||||
const uint32_t C_ACT_TRACE = SCMP_ACT_TRACE(0);
|
||||
|
@ -203,7 +213,7 @@ const (
|
|||
archEnd ScmpArch = ArchS390X
|
||||
// Comparison boundaries to check for action validity
|
||||
actionStart ScmpAction = ActKill
|
||||
actionEnd ScmpAction = ActLog
|
||||
actionEnd ScmpAction = ActKillProcess
|
||||
// Comparison boundaries to check for comparison operator validity
|
||||
compareOpStart ScmpCompareOp = CompareNotEqual
|
||||
compareOpEnd ScmpCompareOp = CompareMaskedEqual
|
||||
|
@ -236,7 +246,7 @@ func ensureSupportedVersion() error {
|
|||
}
|
||||
|
||||
// Get the API level
|
||||
func getApi() (uint, error) {
|
||||
func getAPI() (uint, error) {
|
||||
api := C.seccomp_api_get()
|
||||
if api == 0 {
|
||||
return 0, fmt.Errorf("API level operations are not supported")
|
||||
|
@ -246,9 +256,9 @@ func getApi() (uint, error) {
|
|||
}
|
||||
|
||||
// Set the API level
|
||||
func setApi(api uint) error {
|
||||
func setAPI(api uint) error {
|
||||
if retCode := C.seccomp_api_set(C.uint(api)); retCode != 0 {
|
||||
if syscall.Errno(-1*retCode) == syscall.EOPNOTSUPP {
|
||||
if errRc(retCode) == syscall.EOPNOTSUPP {
|
||||
return fmt.Errorf("API level operations are not supported")
|
||||
}
|
||||
|
||||
|
@ -265,6 +275,10 @@ func filterFinalizer(f *ScmpFilter) {
|
|||
f.Release()
|
||||
}
|
||||
|
||||
func errRc(rc C.int) error {
|
||||
return syscall.Errno(-1 * rc)
|
||||
}
|
||||
|
||||
// Get a raw filter attribute
|
||||
func (f *ScmpFilter) getFilterAttr(attr scmpFilterAttr) (C.uint32_t, error) {
|
||||
f.lock.Lock()
|
||||
|
@ -278,7 +292,7 @@ func (f *ScmpFilter) getFilterAttr(attr scmpFilterAttr) (C.uint32_t, error) {
|
|||
|
||||
retCode := C.seccomp_attr_get(f.filterCtx, attr.toNative(), &attribute)
|
||||
if retCode != 0 {
|
||||
return 0x0, syscall.Errno(-1 * retCode)
|
||||
return 0x0, errRc(retCode)
|
||||
}
|
||||
|
||||
return attribute, nil
|
||||
|
@ -295,7 +309,7 @@ func (f *ScmpFilter) setFilterAttr(attr scmpFilterAttr, value C.uint32_t) error
|
|||
|
||||
retCode := C.seccomp_attr_set(f.filterCtx, attr.toNative(), value)
|
||||
if retCode != 0 {
|
||||
return syscall.Errno(-1 * retCode)
|
||||
return errRc(retCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -316,14 +330,17 @@ func (f *ScmpFilter) addRuleWrapper(call ScmpSyscall, action ScmpAction, exact b
|
|||
retCode = C.seccomp_rule_add_array(f.filterCtx, action.toNative(), C.int(call), length, cond)
|
||||
}
|
||||
|
||||
if syscall.Errno(-1*retCode) == syscall.EFAULT {
|
||||
return fmt.Errorf("unrecognized syscall %#x", int32(call))
|
||||
} else if syscall.Errno(-1*retCode) == syscall.EPERM {
|
||||
return fmt.Errorf("requested action matches default action of filter")
|
||||
} else if syscall.Errno(-1*retCode) == syscall.EINVAL {
|
||||
return fmt.Errorf("two checks on same syscall argument")
|
||||
} else if retCode != 0 {
|
||||
return syscall.Errno(-1 * retCode)
|
||||
if retCode != 0 {
|
||||
switch e := errRc(retCode); e {
|
||||
case syscall.EFAULT:
|
||||
return fmt.Errorf("unrecognized syscall %#x", int32(call))
|
||||
case syscall.EPERM:
|
||||
return fmt.Errorf("requested action matches default action of filter")
|
||||
case syscall.EINVAL:
|
||||
return fmt.Errorf("two checks on same syscall argument")
|
||||
default:
|
||||
return e
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -517,6 +534,10 @@ func actionFromNative(a C.uint32_t) (ScmpAction, error) {
|
|||
switch a & 0xFFFF0000 {
|
||||
case C.C_ACT_KILL:
|
||||
return ActKill, nil
|
||||
case C.C_ACT_KILL_PROCESS:
|
||||
return ActKillProcess, nil
|
||||
case C.C_ACT_KILL_THREAD:
|
||||
return ActKillThread, nil
|
||||
case C.C_ACT_TRAP:
|
||||
return ActTrap, nil
|
||||
case C.C_ACT_ERRNO:
|
||||
|
@ -537,6 +558,10 @@ func (a ScmpAction) toNative() C.uint32_t {
|
|||
switch a & 0xFFFF {
|
||||
case ActKill:
|
||||
return C.C_ACT_KILL
|
||||
case ActKillProcess:
|
||||
return C.C_ACT_KILL_PROCESS
|
||||
case ActKillThread:
|
||||
return C.C_ACT_KILL_THREAD
|
||||
case ActTrap:
|
||||
return C.C_ACT_TRAP
|
||||
case ActErrno:
|
||||
|
|
|
@ -54,13 +54,15 @@ github.com/containernetworking/cni/pkg/types/020
|
|||
github.com/containernetworking/cni/pkg/types/current
|
||||
github.com/containernetworking/cni/pkg/utils
|
||||
github.com/containernetworking/cni/pkg/version
|
||||
# github.com/containers/common v0.20.3
|
||||
# github.com/containers/common v0.21.0
|
||||
github.com/containers/common/pkg/apparmor
|
||||
github.com/containers/common/pkg/apparmor/internal/supported
|
||||
github.com/containers/common/pkg/auth
|
||||
github.com/containers/common/pkg/capabilities
|
||||
github.com/containers/common/pkg/cgroupv2
|
||||
github.com/containers/common/pkg/config
|
||||
github.com/containers/common/pkg/retry
|
||||
github.com/containers/common/pkg/seccomp
|
||||
github.com/containers/common/version
|
||||
# github.com/containers/image/v5 v5.5.2
|
||||
github.com/containers/image/v5/copy
|
||||
|
@ -116,7 +118,7 @@ github.com/containers/ocicrypt/keywrap/pgp
|
|||
github.com/containers/ocicrypt/keywrap/pkcs7
|
||||
github.com/containers/ocicrypt/spec
|
||||
github.com/containers/ocicrypt/utils
|
||||
# github.com/containers/storage v1.23.0
|
||||
# github.com/containers/storage v1.23.3
|
||||
github.com/containers/storage
|
||||
github.com/containers/storage/drivers
|
||||
github.com/containers/storage/drivers/aufs
|
||||
|
@ -252,7 +254,7 @@ github.com/imdario/mergo
|
|||
github.com/inconshreveable/mousetrap
|
||||
# github.com/ishidawataru/sctp v0.0.0-20191218070446-00ab2ac2db07
|
||||
github.com/ishidawataru/sctp
|
||||
# github.com/klauspost/compress v1.10.10
|
||||
# github.com/klauspost/compress v1.10.11
|
||||
github.com/klauspost/compress/flate
|
||||
github.com/klauspost/compress/fse
|
||||
github.com/klauspost/compress/huff0
|
||||
|
@ -273,6 +275,8 @@ github.com/mattn/go-shellwords
|
|||
github.com/matttproud/golang_protobuf_extensions/pbutil
|
||||
# github.com/mistifyio/go-zfs v2.1.1+incompatible
|
||||
github.com/mistifyio/go-zfs
|
||||
# github.com/moby/sys/mountinfo v0.1.3
|
||||
github.com/moby/sys/mountinfo
|
||||
# github.com/morikuni/aec v1.0.0
|
||||
github.com/morikuni/aec
|
||||
# github.com/mtrmac/gpgme v0.1.2
|
||||
|
@ -377,9 +381,7 @@ github.com/prometheus/common/model
|
|||
github.com/prometheus/procfs
|
||||
github.com/prometheus/procfs/internal/fs
|
||||
github.com/prometheus/procfs/internal/util
|
||||
# github.com/seccomp/containers-golang v0.6.0
|
||||
github.com/seccomp/containers-golang
|
||||
# github.com/seccomp/libseccomp-golang v0.9.1
|
||||
# github.com/seccomp/libseccomp-golang v0.9.2-0.20200616122406-847368b35ebf
|
||||
github.com/seccomp/libseccomp-golang
|
||||
# github.com/sirupsen/logrus v1.6.0 => github.com/sirupsen/logrus v1.4.2
|
||||
github.com/sirupsen/logrus
|
||||
|
|
Loading…
Reference in New Issue