Add support for apparmor/selinux

Set's an apparmor profile on the OCI spec if one is configred on the
worker.
Adds selinux labels to containers (only added if selinux is enabled on
the system).

This assumes that the specified apparmor profile is already loaded on
the system and does not try to load it or even check if it is loaded.

SELinux support requires the `selinux` build tag to be added.
Likewise, `runc` would require both the `apparmor` and `selinux` build
tags.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>

Vendored go-selinux to v1.8.0
Fixed tests

Signed-off-by: Tibor Vass <tibor@docker.com>
v0.8
Brian Goff 2020-12-07 19:15:52 +00:00 committed by Tibor Vass
parent 8142d66b5e
commit 68bb095353
29 changed files with 411 additions and 346 deletions

View File

@ -87,6 +87,10 @@ type OCIConfig struct {
// Decoding this is delayed in order to remove the dependency from this
// config pkg to stargz snapshotter's config pkg.
StargzSnapshotterConfig toml.Primitive `toml:"stargzSnapshotter"`
// ApparmorProfile is the name of the apparmor profile that should be used to constrain build containers.
// The profile should already be loaded (by a higher level system) before creating a worker.
ApparmorProfile string `toml:"apparmor-profile"`
}
type ContainerdConfig struct {
@ -98,6 +102,10 @@ type ContainerdConfig struct {
GCConfig
NetworkConfig
Snapshotter string `toml:"snapshotter"`
// ApparmorProfile is the name of the apparmor profile that should be used to constrain build containers.
// The profile should already be loaded (by a higher level system) before creating a worker.
ApparmorProfile string `toml:"apparmor-profile"`
}
type GCPolicy struct {

View File

@ -91,6 +91,10 @@ func init() {
Usage: "snapshotter name to use",
Value: ctd.DefaultSnapshotter,
},
cli.StringFlag{
Name: "containerd-worker-apparmor-profile",
Usage: "set the name of the apparmor profile applied to containers",
},
}
if defaultConf.Workers.Containerd.GC == nil || *defaultConf.Workers.Containerd.GC {
@ -192,6 +196,9 @@ func applyContainerdFlags(c *cli.Context, cfg *config.Config) error {
if c.GlobalIsSet("containerd-worker-snapshotter") {
cfg.Workers.Containerd.Snapshotter = c.GlobalString("containerd-worker-snapshotter")
}
if c.GlobalIsSet("containerd-worker-apparmor-profile") {
cfg.Workers.Containerd.ApparmorProfile = c.GlobalString("containerd-worker-apparmor-profile")
}
return nil
}
@ -222,7 +229,7 @@ func containerdWorkerInitializer(c *cli.Context, common workerInitializerOpt) ([
if cfg.Snapshotter != "" {
snapshotter = cfg.Snapshotter
}
opt, err := containerd.NewWorkerOpt(common.config.Root, cfg.Address, snapshotter, cfg.Namespace, cfg.Labels, dns, nc, ctd.WithTimeout(60*time.Second))
opt, err := containerd.NewWorkerOpt(common.config.Root, cfg.Address, snapshotter, cfg.Namespace, cfg.Labels, dns, nc, common.config.Workers.Containerd.ApparmorProfile, ctd.WithTimeout(60*time.Second))
if err != nil {
return nil, err
}

View File

@ -96,6 +96,10 @@ func init() {
Usage: "name of specified oci worker binary",
Value: defaultConf.Workers.OCI.Binary,
},
cli.StringFlag{
Name: "oci-worker-apparmor-profile",
Usage: "set the name of the apparmor profile applied to containers",
},
}
n := "oci-worker-rootless"
u := "enable rootless mode"
@ -215,6 +219,9 @@ func applyOCIFlags(c *cli.Context, cfg *config.Config) error {
if c.GlobalIsSet("oci-worker-proxy-snapshotter-path") {
cfg.Workers.OCI.ProxySnapshotterPath = c.GlobalString("oci-worker-proxy-snapshotter-path")
}
if c.GlobalIsSet("oci-worker-apparmor-profile") {
cfg.Workers.OCI.ApparmorProfile = c.GlobalString("oci-worker-apparmor-profile")
}
return nil
}
@ -268,7 +275,7 @@ func ociWorkerInitializer(c *cli.Context, common workerInitializerOpt) ([]worker
},
}
opt, err := runc.NewWorkerOpt(common.config.Root, snFactory, cfg.Rootless, processMode, cfg.Labels, idmapping, nc, dns, cfg.Binary)
opt, err := runc.NewWorkerOpt(common.config.Root, snFactory, cfg.Rootless, processMode, cfg.Labels, idmapping, nc, dns, cfg.Binary, cfg.ApparmorProfile)
if err != nil {
return nil, err
}

View File

@ -37,10 +37,11 @@ type containerdExecutor struct {
dnsConfig *oci.DNSConfig
running map[string]chan error
mu sync.Mutex
apparmorProfile string
}
// New creates a new executor backed by connection to containerd API
func New(client *containerd.Client, root, cgroup string, networkProviders map[pb.NetMode]network.Provider, dnsConfig *oci.DNSConfig) executor.Executor {
func New(client *containerd.Client, root, cgroup string, networkProviders map[pb.NetMode]network.Provider, dnsConfig *oci.DNSConfig, apparmorProfile string) executor.Executor {
// clean up old hosts/resolv.conf file. ignore errors
os.RemoveAll(filepath.Join(root, "hosts"))
os.RemoveAll(filepath.Join(root, "resolv.conf"))
@ -52,6 +53,7 @@ func New(client *containerd.Client, root, cgroup string, networkProviders map[pb
cgroupParent: cgroup,
dnsConfig: dnsConfig,
running: make(map[string]chan error),
apparmorProfile: apparmorProfile,
}
}
@ -168,7 +170,7 @@ func (w *containerdExecutor) Run(ctx context.Context, id string, root executor.M
opts = append(opts, containerdoci.WithCgroup(cgroupsPath))
}
processMode := oci.ProcessSandbox // FIXME(AkihiroSuda)
spec, cleanup, err := oci.GenerateSpec(ctx, meta, mounts, id, resolvConf, hostsFile, namespace, processMode, nil, opts...)
spec, cleanup, err := oci.GenerateSpec(ctx, meta, mounts, id, resolvConf, hostsFile, namespace, processMode, nil, w.apparmorProfile, opts...)
if err != nil {
return err
}

View File

@ -16,6 +16,7 @@ import (
"github.com/moby/buildkit/snapshot"
"github.com/moby/buildkit/util/network"
specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/selinux/go-selinux"
"github.com/pkg/errors"
)
@ -35,7 +36,7 @@ const (
// GenerateSpec generates spec using containerd functionality.
// opts are ignored for s.Process, s.Hostname, and s.Mounts .
func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mount, id, resolvConf, hostsFile string, namespace network.Namespace, processMode ProcessMode, idmap *idtools.IdentityMapping, opts ...oci.SpecOpts) (*specs.Spec, func(), error) {
func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mount, id, resolvConf, hostsFile string, namespace network.Namespace, processMode ProcessMode, idmap *idtools.IdentityMapping, apparmorProfile string, opts ...oci.SpecOpts) (*specs.Spec, func(), error) {
c := &containers.Container{
ID: id,
}
@ -52,7 +53,7 @@ func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mou
return nil, nil, err
}
if securityOpts, err := generateSecurityOpts(meta.SecurityMode); err == nil {
if securityOpts, err := generateSecurityOpts(meta.SecurityMode, apparmorProfile); err == nil {
opts = append(opts, securityOpts...)
} else {
return nil, nil, err
@ -103,6 +104,9 @@ func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mou
for _, f := range releasers {
f()
}
if s.Process.SelinuxLabel != "" {
selinux.ReleaseLabel(s.Process.SelinuxLabel)
}
}
for _, m := range mounts {

View File

@ -13,6 +13,7 @@ import (
"github.com/moby/buildkit/util/entitlements/security"
"github.com/moby/buildkit/util/system"
specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/selinux/go-selinux/label"
)
func generateMountOpts(resolvConf, hostsFile string) ([]oci.SpecOpts, error) {
@ -26,15 +27,32 @@ func generateMountOpts(resolvConf, hostsFile string) ([]oci.SpecOpts, error) {
}
// generateSecurityOpts may affect mounts, so must be called after generateMountOpts
func generateSecurityOpts(mode pb.SecurityMode) ([]oci.SpecOpts, error) {
if mode == pb.SecurityMode_INSECURE {
func generateSecurityOpts(mode pb.SecurityMode, apparmorProfile string) (opts []oci.SpecOpts, _ error) {
switch mode {
case pb.SecurityMode_INSECURE:
return []oci.SpecOpts{
security.WithInsecureSpec(),
oci.WithWriteableCgroupfs,
oci.WithWriteableSysfs,
func(_ context.Context, _ oci.Client, _ *containers.Container, s *oci.Spec) error {
var err error
s.Process.SelinuxLabel, s.Linux.MountLabel, err = label.InitLabels([]string{"disable"})
return err
},
}, nil
} else if system.SeccompSupported() && mode == pb.SecurityMode_SANDBOX {
return []oci.SpecOpts{withDefaultProfile()}, nil
case pb.SecurityMode_SANDBOX:
if system.SeccompSupported() {
opts = append(opts, withDefaultProfile())
}
if apparmorProfile != "" {
opts = append(opts, oci.WithApparmorProfile(apparmorProfile))
}
opts = append(opts, func(_ context.Context, _ oci.Client, _ *containers.Container, s *oci.Spec) error {
var err error
s.Process.SelinuxLabel, s.Linux.MountLabel, err = label.InitLabels(nil)
return err
})
return opts, nil
}
return nil, nil
}

View File

@ -14,7 +14,7 @@ func generateMountOpts(resolvConf, hostsFile string) ([]oci.SpecOpts, error) {
}
// generateSecurityOpts may affect mounts, so must be called after generateMountOpts
func generateSecurityOpts(mode pb.SecurityMode) ([]oci.SpecOpts, error) {
func generateSecurityOpts(mode pb.SecurityMode, apparmorProfile string) ([]oci.SpecOpts, error) {
if mode == pb.SecurityMode_INSECURE {
return nil, errors.New("no support for running in insecure mode on Windows")
}

View File

@ -45,6 +45,7 @@ type Opt struct {
NoPivot bool
DNS *oci.DNSConfig
OOMScoreAdj *int
ApparmorProfile string
}
var defaultCommandCandidates = []string{"buildkit-runc", "runc"}
@ -62,6 +63,7 @@ type runcExecutor struct {
oomScoreAdj *int
running map[string]chan error
mu sync.Mutex
apparmorProfile string
}
func New(opt Opt, networkProviders map[pb.NetMode]network.Provider) (executor.Executor, error) {
@ -124,6 +126,7 @@ func New(opt Opt, networkProviders map[pb.NetMode]network.Provider) (executor.Ex
dns: opt.DNS,
oomScoreAdj: opt.OOMScoreAdj,
running: make(map[string]chan error),
apparmorProfile: opt.ApparmorProfile,
}
return w, nil
}
@ -253,7 +256,7 @@ func (w *runcExecutor) Run(ctx context.Context, id string, root executor.Mount,
}
opts = append(opts, containerdoci.WithCgroup(cgroupsPath))
}
spec, cleanup, err := oci.GenerateSpec(ctx, meta, mounts, id, resolvConf, hostsFile, namespace, w.processMode, w.idmap, opts...)
spec, cleanup, err := oci.GenerateSpec(ctx, meta, mounts, id, resolvConf, hostsFile, namespace, w.processMode, w.idmap, w.apparmorProfile, opts...)
if err != nil {
return err
}

1
go.mod
View File

@ -46,6 +46,7 @@ require (
github.com/opencontainers/image-spec v1.0.1
github.com/opencontainers/runc v1.0.0-rc92
github.com/opencontainers/runtime-spec v1.0.3-0.20200728170252-4d89ac9fbff6
github.com/opencontainers/selinux v1.8.0
github.com/opentracing-contrib/go-stdlib v1.0.0
github.com/opentracing/opentracing-go v1.2.0
github.com/pkg/errors v0.9.1

4
go.sum
View File

@ -724,6 +724,8 @@ github.com/opencontainers/runtime-spec v1.0.3-0.20200728170252-4d89ac9fbff6/go.m
github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
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/opencontainers/selinux v1.8.0 h1:+77ba4ar4jsCbL1GLbFL8fFM57w6suPfSS9PDLDY7KM=
github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
github.com/opentracing-contrib/go-stdlib v1.0.0 h1:TBS7YuVotp8myLon4Pv7BtCBzOTo1DeZCld0Z63mW2w=
github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
@ -919,6 +921,8 @@ github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17
github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU=
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/willf/bitset v1.1.11 h1:N7Z7E9UvjW+sGsEl7k/SJrvY2reP1A07MrGuCjIOjRE=
github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
github.com/xanzy/go-gitlab v0.31.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug=
github.com/xanzy/go-gitlab v0.32.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=

View File

@ -5,9 +5,6 @@ This package uses a selinux build tag to enable the selinux functionality. This
allows non-linux and linux users who do not have selinux support to still use
tools that rely on this library.
To compile with full selinux support use the -tags=selinux option in your build
and test commands.
Usage:
import "github.com/opencontainers/selinux/go-selinux"

View File

@ -1,5 +1,3 @@
// +build selinux,linux
package label
import (
@ -27,14 +25,14 @@ var ErrIncompatibleLabel = errors.New("Bad SELinux option z and Z can not be use
// the container. A list of options can be passed into this function to alter
// the labels. The labels returned will include a random MCS String, that is
// guaranteed to be unique.
func InitLabels(options []string) (plabel string, mlabel string, Err error) {
func InitLabels(options []string) (plabel string, mlabel string, retErr error) {
if !selinux.GetEnabled() {
return "", "", nil
}
processLabel, mountLabel := selinux.ContainerLabels()
if processLabel != "" {
defer func() {
if Err != nil {
if retErr != nil {
selinux.ReleaseLabel(mountLabel)
}
}()
@ -57,7 +55,6 @@ func InitLabels(options []string) (plabel string, mlabel string, Err error) {
con := strings.SplitN(opt, ":", 2)
if !validOptions[con[0]] {
return "", "", errors.Errorf("Bad label option %q, valid options 'disable, user, role, level, type, filetype'", con[0])
}
if con[0] == "filetype" {
mcon["type"] = con[1]

View File

@ -1,4 +1,4 @@
// +build !selinux !linux
// +build !linux
package label

View File

@ -30,6 +30,11 @@ var (
// ErrLevelSyntax is returned when a sensitivity or category do not have correct syntax in a level
ErrLevelSyntax = errors.New("invalid level syntax")
// ErrContextMissing is returned if a requested context is not found in a file.
ErrContextMissing = errors.New("context does not have a match")
// ErrVerifierNil is returned when a context verifier function is nil.
ErrVerifierNil = errors.New("verifier function is nil")
// CategoryRange allows the upper bound on the category range to be adjusted
CategoryRange = DefaultCategoryRange
)
@ -63,8 +68,12 @@ func FileLabel(fpath string) (string, error) {
return fileLabel(fpath)
}
// SetFSCreateLabel tells kernel the label to create all file system objects
// created by this task. Setting label="" to return to default.
// SetFSCreateLabel tells the kernel what label to use for all file system objects
// created by this task.
// Set the label to an empty string to return to the default label. Calls to SetFSCreateLabel
// should be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() until file system
// objects created by this task are finished to guarantee another goroutine does not migrate
// to the current thread before execution is complete.
func SetFSCreateLabel(label string) error {
return setFSCreateLabel(label)
}
@ -113,19 +122,27 @@ func CalculateGlbLub(sourceRange, targetRange string) (string, error) {
}
// SetExecLabel sets the SELinux label that the kernel will use for any programs
// that are executed by the current process thread, or an error.
// that are executed by the current process thread, or an error. Calls to SetExecLabel
// should be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() until execution
// of the program is finished to guarantee another goroutine does not migrate to the current
// thread before execution is complete.
func SetExecLabel(label string) error {
return setExecLabel(label)
}
// SetTaskLabel sets the SELinux label for the current thread, or an error.
// This requires the dyntransition permission.
// This requires the dyntransition permission. Calls to SetTaskLabel should
// be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() to guarantee
// the current thread does not run in a new mislabeled thread.
func SetTaskLabel(label string) error {
return setTaskLabel(label)
}
// SetSocketLabel takes a process label and tells the kernel to assign the
// label to the next socket that gets created
// label to the next socket that gets created. Calls to SetSocketLabel
// should be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() until
// the the socket is created to guarantee another goroutine does not migrate
// to the current thread before execution is complete.
func SetSocketLabel(label string) error {
return setSocketLabel(label)
}
@ -141,7 +158,10 @@ func PeerLabel(fd uintptr) (string, error) {
}
// SetKeyLabel takes a process label and tells the kernel to assign the
// label to the next kernel keyring that gets created
// label to the next kernel keyring that gets created. Calls to SetKeyLabel
// should be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() until
// the kernel keyring is created to guarantee another goroutine does not migrate
// to the current thread before execution is complete.
func SetKeyLabel(label string) error {
return setKeyLabel(label)
}
@ -247,3 +267,12 @@ func DupSecOpt(src string) ([]string, error) {
func DisableSecOpt() []string {
return disableSecOpt()
}
// GetDefaultContextWithLevel gets a single context for the specified SELinux user
// identity that is reachable from the specified scon context. The context is based
// on the per-user /etc/selinux/{SELINUXTYPE}/contexts/users/<username> if it exists,
// and falls back to the global /etc/selinux/{SELINUXTYPE}/contexts/default_contexts
// file.
func GetDefaultContextWithLevel(user, level, scon string) (string, error) {
return getDefaultContextWithLevel(user, level, scon)
}

View File

@ -1,5 +1,3 @@
// +build selinux,linux
package selinux
import (
@ -28,6 +26,8 @@ const (
minSensLen = 2
contextFile = "/usr/share/containers/selinux/contexts"
selinuxDir = "/etc/selinux/"
selinuxUsersDir = "contexts/users"
defaultContexts = "contexts/default_contexts"
selinuxConfig = selinuxDir + "config"
selinuxfsMount = "/sys/fs/selinux"
selinuxTypeTag = "SELINUXTYPE"
@ -35,6 +35,8 @@ const (
xattrNameSelinux = "security.selinux"
)
var policyRoot = filepath.Join(selinuxDir, readConfig(selinuxTypeTag))
type selinuxState struct {
enabledSet bool
enabled bool
@ -54,6 +56,13 @@ type mlsRange struct {
high *level
}
type defaultSECtx struct {
user, level, scon string
userRdr, defaultRdr io.Reader
verifier func(string) error
}
type levelItem byte
const (
@ -111,7 +120,7 @@ func verifySELinuxfsMount(mnt string) bool {
if err == nil {
break
}
if err == unix.EAGAIN {
if err == unix.EAGAIN || err == unix.EINTR {
continue
}
return false
@ -205,28 +214,16 @@ func getEnabled() bool {
}
func readConfig(target string) string {
var (
val, key string
bufin *bufio.Reader
)
in, err := os.Open(selinuxConfig)
if err != nil {
return ""
}
defer in.Close()
bufin = bufio.NewReader(in)
scanner := bufio.NewScanner(in)
for done := false; !done; {
var line string
if line, err = bufin.ReadString('\n'); err != nil {
if err != io.EOF {
return ""
}
done = true
}
line = strings.TrimSpace(line)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if len(line) == 0 {
// Skip blank lines
continue
@ -236,7 +233,7 @@ func readConfig(target string) string {
continue
}
if groups := assignRegex.FindStringSubmatch(line); groups != nil {
key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2])
key, val := strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2])
if key == target {
return strings.Trim(val, "\"")
}
@ -245,16 +242,18 @@ func readConfig(target string) string {
return ""
}
func getSELinuxPolicyRoot() string {
return filepath.Join(selinuxDir, readConfig(selinuxTypeTag))
}
func isProcHandle(fh *os.File) error {
var buf unix.Statfs_t
for {
err := unix.Fstatfs(int(fh.Fd()), &buf)
if err != nil {
if err == nil {
break
}
if err != unix.EINTR {
return errors.Wrapf(err, "statfs(%q) failed", fh.Name())
}
}
if buf.Type != unix.PROC_SUPER_MAGIC {
return errors.Errorf("file %q is not on procfs", fh.Name())
}
@ -307,9 +306,16 @@ func setFileLabel(fpath string, label string) error {
if fpath == "" {
return ErrEmptyPath
}
if err := unix.Lsetxattr(fpath, xattrNameSelinux, []byte(label), 0); err != nil {
for {
err := unix.Lsetxattr(fpath, xattrNameSelinux, []byte(label), 0)
if err == nil {
break
}
if err != unix.EINTR {
return errors.Wrapf(err, "failed to set file label on %s", fpath)
}
}
return nil
}
@ -751,7 +757,7 @@ func reserveLabel(label string) {
if len(label) != 0 {
con := strings.SplitN(label, ":", 4)
if len(con) > 3 {
mcsAdd(con[3])
_ = mcsAdd(con[3])
}
}
}
@ -828,11 +834,11 @@ func intToMcs(id int, catRange uint32) string {
}
for ORD > TIER {
ORD = ORD - TIER
ORD -= TIER
TIER--
}
TIER = SETSIZE - TIER
ORD = ORD + TIER
ORD += TIER
return fmt.Sprintf("s0:c%d,c%d", TIER, ORD)
}
@ -844,17 +850,15 @@ func uniqMcs(catRange uint32) string {
)
for {
binary.Read(rand.Reader, binary.LittleEndian, &n)
_ = binary.Read(rand.Reader, binary.LittleEndian, &n)
c1 = n % catRange
binary.Read(rand.Reader, binary.LittleEndian, &n)
_ = binary.Read(rand.Reader, binary.LittleEndian, &n)
c2 = n % catRange
if c1 == c2 {
continue
} else {
if c1 > c2 {
} else if c1 > c2 {
c1, c2 = c2, c1
}
}
mcs = fmt.Sprintf("s0:c%d,c%d", c1, c2)
if err := mcsAdd(mcs); err != nil {
continue
@ -884,18 +888,13 @@ func openContextFile() (*os.File, error) {
if f, err := os.Open(contextFile); err == nil {
return f, nil
}
lxcPath := filepath.Join(getSELinuxPolicyRoot(), "/contexts/lxc_contexts")
lxcPath := filepath.Join(policyRoot, "/contexts/lxc_contexts")
return os.Open(lxcPath)
}
var labels = loadLabels()
func loadLabels() map[string]string {
var (
val, key string
bufin *bufio.Reader
)
labels := make(map[string]string)
in, err := openContextFile()
if err != nil {
@ -903,18 +902,10 @@ func loadLabels() map[string]string {
}
defer in.Close()
bufin = bufio.NewReader(in)
scanner := bufio.NewScanner(in)
for done := false; !done; {
var line string
if line, err = bufin.ReadString('\n'); err != nil {
if err == io.EOF {
done = true
} else {
break
}
}
line = strings.TrimSpace(line)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if len(line) == 0 {
// Skip blank lines
continue
@ -924,7 +915,7 @@ func loadLabels() map[string]string {
continue
}
if groups := assignRegex.FindStringSubmatch(line); groups != nil {
key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2])
key, val := strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2])
labels[key] = strings.Trim(val, "\"")
}
}
@ -1015,7 +1006,7 @@ func copyLevel(src, dest string) (string, error) {
return "", err
}
mcsDelete(tcon["level"])
mcsAdd(scon["level"])
_ = mcsAdd(scon["level"])
tcon["level"] = scon["level"]
return tcon.Get(), nil
}
@ -1095,3 +1086,124 @@ func dupSecOpt(src string) ([]string, error) {
func disableSecOpt() []string {
return []string{"disable"}
}
// findUserInContext scans the reader for a valid SELinux context
// match that is verified with the verifier. Invalid contexts are
// skipped. It returns a matched context or an empty string if no
// match is found. If a scanner error occurs, it is returned.
func findUserInContext(context Context, r io.Reader, verifier func(string) error) (string, error) {
fromRole := context["role"]
fromType := context["type"]
scanner := bufio.NewScanner(r)
for scanner.Scan() {
fromConns := strings.Fields(scanner.Text())
if len(fromConns) == 0 {
// Skip blank lines
continue
}
line := fromConns[0]
if line[0] == ';' || line[0] == '#' {
// Skip comments
continue
}
// user context files contexts are formatted as
// role_r:type_t:s0 where the user is missing.
lineArr := strings.SplitN(line, ":", 4)
// skip context with typo, or role and type do not match
if len(lineArr) != 3 ||
lineArr[0] != fromRole ||
lineArr[1] != fromType {
continue
}
for _, cc := range fromConns[1:] {
toConns := strings.SplitN(cc, ":", 4)
if len(toConns) != 3 {
continue
}
context["role"] = toConns[0]
context["type"] = toConns[1]
outConn := context.get()
if err := verifier(outConn); err != nil {
continue
}
return outConn, nil
}
}
if err := scanner.Err(); err != nil {
return "", errors.Wrap(err, "failed to scan for context")
}
return "", nil
}
func getDefaultContextFromReaders(c *defaultSECtx) (string, error) {
if c.verifier == nil {
return "", ErrVerifierNil
}
context, err := newContext(c.scon)
if err != nil {
return "", errors.Wrapf(err, "failed to create label for %s", c.scon)
}
// set so the verifier validates the matched context with the provided user and level.
context["user"] = c.user
context["level"] = c.level
conn, err := findUserInContext(context, c.userRdr, c.verifier)
if err != nil {
return "", err
}
if conn != "" {
return conn, nil
}
conn, err = findUserInContext(context, c.defaultRdr, c.verifier)
if err != nil {
return "", err
}
if conn != "" {
return conn, nil
}
return "", errors.Wrapf(ErrContextMissing, "context not found: %q", c.scon)
}
func getDefaultContextWithLevel(user, level, scon string) (string, error) {
userPath := filepath.Join(policyRoot, selinuxUsersDir, user)
defaultPath := filepath.Join(policyRoot, defaultContexts)
fu, err := os.Open(userPath)
if err != nil {
return "", err
}
defer fu.Close()
fd, err := os.Open(defaultPath)
if err != nil {
return "", err
}
defer fd.Close()
c := defaultSECtx{
user: user,
level: level,
scon: scon,
userRdr: fu,
defaultRdr: fd,
verifier: securityCheckContext,
}
return getDefaultContextFromReaders(&c)
}

View File

@ -1,4 +1,4 @@
// +build !selinux !linux
// +build !linux
package selinux
@ -146,3 +146,7 @@ func dupSecOpt(src string) ([]string, error) {
func disableSecOpt() []string {
return []string{"disable"}
}
func getDefaultContextWithLevel(user, level, scon string) (string, error) {
return "", nil
}

View File

@ -1,30 +0,0 @@
// +build selinux,linux
package selinux
import (
"golang.org/x/sys/unix"
)
// Returns a []byte slice if the xattr is set and nil otherwise
// Requires path and its attribute as arguments
func lgetxattr(path string, attr string) ([]byte, error) {
// Start with a 128 length byte array
dest := make([]byte, 128)
sz, errno := unix.Lgetxattr(path, attr, dest)
for errno == unix.ERANGE {
// Buffer too small, use zero-sized buffer to get the actual size
sz, errno = unix.Lgetxattr(path, attr, []byte{})
if errno != nil {
return nil, errno
}
dest = make([]byte, sz)
sz, errno = unix.Lgetxattr(path, attr, dest)
}
if errno != nil {
return nil, errno
}
return dest[:sz], nil
}

View File

@ -0,0 +1,38 @@
package selinux
import (
"golang.org/x/sys/unix"
)
// lgetxattr returns a []byte slice containing the value of
// an extended attribute attr set for path.
func lgetxattr(path, attr string) ([]byte, error) {
// Start with a 128 length byte array
dest := make([]byte, 128)
sz, errno := doLgetxattr(path, attr, dest)
for errno == unix.ERANGE {
// Buffer too small, use zero-sized buffer to get the actual size
sz, errno = doLgetxattr(path, attr, []byte{})
if errno != nil {
return nil, errno
}
dest = make([]byte, sz)
sz, errno = doLgetxattr(path, attr, dest)
}
if errno != nil {
return nil, errno
}
return dest[:sz], nil
}
// doLgetxattr is a wrapper that retries on EINTR
func doLgetxattr(path, attr string, dest []byte) (int, error) {
for {
sz, err := unix.Lgetxattr(path, attr, dest)
if err != unix.EINTR {
return sz, err
}
}
}

View File

@ -20,17 +20,16 @@ type WalkFunc = filepath.WalkFunc
//
// Note that this implementation only supports primitive error handling:
//
// * no errors are ever passed to WalkFn
// - no errors are ever passed to WalkFn;
//
// * once a walkFn returns any error, all further processing stops
// - once a walkFn returns any error, all further processing stops
// and the error is returned to the caller of Walk;
//
// * filepath.SkipDir is not supported;
// - filepath.SkipDir is not supported;
//
// * if more than one walkFn instance will return an error, only one
// - if more than one walkFn instance will return an error, only one
// of such errors will be propagated and returned by Walk, others
// will be silently discarded.
//
func Walk(root string, walkFn WalkFunc) error {
return WalkN(root, walkFn, runtime.NumCPU()*2)
}
@ -38,6 +37,8 @@ func Walk(root string, walkFn WalkFunc) error {
// WalkN is a wrapper for filepath.Walk which can call multiple walkFn
// in parallel, allowing to handle each item concurrently. A maximum of
// num walkFn will be called at any one time.
//
// Please see Walk documentation for caveats of using this function.
func WalkN(root string, walkFn WalkFunc, num int) error {
// make sure limit is sensible
if num < 1 {

View File

@ -1,191 +0,0 @@
# MAKEFILE
#
# @author Nicola Asuni <info@tecnick.com>
# @link https://github.com/willf/bitset
# ------------------------------------------------------------------------------
# List special make targets that are not associated with files
.PHONY: help all test format fmtcheck vet lint coverage cyclo ineffassign misspell structcheck varcheck errcheck gosimple astscan qa deps clean nuke
# Use bash as shell (Note: Ubuntu now uses dash which doesn't support PIPESTATUS).
SHELL=/bin/bash
# CVS path (path to the parent dir containing the project)
CVSPATH=github.com/willf
# Project owner
OWNER=willf
# Project vendor
VENDOR=willf
# Project name
PROJECT=bitset
# Project version
VERSION=$(shell cat VERSION)
# Name of RPM or DEB package
PKGNAME=${VENDOR}-${PROJECT}
# Current directory
CURRENTDIR=$(shell pwd)
# GO lang path
ifneq ($(GOPATH),)
ifeq ($(findstring $(GOPATH),$(CURRENTDIR)),)
# the defined GOPATH is not valid
GOPATH=
endif
endif
ifeq ($(GOPATH),)
# extract the GOPATH
GOPATH=$(firstword $(subst /src/, ,$(CURRENTDIR)))
endif
# --- MAKE TARGETS ---
# Display general help about this command
help:
@echo ""
@echo "$(PROJECT) Makefile."
@echo "GOPATH=$(GOPATH)"
@echo "The following commands are available:"
@echo ""
@echo " make qa : Run all the tests"
@echo " make test : Run the unit tests"
@echo ""
@echo " make format : Format the source code"
@echo " make fmtcheck : Check if the source code has been formatted"
@echo " make vet : Check for suspicious constructs"
@echo " make lint : Check for style errors"
@echo " make coverage : Generate the coverage report"
@echo " make cyclo : Generate the cyclomatic complexity report"
@echo " make ineffassign : Detect ineffectual assignments"
@echo " make misspell : Detect commonly misspelled words in source files"
@echo " make structcheck : Find unused struct fields"
@echo " make varcheck : Find unused global variables and constants"
@echo " make errcheck : Check that error return values are used"
@echo " make gosimple : Suggest code simplifications"
@echo " make astscan : GO AST scanner"
@echo ""
@echo " make docs : Generate source code documentation"
@echo ""
@echo " make deps : Get the dependencies"
@echo " make clean : Remove any build artifact"
@echo " make nuke : Deletes any intermediate file"
@echo ""
# Alias for help target
all: help
# Run the unit tests
test:
@mkdir -p target/test
@mkdir -p target/report
GOPATH=$(GOPATH) \
go test \
-covermode=atomic \
-bench=. \
-race \
-cpuprofile=target/report/cpu.out \
-memprofile=target/report/mem.out \
-mutexprofile=target/report/mutex.out \
-coverprofile=target/report/coverage.out \
-v ./... | \
tee >(PATH=$(GOPATH)/bin:$(PATH) go-junit-report > target/test/report.xml); \
test $${PIPESTATUS[0]} -eq 0
# Format the source code
format:
@find . -type f -name "*.go" -exec gofmt -s -w {} \;
# Check if the source code has been formatted
fmtcheck:
@mkdir -p target
@find . -type f -name "*.go" -exec gofmt -s -d {} \; | tee target/format.diff
@test ! -s target/format.diff || { echo "ERROR: the source code has not been formatted - please use 'make format' or 'gofmt'"; exit 1; }
# Check for syntax errors
vet:
GOPATH=$(GOPATH) go vet .
# Check for style errors
lint:
GOPATH=$(GOPATH) PATH=$(GOPATH)/bin:$(PATH) golint .
# Generate the coverage report
coverage:
@mkdir -p target/report
GOPATH=$(GOPATH) \
go tool cover -html=target/report/coverage.out -o target/report/coverage.html
# Report cyclomatic complexity
cyclo:
@mkdir -p target/report
GOPATH=$(GOPATH) gocyclo -avg ./ | tee target/report/cyclo.txt ; test $${PIPESTATUS[0]} -eq 0
# Detect ineffectual assignments
ineffassign:
@mkdir -p target/report
GOPATH=$(GOPATH) ineffassign ./ | tee target/report/ineffassign.txt ; test $${PIPESTATUS[0]} -eq 0
# Detect commonly misspelled words in source files
misspell:
@mkdir -p target/report
GOPATH=$(GOPATH) misspell -error ./ | tee target/report/misspell.txt ; test $${PIPESTATUS[0]} -eq 0
# Find unused struct fields
structcheck:
@mkdir -p target/report
GOPATH=$(GOPATH) structcheck -a ./ | tee target/report/structcheck.txt
# Find unused global variables and constants
varcheck:
@mkdir -p target/report
GOPATH=$(GOPATH) varcheck -e ./ | tee target/report/varcheck.txt
# Check that error return values are used
errcheck:
@mkdir -p target/report
GOPATH=$(GOPATH) errcheck ./ | tee target/report/errcheck.txt
# AST scanner
astscan:
@mkdir -p target/report
GOPATH=$(GOPATH) gosec . | tee target/report/astscan.txt ; test $${PIPESTATUS[0]} -eq 0 || true
# Generate source docs
docs:
@mkdir -p target/docs
nohup sh -c 'GOPATH=$(GOPATH) godoc -http=127.0.0.1:6060' > target/godoc_server.log 2>&1 &
wget --directory-prefix=target/docs/ --execute robots=off --retry-connrefused --recursive --no-parent --adjust-extension --page-requisites --convert-links http://127.0.0.1:6060/pkg/github.com/${VENDOR}/${PROJECT}/ ; kill -9 `lsof -ti :6060`
@echo '<html><head><meta http-equiv="refresh" content="0;./127.0.0.1:6060/pkg/'${CVSPATH}'/'${PROJECT}'/index.html"/></head><a href="./127.0.0.1:6060/pkg/'${CVSPATH}'/'${PROJECT}'/index.html">'${PKGNAME}' Documentation ...</a></html>' > target/docs/index.html
# Alias to run all quality-assurance checks
qa: fmtcheck test vet lint coverage cyclo ineffassign misspell structcheck varcheck errcheck gosimple astscan
# --- INSTALL ---
# Get the dependencies
deps:
GOPATH=$(GOPATH) go get ./...
GOPATH=$(GOPATH) go get golang.org/x/lint/golint
GOPATH=$(GOPATH) go get github.com/jstemmer/go-junit-report
GOPATH=$(GOPATH) go get github.com/axw/gocov/gocov
GOPATH=$(GOPATH) go get github.com/fzipp/gocyclo
GOPATH=$(GOPATH) go get github.com/gordonklaus/ineffassign
GOPATH=$(GOPATH) go get github.com/client9/misspell/cmd/misspell
GOPATH=$(GOPATH) go get github.com/opennota/check/cmd/structcheck
GOPATH=$(GOPATH) go get github.com/opennota/check/cmd/varcheck
GOPATH=$(GOPATH) go get github.com/kisielk/errcheck
GOPATH=$(GOPATH) go get github.com/securego/gosec/cmd/gosec/...
# Remove any build artifact
clean:
GOPATH=$(GOPATH) go clean ./...
# Deletes any intermediate file
nuke:
rm -rf ./target
GOPATH=$(GOPATH) go clean -i ./...

View File

@ -2,10 +2,10 @@
*Go language library to map between non-negative integers and boolean values*
[![Master Build Status](https://secure.travis-ci.org/willf/bitset.png?branch=master)](https://travis-ci.org/willf/bitset?branch=master)
[![Test](https://github.com/willf/bitset/workflows/Test/badge.svg)](https://github.com/willf/bitset/actions?query=workflow%3ATest)
[![Master Coverage Status](https://coveralls.io/repos/willf/bitset/badge.svg?branch=master&service=github)](https://coveralls.io/github/willf/bitset?branch=master)
[![Go Report Card](https://goreportcard.com/badge/github.com/willf/bitset)](https://goreportcard.com/report/github.com/willf/bitset)
[![GoDoc](https://godoc.org/github.com/willf/bitset?status.svg)](http://godoc.org/github.com/willf/bitset)
[![PkgGoDev](https://pkg.go.dev/badge/github.com/willf/bitset?tab=doc)](https://pkg.go.dev/github.com/willf/bitset?tab=doc)
## Description
@ -63,8 +63,11 @@ func main() {
As an alternative to BitSets, one should check out the 'big' package, which provides a (less set-theoretical) view of bitsets.
Godoc documentation is at: https://godoc.org/github.com/willf/bitset
Package documentation is at: https://pkg.go.dev/github.com/willf/bitset?tab=doc
## Memory Usage
The memory usage of a bitset using N bits is at least N/8 bytes. The number of bits in a bitset is at least as large as one plus the greatest bit index you have accessed. Thus it is possible to run out of memory while using a bitset. If you have lots of bits, you might prefer compressed bitsets, like the [Roaring bitmaps](http://roaringbitmap.org) and its [Go implementation](https://github.com/RoaringBitmap/roaring).
## Implementation Note
@ -82,15 +85,10 @@ go get github.com/willf/bitset
If you wish to contribute to this project, please branch and issue a pull request against master ("[GitHub Flow](https://guides.github.com/introduction/flow/)")
This project include a Makefile that allows you to test and build the project with simple commands.
To see all available options:
```bash
make help
```
## Running all tests
Before committing the code, please check if it passes all tests using (note: this will install some dependencies):
Before committing the code, please check if it passes tests, has adequate coverage, etc.
```bash
make qa
go test
go test -cover
```

View File

@ -138,6 +138,9 @@ func (b *BitSet) Len() uint {
// extendSetMaybe adds additional words to incorporate new bits if needed
func (b *BitSet) extendSetMaybe(i uint) {
if i >= b.length { // if we need more bits, make 'em
if i >= Cap() {
panic("You are exceeding the capacity")
}
nsize := wordsNeeded(i + 1)
if b.set == nil {
b.set = make([]uint64, nsize)
@ -160,7 +163,12 @@ func (b *BitSet) Test(i uint) bool {
return b.set[i>>log2WordSize]&(1<<(i&(wordSize-1))) != 0
}
// Set bit i to 1
// Set bit i to 1, the capacity of the bitset is automatically
// increased accordingly.
// If i>= Cap(), this function will panic.
// Warning: using a very large value for 'i'
// may lead to a memory shortage and a panic: the caller is responsible
// for providing sensible parameters in line with their memory capacity.
func (b *BitSet) Set(i uint) *BitSet {
b.extendSetMaybe(i)
b.set[i>>log2WordSize] |= 1 << (i & (wordSize - 1))
@ -176,7 +184,11 @@ func (b *BitSet) Clear(i uint) *BitSet {
return b
}
// SetTo sets bit i to value
// SetTo sets bit i to value.
// If i>= Cap(), this function will panic.
// Warning: using a very large value for 'i'
// may lead to a memory shortage and a panic: the caller is responsible
// for providing sensible parameters in line with their memory capacity.
func (b *BitSet) SetTo(i uint, value bool) *BitSet {
if value {
return b.Set(i)
@ -184,7 +196,11 @@ func (b *BitSet) SetTo(i uint, value bool) *BitSet {
return b.Clear(i)
}
// Flip bit at i
// Flip bit at i.
// If i>= Cap(), this function will panic.
// Warning: using a very large value for 'i'
// may lead to a memory shortage and a panic: the caller is responsible
// for providing sensible parameters in line with their memory capacity.
func (b *BitSet) Flip(i uint) *BitSet {
if i >= b.length {
return b.Set(i)
@ -193,26 +209,51 @@ func (b *BitSet) Flip(i uint) *BitSet {
return b
}
// Shrink shrinks BitSet to desired length in bits. It clears all bits > length
// and reduces the size and length of the set.
// Shrink shrinks BitSet so that the provided value is the last possible
// set value. It clears all bits > the provided index and reduces the size
// and length of the set.
//
// Note that the parameter value is not the new length in bits: it is the
// maximal value that can be stored in the bitset after the function call.
// The new length in bits is the parameter value + 1. Thus it is not possible
// to use this function to set the length to 0, the minimal value of the length
// after this function call is 1.
//
// A new slice is allocated to store the new bits, so you may see an increase in
// memory usage until the GC runs. Normally this should not be a problem, but if you
// have an extremely large BitSet its important to understand that the old BitSet will
// remain in memory until the GC frees it.
func (b *BitSet) Shrink(length uint) *BitSet {
idx := wordsNeeded(length + 1)
func (b *BitSet) Shrink(lastbitindex uint) *BitSet {
length := lastbitindex + 1
idx := wordsNeeded(length)
if idx > len(b.set) {
return b
}
shrunk := make([]uint64, idx)
copy(shrunk, b.set[:idx])
b.set = shrunk
b.length = length + 1
b.set[idx-1] &= (allBits >> (uint64(64) - uint64(length&(wordSize-1)) - 1))
b.length = length
b.set[idx-1] &= (allBits >> (uint64(64) - uint64(length&(wordSize-1))))
return b
}
// Compact shrinks BitSet to so that we preserve all set bits, while minimizing
// memory usage. Compact calls Shrink.
func (b *BitSet) Compact() *BitSet {
idx := len(b.set) - 1
for ; idx >= 0 && b.set[idx] == 0; idx-- {
}
newlength := uint((idx + 1) << log2WordSize)
if newlength >= b.length {
return b // nothing to do
}
if newlength > 0 {
return b.Shrink(newlength - 1)
}
// We preserve one word
return b.Shrink(63)
}
// InsertAt takes an index which indicates where a bit should be
// inserted. Then it shifts all the bits in the set to the left by 1, starting
// from the given index position, and sets the index position to 0.
@ -323,6 +364,9 @@ func (b *BitSet) DeleteAt(i uint) *BitSet {
// including possibly the current index
// along with an error code (true = valid, false = no set bit found)
// for i,e := v.NextSet(0); e; i,e = v.NextSet(i + 1) {...}
//
// Users concerned with performance may want to use NextSetMany to
// retrieve several values at once.
func (b *BitSet) NextSet(i uint) (uint, bool) {
x := int(i >> log2WordSize)
if x >= len(b.set) {
@ -358,6 +402,14 @@ func (b *BitSet) NextSet(i uint) (uint, bool) {
// j += 1
// }
//
//
// It is possible to retrieve all set bits as follow:
//
// indices := make([]uint, bitmap.Count())
// bitmap.NextSetMany(0, indices)
//
// However if bitmap.Count() is large, it might be preferable to
// use several calls to NextSetMany, for performance reasons.
func (b *BitSet) NextSetMany(i uint, buffer []uint) (uint, []uint) {
myanswer := buffer
capacity := cap(buffer)
@ -809,7 +861,7 @@ func (b *BitSet) ReadFrom(stream io.Reader) (int64, error) {
newset := New(uint(length))
if uint64(newset.length) != length {
return 0, errors.New("Unmarshalling error: type mismatch")
return 0, errors.New("unmarshalling error: type mismatch")
}
// Read remaining bytes as set

3
vendor/github.com/willf/bitset/go.mod generated vendored Normal file
View File

@ -0,0 +1,3 @@
module github.com/willf/bitset
go 1.14

0
vendor/github.com/willf/bitset/go.sum generated vendored Normal file
View File

4
vendor/modules.txt vendored
View File

@ -284,7 +284,7 @@ github.com/opencontainers/image-spec/specs-go/v1
github.com/opencontainers/runc/libcontainer/user
# github.com/opencontainers/runtime-spec v1.0.3-0.20200728170252-4d89ac9fbff6
github.com/opencontainers/runtime-spec/specs-go
# github.com/opencontainers/selinux v1.6.0
# github.com/opencontainers/selinux v1.8.0
github.com/opencontainers/selinux/go-selinux
github.com/opencontainers/selinux/go-selinux/label
github.com/opencontainers/selinux/pkg/pwalk
@ -336,7 +336,7 @@ github.com/uber/jaeger-client-go/utils
github.com/uber/jaeger-lib/metrics
# github.com/urfave/cli v1.22.2
github.com/urfave/cli
# github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243
# github.com/willf/bitset v1.1.11
github.com/willf/bitset
# go.etcd.io/bbolt v1.3.5
go.etcd.io/bbolt

View File

@ -23,16 +23,16 @@ import (
)
// NewWorkerOpt creates a WorkerOpt.
func NewWorkerOpt(root string, address, snapshotterName, ns string, labels map[string]string, dns *oci.DNSConfig, nopt netproviders.Opt, opts ...containerd.ClientOpt) (base.WorkerOpt, error) {
func NewWorkerOpt(root string, address, snapshotterName, ns string, labels map[string]string, dns *oci.DNSConfig, nopt netproviders.Opt, apparmorProfile string, opts ...containerd.ClientOpt) (base.WorkerOpt, error) {
opts = append(opts, containerd.WithDefaultNamespace(ns))
client, err := containerd.New(address, opts...)
if err != nil {
return base.WorkerOpt{}, errors.Wrapf(err, "failed to connect client to %q . make sure containerd is running", address)
}
return newContainerd(root, client, snapshotterName, ns, labels, dns, nopt)
return newContainerd(root, client, snapshotterName, ns, labels, dns, nopt, apparmorProfile)
}
func newContainerd(root string, client *containerd.Client, snapshotterName, ns string, labels map[string]string, dns *oci.DNSConfig, nopt netproviders.Opt) (base.WorkerOpt, error) {
func newContainerd(root string, client *containerd.Client, snapshotterName, ns string, labels map[string]string, dns *oci.DNSConfig, nopt netproviders.Opt, apparmorProfile string) (base.WorkerOpt, error) {
if strings.Contains(snapshotterName, "/") {
return base.WorkerOpt{}, errors.Errorf("bad snapshotter name: %q", snapshotterName)
}
@ -104,7 +104,7 @@ func newContainerd(root string, client *containerd.Client, snapshotterName, ns s
ID: id,
Labels: xlabels,
MetadataStore: md,
Executor: containerdexecutor.New(client, root, "", np, dns),
Executor: containerdexecutor.New(client, root, "", np, dns, apparmorProfile),
Snapshotter: snap,
ContentStore: cs,
Applier: winlayers.NewFileSystemApplierWithWindows(cs, df),

View File

@ -30,7 +30,7 @@ func newWorkerOpt(t *testing.T, addr string) (base.WorkerOpt, func()) {
tmpdir, err := ioutil.TempDir("", "workertest")
require.NoError(t, err)
cleanup := func() { os.RemoveAll(tmpdir) }
workerOpt, err := NewWorkerOpt(tmpdir, addr, "overlayfs", "buildkit-test", nil, nil, netproviders.Opt{Mode: "host"})
workerOpt, err := NewWorkerOpt(tmpdir, addr, "overlayfs", "buildkit-test", nil, nil, netproviders.Opt{Mode: "host"}, "")
require.NoError(t, err)
return workerOpt, cleanup
}

View File

@ -32,7 +32,7 @@ type SnapshotterFactory struct {
}
// NewWorkerOpt creates a WorkerOpt.
func NewWorkerOpt(root string, snFactory SnapshotterFactory, rootless bool, processMode oci.ProcessMode, labels map[string]string, idmap *idtools.IdentityMapping, nopt netproviders.Opt, dns *oci.DNSConfig, binary string) (base.WorkerOpt, error) {
func NewWorkerOpt(root string, snFactory SnapshotterFactory, rootless bool, processMode oci.ProcessMode, labels map[string]string, idmap *idtools.IdentityMapping, nopt netproviders.Opt, dns *oci.DNSConfig, binary, apparmorProfile string) (base.WorkerOpt, error) {
var opt base.WorkerOpt
name := "runc-" + snFactory.Name
root = filepath.Join(root, name)
@ -62,6 +62,7 @@ func NewWorkerOpt(root string, snFactory SnapshotterFactory, rootless bool, proc
ProcessMode: processMode,
IdentityMapping: idmap,
DNS: dns,
ApparmorProfile: apparmorProfile,
}, np)
if err != nil {
return opt, err

View File

@ -40,7 +40,7 @@ func newWorkerOpt(t *testing.T, processMode oci.ProcessMode) (base.WorkerOpt, fu
},
}
rootless := false
workerOpt, err := NewWorkerOpt(tmpdir, snFactory, rootless, processMode, nil, nil, netproviders.Opt{Mode: "host"}, nil, "")
workerOpt, err := NewWorkerOpt(tmpdir, snFactory, rootless, processMode, nil, nil, netproviders.Opt{Mode: "host"}, nil, "", "")
require.NoError(t, err)
return workerOpt, cleanup