Browse Source

vendor: github.com/opencontainers/selinux v1.6.0

full diff: https://github.com/opencontainers/selinux/compare/v1.5.2...v1.6.0

This also adds a new dependency: github.com/willf/bitset

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Sebastiaan van Stijn 4 years ago
parent
commit
245f2d922a

+ 2 - 1
vendor.conf

@@ -169,7 +169,8 @@ github.com/morikuni/aec                             39771216ff4c63d11f5e604076f9
 # metrics
 # metrics
 github.com/docker/go-metrics                        b619b3592b65de4f087d9f16863a7e6ff905973c # v0.0.1
 github.com/docker/go-metrics                        b619b3592b65de4f087d9f16863a7e6ff905973c # v0.0.1
 
 
-github.com/opencontainers/selinux                   c688bba66d7ecb448819836b96f9c416da8b0746 # v1.5.2
+github.com/opencontainers/selinux                   25504e34a9826d481f6e2903963ecaa881749124 # v1.6.0
+github.com/willf/bitset                             559910e8471e48d76d9e5a1ba15842dee77ad45d # v1.1.11
 
 
 
 
 # archive/tar
 # archive/tar

+ 5 - 1
vendor/github.com/opencontainers/selinux/README.md

@@ -4,7 +4,11 @@
 
 
 Common SELinux package used across the container ecosystem.
 Common SELinux package used across the container ecosystem.
 
 
-Please see the [godoc](https://godoc.org/github.com/opencontainers/selinux) for more information.
+## Usage
+
+When compiling consumers of this project, the `selinux` build tag must be used to enable selinux functionality.
+
+For complete documentation, see [godoc](https://godoc.org/github.com/opencontainers/selinux).
 
 
 ## Code of Conduct
 ## Code of Conduct
 
 

+ 21 - 0
vendor/github.com/opencontainers/selinux/go-selinux/doc.go

@@ -0,0 +1,21 @@
+/*
+Package selinux provides a high-level interface for interacting with selinux.
+
+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"
+
+	// Ensure that selinux is enforcing mode.
+	if selinux.EnforceMode() != selinux.Enforcing {
+		selinux.SetEnforceMode(selinux.Enforcing)
+	}
+
+*/
+package selinux

+ 1 - 1
vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go

@@ -73,9 +73,9 @@ func InitLabels(options []string) (plabel string, mlabel string, Err error) {
 				selinux.ReleaseLabel(processLabel)
 				selinux.ReleaseLabel(processLabel)
 			}
 			}
 			processLabel = pcon.Get()
 			processLabel = pcon.Get()
-			mountLabel = mcon.Get()
 			selinux.ReserveLabel(processLabel)
 			selinux.ReserveLabel(processLabel)
 		}
 		}
+		mountLabel = mcon.Get()
 	}
 	}
 	return processLabel, mountLabel, nil
 	return processLabel, mountLabel, nil
 }
 }

+ 0 - 1
vendor/github.com/opencontainers/selinux/go-selinux/label/label_stub.go

@@ -30,7 +30,6 @@ func Relabel(path string, fileLabel string, shared bool) error {
 // DisableSecOpt returns a security opt that can disable labeling
 // DisableSecOpt returns a security opt that can disable labeling
 // support for future container processes
 // support for future container processes
 func DisableSecOpt() []string {
 func DisableSecOpt() []string {
-	// TODO the selinux.DisableSecOpt stub returns []string{"disable"} instead of "nil"
 	return nil
 	return nil
 }
 }
 
 

+ 249 - 0
vendor/github.com/opencontainers/selinux/go-selinux/selinux.go

@@ -0,0 +1,249 @@
+package selinux
+
+import (
+	"github.com/pkg/errors"
+)
+
+const (
+	// Enforcing constant indicate SELinux is in enforcing mode
+	Enforcing = 1
+	// Permissive constant to indicate SELinux is in permissive mode
+	Permissive = 0
+	// Disabled constant to indicate SELinux is disabled
+	Disabled = -1
+
+	// DefaultCategoryRange is the upper bound on the category range
+	DefaultCategoryRange = uint32(1024)
+)
+
+var (
+	// ErrMCSAlreadyExists is returned when trying to allocate a duplicate MCS.
+	ErrMCSAlreadyExists = errors.New("MCS label already exists")
+	// ErrEmptyPath is returned when an empty path has been specified.
+	ErrEmptyPath = errors.New("empty path")
+
+	// InvalidLabel is returned when an invalid label is specified.
+	InvalidLabel = errors.New("Invalid Label")
+
+	// ErrIncomparable is returned two levels are not comparable
+	ErrIncomparable = errors.New("incomparable levels")
+	// ErrLevelSyntax is returned when a sensitivity or category do not have correct syntax in a level
+	ErrLevelSyntax = errors.New("invalid level syntax")
+
+	// CategoryRange allows the upper bound on the category range to be adjusted
+	CategoryRange = DefaultCategoryRange
+)
+
+// Context is a representation of the SELinux label broken into 4 parts
+type Context map[string]string
+
+// SetDisabled disables SELinux support for the package
+func SetDisabled() {
+	setDisabled()
+}
+
+// GetEnabled returns whether SELinux is currently enabled.
+func GetEnabled() bool {
+	return getEnabled()
+}
+
+// ClassIndex returns the int index for an object class in the loaded policy,
+// or -1 and an error
+func ClassIndex(class string) (int, error) {
+	return classIndex(class)
+}
+
+// SetFileLabel sets the SELinux label for this path or returns an error.
+func SetFileLabel(fpath string, label string) error {
+	return setFileLabel(fpath, label)
+}
+
+// FileLabel returns the SELinux label for this path or returns an error.
+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.
+func SetFSCreateLabel(label string) error {
+	return setFSCreateLabel(label)
+}
+
+// FSCreateLabel returns the default label the kernel which the kernel is using
+// for file system objects created by this task. "" indicates default.
+func FSCreateLabel() (string, error) {
+	return fsCreateLabel()
+}
+
+// CurrentLabel returns the SELinux label of the current process thread, or an error.
+func CurrentLabel() (string, error) {
+	return currentLabel()
+}
+
+// PidLabel returns the SELinux label of the given pid, or an error.
+func PidLabel(pid int) (string, error) {
+	return pidLabel(pid)
+}
+
+// ExecLabel returns the SELinux label that the kernel will use for any programs
+// that are executed by the current process thread, or an error.
+func ExecLabel() (string, error) {
+	return execLabel()
+}
+
+// CanonicalizeContext takes a context string and writes it to the kernel
+// the function then returns the context that the kernel will use. Use this
+// function to check if two contexts are equivalent
+func CanonicalizeContext(val string) (string, error) {
+	return canonicalizeContext(val)
+}
+
+// ComputeCreateContext requests the type transition from source to target for
+// class from the kernel.
+func ComputeCreateContext(source string, target string, class string) (string, error) {
+	return computeCreateContext(source, target, class)
+}
+
+// CalculateGlbLub computes the glb (greatest lower bound) and lub (least upper bound)
+// of a source and target range.
+// The glblub is calculated as the greater of the low sensitivities and
+// the lower of the high sensitivities and the and of each category bitset.
+func CalculateGlbLub(sourceRange, targetRange string) (string, error) {
+	return calculateGlbLub(sourceRange, targetRange)
+}
+
+// SetExecLabel sets the SELinux label that the kernel will use for any programs
+// that are executed by the current process thread, or an error.
+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.
+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
+func SetSocketLabel(label string) error {
+	return setSocketLabel(label)
+}
+
+// SocketLabel retrieves the current socket label setting
+func SocketLabel() (string, error) {
+	return socketLabel()
+}
+
+// PeerLabel retrieves the label of the client on the other side of a socket
+func PeerLabel(fd uintptr) (string, error) {
+	return peerLabel(fd)
+}
+
+// SetKeyLabel takes a process label and tells the kernel to assign the
+// label to the next kernel keyring that gets created
+func SetKeyLabel(label string) error {
+	return setKeyLabel(label)
+}
+
+// KeyLabel retrieves the current kernel keyring label setting
+func KeyLabel() (string, error) {
+	return keyLabel()
+}
+
+// Get returns the Context as a string
+func (c Context) Get() string {
+	return c.get()
+}
+
+// NewContext creates a new Context struct from the specified label
+func NewContext(label string) (Context, error) {
+	return newContext(label)
+}
+
+// ClearLabels clears all reserved labels
+func ClearLabels() {
+	clearLabels()
+}
+
+// ReserveLabel reserves the MLS/MCS level component of the specified label
+func ReserveLabel(label string) {
+	reserveLabel(label)
+}
+
+// EnforceMode returns the current SELinux mode Enforcing, Permissive, Disabled
+func EnforceMode() int {
+	return enforceMode()
+}
+
+// SetEnforceMode sets the current SELinux mode Enforcing, Permissive.
+// Disabled is not valid, since this needs to be set at boot time.
+func SetEnforceMode(mode int) error {
+	return setEnforceMode(mode)
+}
+
+// DefaultEnforceMode returns the systems default SELinux mode Enforcing,
+// Permissive or Disabled. Note this is is just the default at boot time.
+// EnforceMode tells you the systems current mode.
+func DefaultEnforceMode() int {
+	return defaultEnforceMode()
+}
+
+// ReleaseLabel un-reserves the MLS/MCS Level field of the specified label,
+// allowing it to be used by another process.
+func ReleaseLabel(label string) {
+	releaseLabel(label)
+}
+
+// ROFileLabel returns the specified SELinux readonly file label
+func ROFileLabel() string {
+	return roFileLabel()
+}
+
+// KVMContainerLabels returns the default processLabel and mountLabel to be used
+// for kvm containers by the calling process.
+func KVMContainerLabels() (string, string) {
+	return kvmContainerLabels()
+}
+
+// InitContainerLabels returns the default processLabel and file labels to be
+// used for containers running an init system like systemd by the calling process.
+func InitContainerLabels() (string, string) {
+	return initContainerLabels()
+}
+
+// ContainerLabels returns an allocated processLabel and fileLabel to be used for
+// container labeling by the calling process.
+func ContainerLabels() (processLabel string, fileLabel string) {
+	return containerLabels()
+}
+
+// SecurityCheckContext validates that the SELinux label is understood by the kernel
+func SecurityCheckContext(val string) error {
+	return securityCheckContext(val)
+}
+
+// CopyLevel returns a label with the MLS/MCS level from src label replaced on
+// the dest label.
+func CopyLevel(src, dest string) (string, error) {
+	return copyLevel(src, dest)
+}
+
+// Chcon changes the fpath file object to the SELinux label label.
+// If fpath is a directory and recurse is true, then Chcon walks the
+// directory tree setting the label.
+func Chcon(fpath string, label string, recurse bool) error {
+	return chcon(fpath, label, recurse)
+}
+
+// DupSecOpt takes an SELinux process label and returns security options that
+// can be used to set the SELinux Type and Level for future container processes.
+func DupSecOpt(src string) ([]string, error) {
+	return dupSecOpt(src)
+}
+
+// DisableSecOpt returns a security opt that can be used to disable SELinux
+// labeling support for future container processes.
+func DisableSecOpt() []string {
+	return disableSecOpt()
+}

+ 334 - 147
vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go

@@ -20,17 +20,12 @@ import (
 
 
 	"github.com/opencontainers/selinux/pkg/pwalk"
 	"github.com/opencontainers/selinux/pkg/pwalk"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
+	"github.com/willf/bitset"
 	"golang.org/x/sys/unix"
 	"golang.org/x/sys/unix"
 )
 )
 
 
 const (
 const (
-	// Enforcing constant indicate SELinux is in enforcing mode
-	Enforcing = 1
-	// Permissive constant to indicate SELinux is in permissive mode
-	Permissive = 0
-	// Disabled constant to indicate SELinux is disabled
-	Disabled = -1
-
+	minSensLen       = 2
 	contextFile      = "/usr/share/containers/selinux/contexts"
 	contextFile      = "/usr/share/containers/selinux/contexts"
 	selinuxDir       = "/etc/selinux/"
 	selinuxDir       = "/etc/selinux/"
 	selinuxConfig    = selinuxDir + "config"
 	selinuxConfig    = selinuxDir + "config"
@@ -49,17 +44,27 @@ type selinuxState struct {
 	sync.Mutex
 	sync.Mutex
 }
 }
 
 
+type level struct {
+	sens uint
+	cats *bitset.BitSet
+}
+
+type mlsRange struct {
+	low  *level
+	high *level
+}
+
+type levelItem byte
+
+const (
+	sensitivity levelItem = 's'
+	category    levelItem = 'c'
+)
+
 var (
 var (
-	// ErrMCSAlreadyExists is returned when trying to allocate a duplicate MCS.
-	ErrMCSAlreadyExists = errors.New("MCS label already exists")
-	// ErrEmptyPath is returned when an empty path has been specified.
-	ErrEmptyPath = errors.New("empty path")
-	// InvalidLabel is returned when an invalid label is specified.
-	InvalidLabel = errors.New("Invalid Label")
-
-	assignRegex = regexp.MustCompile(`^([^=]+)=(.*)$`)
-	roFileLabel string
-	state       = selinuxState{
+	assignRegex       = regexp.MustCompile(`^([^=]+)=(.*)$`)
+	readOnlyFileLabel string
+	state             = selinuxState{
 		mcsList: make(map[string]bool),
 		mcsList: make(map[string]bool),
 	}
 	}
 
 
@@ -68,9 +73,6 @@ var (
 	haveThreadSelf bool
 	haveThreadSelf bool
 )
 )
 
 
-// Context is a representation of the SELinux label broken into 4 parts
-type Context map[string]string
-
 func (s *selinuxState) setEnable(enabled bool) bool {
 func (s *selinuxState) setEnable(enabled bool) bool {
 	s.Lock()
 	s.Lock()
 	defer s.Unlock()
 	defer s.Unlock()
@@ -97,8 +99,8 @@ func (s *selinuxState) getEnabled() bool {
 	return s.setEnable(enabled)
 	return s.setEnable(enabled)
 }
 }
 
 
-// SetDisabled disables selinux support for the package
-func SetDisabled() {
+// setDisabled disables SELinux support for the package
+func setDisabled() {
 	state.setEnable(false)
 	state.setEnable(false)
 }
 }
 
 
@@ -190,15 +192,15 @@ func (s *selinuxState) getSELinuxfs() string {
 
 
 // getSelinuxMountPoint returns the path to the mountpoint of an selinuxfs
 // getSelinuxMountPoint returns the path to the mountpoint of an selinuxfs
 // filesystem or an empty string if no mountpoint is found.  Selinuxfs is
 // filesystem or an empty string if no mountpoint is found.  Selinuxfs is
-// a proc-like pseudo-filesystem that exposes the selinux policy API to
+// a proc-like pseudo-filesystem that exposes the SELinux policy API to
 // processes.  The existence of an selinuxfs mount is used to determine
 // processes.  The existence of an selinuxfs mount is used to determine
-// whether selinux is currently enabled or not.
+// whether SELinux is currently enabled or not.
 func getSelinuxMountPoint() string {
 func getSelinuxMountPoint() string {
 	return state.getSELinuxfs()
 	return state.getSELinuxfs()
 }
 }
 
 
-// GetEnabled returns whether selinux is currently enabled.
-func GetEnabled() bool {
+// getEnabled returns whether SELinux is currently enabled.
+func getEnabled() bool {
 	return state.getEnabled()
 	return state.getEnabled()
 }
 }
 
 
@@ -282,8 +284,9 @@ func readCon(fpath string) (string, error) {
 	return strings.Trim(retval, "\x00"), nil
 	return strings.Trim(retval, "\x00"), nil
 }
 }
 
 
-// ClassIndex returns the int index for an object class in the loaded policy, or -1 and an error
-func ClassIndex(class string) (int, error) {
+// classIndex returns the int index for an object class in the loaded policy,
+// or -1 and an error
+func classIndex(class string) (int, error) {
 	permpath := fmt.Sprintf("class/%s/index", class)
 	permpath := fmt.Sprintf("class/%s/index", class)
 	indexpath := filepath.Join(getSelinuxMountPoint(), permpath)
 	indexpath := filepath.Join(getSelinuxMountPoint(), permpath)
 
 
@@ -299,8 +302,8 @@ func ClassIndex(class string) (int, error) {
 	return index, nil
 	return index, nil
 }
 }
 
 
-// SetFileLabel sets the SELinux label for this path or returns an error.
-func SetFileLabel(fpath string, label string) error {
+// setFileLabel sets the SELinux label for this path or returns an error.
+func setFileLabel(fpath string, label string) error {
 	if fpath == "" {
 	if fpath == "" {
 		return ErrEmptyPath
 		return ErrEmptyPath
 	}
 	}
@@ -310,8 +313,8 @@ func SetFileLabel(fpath string, label string) error {
 	return nil
 	return nil
 }
 }
 
 
-// FileLabel returns the SELinux label for this path or returns an error.
-func FileLabel(fpath string) (string, error) {
+// fileLabel returns the SELinux label for this path or returns an error.
+func fileLabel(fpath string) (string, error) {
 	if fpath == "" {
 	if fpath == "" {
 		return "", ErrEmptyPath
 		return "", ErrEmptyPath
 	}
 	}
@@ -327,37 +330,31 @@ func FileLabel(fpath string) (string, error) {
 	return string(label), nil
 	return string(label), nil
 }
 }
 
 
-/*
-SetFSCreateLabel tells kernel the label to create all file system objects
-created by this task. Setting label="" to return to default.
-*/
-func SetFSCreateLabel(label string) error {
+// setFSCreateLabel tells kernel the label to create all file system objects
+// created by this task. Setting label="" to return to default.
+func setFSCreateLabel(label string) error {
 	return writeAttr("fscreate", label)
 	return writeAttr("fscreate", label)
 }
 }
 
 
-/*
-FSCreateLabel returns the default label the kernel which the kernel is using
-for file system objects created by this task. "" indicates default.
-*/
-func FSCreateLabel() (string, error) {
+// fsCreateLabel returns the default label the kernel which the kernel is using
+// for file system objects created by this task. "" indicates default.
+func fsCreateLabel() (string, error) {
 	return readAttr("fscreate")
 	return readAttr("fscreate")
 }
 }
 
 
-// CurrentLabel returns the SELinux label of the current process thread, or an error.
-func CurrentLabel() (string, error) {
+// currentLabel returns the SELinux label of the current process thread, or an error.
+func currentLabel() (string, error) {
 	return readAttr("current")
 	return readAttr("current")
 }
 }
 
 
-// PidLabel returns the SELinux label of the given pid, or an error.
-func PidLabel(pid int) (string, error) {
+// pidLabel returns the SELinux label of the given pid, or an error.
+func pidLabel(pid int) (string, error) {
 	return readCon(fmt.Sprintf("/proc/%d/attr/current", pid))
 	return readCon(fmt.Sprintf("/proc/%d/attr/current", pid))
 }
 }
 
 
-/*
-ExecLabel returns the SELinux label that the kernel will use for any programs
-that are executed by the current process thread, or an error.
-*/
-func ExecLabel() (string, error) {
+// ExecLabel returns the SELinux label that the kernel will use for any programs
+// that are executed by the current process thread, or an error.
+func execLabel() (string, error) {
 	return readAttr("exec")
 	return readAttr("exec")
 }
 }
 
 
@@ -366,7 +363,7 @@ func writeCon(fpath, val string) error {
 		return ErrEmptyPath
 		return ErrEmptyPath
 	}
 	}
 	if val == "" {
 	if val == "" {
-		if !GetEnabled() {
+		if !getEnabled() {
 			return nil
 			return nil
 		}
 		}
 	}
 	}
@@ -418,20 +415,17 @@ func writeAttr(attr, val string) error {
 	return writeCon(attrPath(attr), val)
 	return writeCon(attrPath(attr), val)
 }
 }
 
 
-/*
-CanonicalizeContext takes a context string and writes it to the kernel
-the function then returns the context that the kernel will use.  This function
-can be used to see if two contexts are equivalent
-*/
-func CanonicalizeContext(val string) (string, error) {
+// canonicalizeContext takes a context string and writes it to the kernel
+// the function then returns the context that the kernel will use. Use this
+// function to check if two contexts are equivalent
+func canonicalizeContext(val string) (string, error) {
 	return readWriteCon(filepath.Join(getSelinuxMountPoint(), "context"), val)
 	return readWriteCon(filepath.Join(getSelinuxMountPoint(), "context"), val)
 }
 }
 
 
-/*
-ComputeCreateContext requests the type transition from source to target for class  from the kernel.
-*/
-func ComputeCreateContext(source string, target string, class string) (string, error) {
-	classidx, err := ClassIndex(class)
+// computeCreateContext requests the type transition from source to target for
+// class from the kernel.
+func computeCreateContext(source string, target string, class string) (string, error) {
+	classidx, err := classIndex(class)
 	if err != nil {
 	if err != nil {
 		return "", err
 		return "", err
 	}
 	}
@@ -439,6 +433,217 @@ func ComputeCreateContext(source string, target string, class string) (string, e
 	return readWriteCon(filepath.Join(getSelinuxMountPoint(), "create"), fmt.Sprintf("%s %s %d", source, target, classidx))
 	return readWriteCon(filepath.Join(getSelinuxMountPoint(), "create"), fmt.Sprintf("%s %s %d", source, target, classidx))
 }
 }
 
 
+// catsToBitset stores categories in a bitset.
+func catsToBitset(cats string) (*bitset.BitSet, error) {
+	bitset := &bitset.BitSet{}
+
+	catlist := strings.Split(cats, ",")
+	for _, r := range catlist {
+		ranges := strings.SplitN(r, ".", 2)
+		if len(ranges) > 1 {
+			catstart, err := parseLevelItem(ranges[0], category)
+			if err != nil {
+				return nil, err
+			}
+			catend, err := parseLevelItem(ranges[1], category)
+			if err != nil {
+				return nil, err
+			}
+			for i := catstart; i <= catend; i++ {
+				bitset.Set(i)
+			}
+		} else {
+			cat, err := parseLevelItem(ranges[0], category)
+			if err != nil {
+				return nil, err
+			}
+			bitset.Set(cat)
+		}
+	}
+
+	return bitset, nil
+}
+
+// parseLevelItem parses and verifies that a sensitivity or category are valid
+func parseLevelItem(s string, sep levelItem) (uint, error) {
+	if len(s) < minSensLen || levelItem(s[0]) != sep {
+		return 0, ErrLevelSyntax
+	}
+	val, err := strconv.ParseUint(s[1:], 10, 32)
+	if err != nil {
+		return 0, err
+	}
+
+	return uint(val), nil
+}
+
+// parseLevel fills a level from a string that contains
+// a sensitivity and categories
+func (l *level) parseLevel(levelStr string) error {
+	lvl := strings.SplitN(levelStr, ":", 2)
+	sens, err := parseLevelItem(lvl[0], sensitivity)
+	if err != nil {
+		return errors.Wrap(err, "failed to parse sensitivity")
+	}
+	l.sens = sens
+	if len(lvl) > 1 {
+		cats, err := catsToBitset(lvl[1])
+		if err != nil {
+			return errors.Wrap(err, "failed to parse categories")
+		}
+		l.cats = cats
+	}
+
+	return nil
+}
+
+// rangeStrToMLSRange marshals a string representation of a range.
+func rangeStrToMLSRange(rangeStr string) (*mlsRange, error) {
+	mlsRange := &mlsRange{}
+	levelSlice := strings.SplitN(rangeStr, "-", 2)
+
+	switch len(levelSlice) {
+	// rangeStr that has a low and a high level, e.g. s4:c0.c1023-s6:c0.c1023
+	case 2:
+		mlsRange.high = &level{}
+		if err := mlsRange.high.parseLevel(levelSlice[1]); err != nil {
+			return nil, errors.Wrapf(err, "failed to parse high level %q", levelSlice[1])
+		}
+		fallthrough
+	// rangeStr that is single level, e.g. s6:c0,c3,c5,c30.c1023
+	case 1:
+		mlsRange.low = &level{}
+		if err := mlsRange.low.parseLevel(levelSlice[0]); err != nil {
+			return nil, errors.Wrapf(err, "failed to parse low level %q", levelSlice[0])
+		}
+	}
+
+	if mlsRange.high == nil {
+		mlsRange.high = mlsRange.low
+	}
+
+	return mlsRange, nil
+}
+
+// bitsetToStr takes a category bitset and returns it in the
+// canonical selinux syntax
+func bitsetToStr(c *bitset.BitSet) string {
+	var str string
+	i, e := c.NextSet(0)
+	len := 0
+	for e {
+		if len == 0 {
+			if str != "" {
+				str += ","
+			}
+			str += "c" + strconv.Itoa(int(i))
+		}
+
+		next, e := c.NextSet(i + 1)
+		if e {
+			// consecutive cats
+			if next == i+1 {
+				len++
+				i = next
+				continue
+			}
+		}
+		if len == 1 {
+			str += ",c" + strconv.Itoa(int(i))
+		} else if len > 1 {
+			str += ".c" + strconv.Itoa(int(i))
+		}
+		if !e {
+			break
+		}
+		len = 0
+		i = next
+	}
+
+	return str
+}
+
+func (l1 *level) equal(l2 *level) bool {
+	if l2 == nil || l1 == nil {
+		return l1 == l2
+	}
+	if l1.sens != l2.sens {
+		return false
+	}
+	return l1.cats.Equal(l2.cats)
+}
+
+// String returns an mlsRange as a string.
+func (m mlsRange) String() string {
+	low := "s" + strconv.Itoa(int(m.low.sens))
+	if m.low.cats != nil && m.low.cats.Count() > 0 {
+		low += ":" + bitsetToStr(m.low.cats)
+	}
+
+	if m.low.equal(m.high) {
+		return low
+	}
+
+	high := "s" + strconv.Itoa(int(m.high.sens))
+	if m.high.cats != nil && m.high.cats.Count() > 0 {
+		high += ":" + bitsetToStr(m.high.cats)
+	}
+
+	return low + "-" + high
+}
+
+func max(a, b uint) uint {
+	if a > b {
+		return a
+	}
+	return b
+}
+
+func min(a, b uint) uint {
+	if a < b {
+		return a
+	}
+	return b
+}
+
+// calculateGlbLub computes the glb (greatest lower bound) and lub (least upper bound)
+// of a source and target range.
+// The glblub is calculated as the greater of the low sensitivities and
+// the lower of the high sensitivities and the and of each category bitset.
+func calculateGlbLub(sourceRange, targetRange string) (string, error) {
+	s, err := rangeStrToMLSRange(sourceRange)
+	if err != nil {
+		return "", err
+	}
+	t, err := rangeStrToMLSRange(targetRange)
+	if err != nil {
+		return "", err
+	}
+
+	if s.high.sens < t.low.sens || t.high.sens < s.low.sens {
+		/* these ranges have no common sensitivities */
+		return "", ErrIncomparable
+	}
+
+	outrange := &mlsRange{low: &level{}, high: &level{}}
+
+	/* take the greatest of the low */
+	outrange.low.sens = max(s.low.sens, t.low.sens)
+
+	/* take the least of the high */
+	outrange.high.sens = min(s.high.sens, t.high.sens)
+
+	/* find the intersecting categories */
+	if s.low.cats != nil && t.low.cats != nil {
+		outrange.low.cats = s.low.cats.Intersection(t.low.cats)
+	}
+	if s.high.cats != nil && t.high.cats != nil {
+		outrange.high.cats = s.high.cats.Intersection(t.high.cats)
+	}
+
+	return outrange.String(), nil
+}
+
 func readWriteCon(fpath string, val string) (string, error) {
 func readWriteCon(fpath string, val string) (string, error) {
 	if fpath == "" {
 	if fpath == "" {
 		return "", ErrEmptyPath
 		return "", ErrEmptyPath
@@ -461,41 +666,37 @@ func readWriteCon(fpath string, val string) (string, error) {
 	return strings.Trim(retval, "\x00"), nil
 	return strings.Trim(retval, "\x00"), nil
 }
 }
 
 
-/*
-SetExecLabel sets the SELinux label that the kernel will use for any programs
-that are executed by the current process thread, or an error.
-*/
-func SetExecLabel(label 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.
+func setExecLabel(label string) error {
 	return writeAttr("exec", label)
 	return writeAttr("exec", label)
 }
 }
 
 
-/*
-SetTaskLabel sets the SELinux label for the current thread, or an error.
-This requires the dyntransition permission.
-*/
-func SetTaskLabel(label string) error {
+// setTaskLabel sets the SELinux label for the current thread, or an error.
+// This requires the dyntransition permission.
+func setTaskLabel(label string) error {
 	return writeAttr("current", label)
 	return writeAttr("current", label)
 }
 }
 
 
-// SetSocketLabel takes a process label and tells the kernel to assign the
+// 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
-func SetSocketLabel(label string) error {
+func setSocketLabel(label string) error {
 	return writeAttr("sockcreate", label)
 	return writeAttr("sockcreate", label)
 }
 }
 
 
-// SocketLabel retrieves the current socket label setting
-func SocketLabel() (string, error) {
+// socketLabel retrieves the current socket label setting
+func socketLabel() (string, error) {
 	return readAttr("sockcreate")
 	return readAttr("sockcreate")
 }
 }
 
 
-// PeerLabel retrieves the label of the client on the other side of a socket
-func PeerLabel(fd uintptr) (string, error) {
+// peerLabel retrieves the label of the client on the other side of a socket
+func peerLabel(fd uintptr) (string, error) {
 	return unix.GetsockoptString(int(fd), unix.SOL_SOCKET, unix.SO_PEERSEC)
 	return unix.GetsockoptString(int(fd), unix.SOL_SOCKET, unix.SO_PEERSEC)
 }
 }
 
 
-// SetKeyLabel takes a process label and tells the kernel to assign the
+// 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
-func SetKeyLabel(label string) error {
+func setKeyLabel(label string) error {
 	err := writeCon("/proc/self/attr/keycreate", label)
 	err := writeCon("/proc/self/attr/keycreate", label)
 	if os.IsNotExist(errors.Cause(err)) {
 	if os.IsNotExist(errors.Cause(err)) {
 		return nil
 		return nil
@@ -506,21 +707,21 @@ func SetKeyLabel(label string) error {
 	return err
 	return err
 }
 }
 
 
-// KeyLabel retrieves the current kernel keyring label setting
-func KeyLabel() (string, error) {
+// keyLabel retrieves the current kernel keyring label setting
+func keyLabel() (string, error) {
 	return readCon("/proc/self/attr/keycreate")
 	return readCon("/proc/self/attr/keycreate")
 }
 }
 
 
-// Get returns the Context as a string
-func (c Context) Get() string {
+// get returns the Context as a string
+func (c Context) get() string {
 	if c["level"] != "" {
 	if c["level"] != "" {
 		return fmt.Sprintf("%s:%s:%s:%s", c["user"], c["role"], c["type"], c["level"])
 		return fmt.Sprintf("%s:%s:%s:%s", c["user"], c["role"], c["type"], c["level"])
 	}
 	}
 	return fmt.Sprintf("%s:%s:%s", c["user"], c["role"], c["type"])
 	return fmt.Sprintf("%s:%s:%s", c["user"], c["role"], c["type"])
 }
 }
 
 
-// NewContext creates a new Context struct from the specified label
-func NewContext(label string) (Context, error) {
+// newContext creates a new Context struct from the specified label
+func newContext(label string) (Context, error) {
 	c := make(Context)
 	c := make(Context)
 
 
 	if len(label) != 0 {
 	if len(label) != 0 {
@@ -538,15 +739,15 @@ func NewContext(label string) (Context, error) {
 	return c, nil
 	return c, nil
 }
 }
 
 
-// ClearLabels clears all reserved labels
-func ClearLabels() {
+// clearLabels clears all reserved labels
+func clearLabels() {
 	state.Lock()
 	state.Lock()
 	state.mcsList = make(map[string]bool)
 	state.mcsList = make(map[string]bool)
 	state.Unlock()
 	state.Unlock()
 }
 }
 
 
-// ReserveLabel reserves the MLS/MCS level component of the specified label
-func ReserveLabel(label string) {
+// reserveLabel reserves the MLS/MCS level component of the specified label
+func reserveLabel(label string) {
 	if len(label) != 0 {
 	if len(label) != 0 {
 		con := strings.SplitN(label, ":", 4)
 		con := strings.SplitN(label, ":", 4)
 		if len(con) > 3 {
 		if len(con) > 3 {
@@ -559,8 +760,8 @@ func selinuxEnforcePath() string {
 	return path.Join(getSelinuxMountPoint(), "enforce")
 	return path.Join(getSelinuxMountPoint(), "enforce")
 }
 }
 
 
-// EnforceMode returns the current SELinux mode Enforcing, Permissive, Disabled
-func EnforceMode() int {
+// enforceMode returns the current SELinux mode Enforcing, Permissive, Disabled
+func enforceMode() int {
 	var enforce int
 	var enforce int
 
 
 	enforceB, err := ioutil.ReadFile(selinuxEnforcePath())
 	enforceB, err := ioutil.ReadFile(selinuxEnforcePath())
@@ -574,20 +775,16 @@ func EnforceMode() int {
 	return enforce
 	return enforce
 }
 }
 
 
-/*
-SetEnforceMode sets the current SELinux mode Enforcing, Permissive.
-Disabled is not valid, since this needs to be set at boot time.
-*/
-func SetEnforceMode(mode int) error {
+// setEnforceMode sets the current SELinux mode Enforcing, Permissive.
+// Disabled is not valid, since this needs to be set at boot time.
+func setEnforceMode(mode int) error {
 	return ioutil.WriteFile(selinuxEnforcePath(), []byte(strconv.Itoa(mode)), 0644)
 	return ioutil.WriteFile(selinuxEnforcePath(), []byte(strconv.Itoa(mode)), 0644)
 }
 }
 
 
-/*
-DefaultEnforceMode returns the systems default SELinux mode Enforcing,
-Permissive or Disabled. Note this is is just the default at boot time.
-EnforceMode tells you the systems current mode.
-*/
-func DefaultEnforceMode() int {
+// defaultEnforceMode returns the systems default SELinux mode Enforcing,
+// Permissive or Disabled. Note this is is just the default at boot time.
+// EnforceMode tells you the systems current mode.
+func defaultEnforceMode() int {
 	switch readConfig(selinuxTag) {
 	switch readConfig(selinuxTag) {
 	case "enforcing":
 	case "enforcing":
 		return Enforcing
 		return Enforcing
@@ -667,11 +864,9 @@ func uniqMcs(catRange uint32) string {
 	return mcs
 	return mcs
 }
 }
 
 
-/*
-ReleaseLabel will unreserve the MLS/MCS Level field of the specified label.
-Allowing it to be used by another process.
-*/
-func ReleaseLabel(label string) {
+// releaseLabel un-reserves the MLS/MCS Level field of the specified label,
+// allowing it to be used by another process.
+func releaseLabel(label string) {
 	if len(label) != 0 {
 	if len(label) != 0 {
 		con := strings.SplitN(label, ":", 4)
 		con := strings.SplitN(label, ":", 4)
 		if len(con) > 3 {
 		if len(con) > 3 {
@@ -680,9 +875,9 @@ func ReleaseLabel(label string) {
 	}
 	}
 }
 }
 
 
-// ROFileLabel returns the specified SELinux readonly file label
-func ROFileLabel() string {
-	return roFileLabel
+// roFileLabel returns the specified SELinux readonly file label
+func roFileLabel() string {
+	return readOnlyFileLabel
 }
 }
 
 
 func openContextFile() (*os.File, error) {
 func openContextFile() (*os.File, error) {
@@ -737,11 +932,9 @@ func loadLabels() map[string]string {
 	return labels
 	return labels
 }
 }
 
 
-/*
-KVMContainerLabels returns the default processLabel and mountLabel to be used
-for kvm containers by the calling process.
-*/
-func KVMContainerLabels() (string, string) {
+// kvmContainerLabels returns the default processLabel and mountLabel to be used
+// for kvm containers by the calling process.
+func kvmContainerLabels() (string, string) {
 	processLabel := labels["kvm_process"]
 	processLabel := labels["kvm_process"]
 	if processLabel == "" {
 	if processLabel == "" {
 		processLabel = labels["process"]
 		processLabel = labels["process"]
@@ -750,11 +943,9 @@ func KVMContainerLabels() (string, string) {
 	return addMcs(processLabel, labels["file"])
 	return addMcs(processLabel, labels["file"])
 }
 }
 
 
-/*
-InitContainerLabels returns the default processLabel and file labels to be
-used for containers running an init system like systemd by the calling process.
-*/
-func InitContainerLabels() (string, string) {
+// initContainerLabels returns the default processLabel and file labels to be
+// used for containers running an init system like systemd by the calling process.
+func initContainerLabels() (string, string) {
 	processLabel := labels["init_process"]
 	processLabel := labels["init_process"]
 	if processLabel == "" {
 	if processLabel == "" {
 		processLabel = labels["process"]
 		processLabel = labels["process"]
@@ -763,25 +954,23 @@ func InitContainerLabels() (string, string) {
 	return addMcs(processLabel, labels["file"])
 	return addMcs(processLabel, labels["file"])
 }
 }
 
 
-/*
-ContainerLabels returns an allocated processLabel and fileLabel to be used for
-container labeling by the calling process.
-*/
-func ContainerLabels() (processLabel string, fileLabel string) {
-	if !GetEnabled() {
+// containerLabels returns an allocated processLabel and fileLabel to be used for
+// container labeling by the calling process.
+func containerLabels() (processLabel string, fileLabel string) {
+	if !getEnabled() {
 		return "", ""
 		return "", ""
 	}
 	}
 
 
 	processLabel = labels["process"]
 	processLabel = labels["process"]
 	fileLabel = labels["file"]
 	fileLabel = labels["file"]
-	roFileLabel = labels["ro_file"]
+	readOnlyFileLabel = labels["ro_file"]
 
 
 	if processLabel == "" || fileLabel == "" {
 	if processLabel == "" || fileLabel == "" {
 		return "", fileLabel
 		return "", fileLabel
 	}
 	}
 
 
-	if roFileLabel == "" {
-		roFileLabel = fileLabel
+	if readOnlyFileLabel == "" {
+		readOnlyFileLabel = fileLabel
 	}
 	}
 
 
 	return addMcs(processLabel, fileLabel)
 	return addMcs(processLabel, fileLabel)
@@ -790,7 +979,7 @@ func ContainerLabels() (processLabel string, fileLabel string) {
 func addMcs(processLabel, fileLabel string) (string, string) {
 func addMcs(processLabel, fileLabel string) (string, string) {
 	scon, _ := NewContext(processLabel)
 	scon, _ := NewContext(processLabel)
 	if scon["level"] != "" {
 	if scon["level"] != "" {
-		mcs := uniqMcs(1024)
+		mcs := uniqMcs(CategoryRange)
 		scon["level"] = mcs
 		scon["level"] = mcs
 		processLabel = scon.Get()
 		processLabel = scon.Get()
 		scon, _ = NewContext(fileLabel)
 		scon, _ = NewContext(fileLabel)
@@ -800,16 +989,14 @@ func addMcs(processLabel, fileLabel string) (string, string) {
 	return processLabel, fileLabel
 	return processLabel, fileLabel
 }
 }
 
 
-// SecurityCheckContext validates that the SELinux label is understood by the kernel
-func SecurityCheckContext(val string) error {
+// securityCheckContext validates that the SELinux label is understood by the kernel
+func securityCheckContext(val string) error {
 	return ioutil.WriteFile(path.Join(getSelinuxMountPoint(), "context"), []byte(val), 0644)
 	return ioutil.WriteFile(path.Join(getSelinuxMountPoint(), "context"), []byte(val), 0644)
 }
 }
 
 
-/*
-CopyLevel returns a label with the MLS/MCS level from src label replaced on
-the dest label.
-*/
-func CopyLevel(src, dest string) (string, error) {
+// copyLevel returns a label with the MLS/MCS level from src label replaced on
+// the dest label.
+func copyLevel(src, dest string) (string, error) {
 	if src == "" {
 	if src == "" {
 		return "", nil
 		return "", nil
 	}
 	}
@@ -833,7 +1020,7 @@ func CopyLevel(src, dest string) (string, error) {
 	return tcon.Get(), nil
 	return tcon.Get(), nil
 }
 }
 
 
-// Prevent users from relabing system files
+// Prevent users from relabeling system files
 func badPrefix(fpath string) error {
 func badPrefix(fpath string) error {
 	if fpath == "" {
 	if fpath == "" {
 		return ErrEmptyPath
 		return ErrEmptyPath
@@ -848,10 +1035,10 @@ func badPrefix(fpath string) error {
 	return nil
 	return nil
 }
 }
 
 
-// Chcon changes the fpath file object to the SELinux label label.
-// If fpath is a directory and recurse is true, Chcon will walk the
+// chcon changes the fpath file object to the SELinux label label.
+// If fpath is a directory and recurse is true, then chcon walks the
 // directory tree setting the label.
 // directory tree setting the label.
-func Chcon(fpath string, label string, recurse bool) error {
+func chcon(fpath string, label string, recurse bool) error {
 	if fpath == "" {
 	if fpath == "" {
 		return ErrEmptyPath
 		return ErrEmptyPath
 	}
 	}
@@ -876,9 +1063,9 @@ func Chcon(fpath string, label string, recurse bool) error {
 	})
 	})
 }
 }
 
 
-// DupSecOpt takes an SELinux process label and returns security options that
+// dupSecOpt takes an SELinux process label and returns security options that
 // can be used to set the SELinux Type and Level for future container processes.
 // can be used to set the SELinux Type and Level for future container processes.
-func DupSecOpt(src string) ([]string, error) {
+func dupSecOpt(src string) ([]string, error) {
 	if src == "" {
 	if src == "" {
 		return nil, nil
 		return nil, nil
 	}
 	}
@@ -903,8 +1090,8 @@ func DupSecOpt(src string) ([]string, error) {
 	return dup, nil
 	return dup, nil
 }
 }
 
 
-// DisableSecOpt returns a security opt that can be used to disable SELinux
+// disableSecOpt returns a security opt that can be used to disable SELinux
 // labeling support for future container processes.
 // labeling support for future container processes.
-func DisableSecOpt() []string {
+func disableSecOpt() []string {
 	return []string{"disable"}
 	return []string{"disable"}
 }
 }

+ 42 - 148
vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go

@@ -2,253 +2,147 @@
 
 
 package selinux
 package selinux
 
 
-import (
-	"errors"
-)
-
-const (
-	// Enforcing constant indicate SELinux is in enforcing mode
-	Enforcing = 1
-	// Permissive constant to indicate SELinux is in permissive mode
-	Permissive = 0
-	// Disabled constant to indicate SELinux is disabled
-	Disabled = -1
-)
-
-var (
-	// ErrMCSAlreadyExists is returned when trying to allocate a duplicate MCS.
-	ErrMCSAlreadyExists = errors.New("MCS label already exists")
-	// ErrEmptyPath is returned when an empty path has been specified.
-	ErrEmptyPath = errors.New("empty path")
-)
-
-// Context is a representation of the SELinux label broken into 4 parts
-type Context map[string]string
-
-// SetDisabled disables selinux support for the package
-func SetDisabled() {
-	return
-}
-
-// GetEnabled returns whether selinux is currently enabled.
-func GetEnabled() bool {
+func setDisabled() {
+}
+
+func getEnabled() bool {
 	return false
 	return false
 }
 }
 
 
-// ClassIndex returns the int index for an object class in the loaded policy, or -1 and an error
-func ClassIndex(class string) (int, error) {
+func classIndex(class string) (int, error) {
 	return -1, nil
 	return -1, nil
 }
 }
 
 
-// SetFileLabel sets the SELinux label for this path or returns an error.
-func SetFileLabel(fpath string, label string) error {
+func setFileLabel(fpath string, label string) error {
 	return nil
 	return nil
 }
 }
 
 
-// FileLabel returns the SELinux label for this path or returns an error.
-func FileLabel(fpath string) (string, error) {
+func fileLabel(fpath string) (string, error) {
 	return "", nil
 	return "", nil
 }
 }
 
 
-/*
-SetFSCreateLabel tells kernel the label to create all file system objects
-created by this task. Setting label="" to return to default.
-*/
-func SetFSCreateLabel(label string) error {
+func setFSCreateLabel(label string) error {
 	return nil
 	return nil
 }
 }
 
 
-/*
-FSCreateLabel returns the default label the kernel which the kernel is using
-for file system objects created by this task. "" indicates default.
-*/
-func FSCreateLabel() (string, error) {
+func fsCreateLabel() (string, error) {
+	return "", nil
+}
+
+func currentLabel() (string, error) {
 	return "", nil
 	return "", nil
 }
 }
 
 
-// CurrentLabel returns the SELinux label of the current process thread, or an error.
-func CurrentLabel() (string, error) {
+func pidLabel(pid int) (string, error) {
 	return "", nil
 	return "", nil
 }
 }
 
 
-// PidLabel returns the SELinux label of the given pid, or an error.
-func PidLabel(pid int) (string, error) {
+func execLabel() (string, error) {
 	return "", nil
 	return "", nil
 }
 }
 
 
-/*
-ExecLabel returns the SELinux label that the kernel will use for any programs
-that are executed by the current process thread, or an error.
-*/
-func ExecLabel() (string, error) {
+func canonicalizeContext(val string) (string, error) {
 	return "", nil
 	return "", nil
 }
 }
 
 
-/*
-CanonicalizeContext takes a context string and writes it to the kernel
-the function then returns the context that the kernel will use.  This function
-can be used to see if two contexts are equivalent
-*/
-func CanonicalizeContext(val string) (string, error) {
+func computeCreateContext(source string, target string, class string) (string, error) {
 	return "", nil
 	return "", nil
 }
 }
 
 
-/*
-ComputeCreateContext requests the type transition from source to target for class  from the kernel.
-*/
-func ComputeCreateContext(source string, target string, class string) (string, error) {
+func calculateGlbLub(sourceRange, targetRange string) (string, error) {
 	return "", nil
 	return "", nil
 }
 }
 
 
-/*
-SetExecLabel sets the SELinux label that the kernel will use for any programs
-that are executed by the current process thread, or an error.
-*/
-func SetExecLabel(label string) error {
+func setExecLabel(label string) error {
 	return nil
 	return nil
 }
 }
 
 
-/*
-SetTaskLabel sets the SELinux label for the current thread, or an error.
-This requires the dyntransition permission.
-*/
-func SetTaskLabel(label string) error {
+func setTaskLabel(label string) error {
 	return nil
 	return nil
 }
 }
 
 
-/*
-SetSocketLabel sets the SELinux label that the kernel will use for any programs
-that are executed by the current process thread, or an error.
-*/
-func SetSocketLabel(label string) error {
+func setSocketLabel(label string) error {
 	return nil
 	return nil
 }
 }
 
 
-// SocketLabel retrieves the current socket label setting
-func SocketLabel() (string, error) {
+func socketLabel() (string, error) {
 	return "", nil
 	return "", nil
 }
 }
 
 
-// PeerLabel retrieves the label of the client on the other side of a socket
-func PeerLabel(fd uintptr) (string, error) {
+func peerLabel(fd uintptr) (string, error) {
 	return "", nil
 	return "", nil
 }
 }
 
 
-// SetKeyLabel takes a process label and tells the kernel to assign the
-// label to the next kernel keyring that gets created
-func SetKeyLabel(label string) error {
+func setKeyLabel(label string) error {
 	return nil
 	return nil
 }
 }
 
 
-// KeyLabel retrieves the current kernel keyring label setting
-func KeyLabel() (string, error) {
+func keyLabel() (string, error) {
 	return "", nil
 	return "", nil
 }
 }
 
 
-// Get returns the Context as a string
-func (c Context) Get() string {
+func (c Context) get() string {
 	return ""
 	return ""
 }
 }
 
 
-// NewContext creates a new Context struct from the specified label
-func NewContext(label string) (Context, error) {
+func newContext(label string) (Context, error) {
 	c := make(Context)
 	c := make(Context)
 	return c, nil
 	return c, nil
 }
 }
 
 
-// ClearLabels clears all reserved MLS/MCS levels
-func ClearLabels() {
-	return
+func clearLabels() {
 }
 }
 
 
-// ReserveLabel reserves the MLS/MCS level component of the specified label
-func ReserveLabel(label string) {
-	return
+func reserveLabel(label string) {
 }
 }
 
 
-// EnforceMode returns the current SELinux mode Enforcing, Permissive, Disabled
-func EnforceMode() int {
+func enforceMode() int {
 	return Disabled
 	return Disabled
 }
 }
 
 
-/*
-SetEnforceMode sets the current SELinux mode Enforcing, Permissive.
-Disabled is not valid, since this needs to be set at boot time.
-*/
-func SetEnforceMode(mode int) error {
+func setEnforceMode(mode int) error {
 	return nil
 	return nil
 }
 }
 
 
-/*
-DefaultEnforceMode returns the systems default SELinux mode Enforcing,
-Permissive or Disabled. Note this is is just the default at boot time.
-EnforceMode tells you the systems current mode.
-*/
-func DefaultEnforceMode() int {
+func defaultEnforceMode() int {
 	return Disabled
 	return Disabled
 }
 }
 
 
-/*
-ReleaseLabel will unreserve the MLS/MCS Level field of the specified label.
-Allowing it to be used by another process.
-*/
-func ReleaseLabel(label string) {
-	return
+func releaseLabel(label string) {
 }
 }
 
 
-// ROFileLabel returns the specified SELinux readonly file label
-func ROFileLabel() string {
+func roFileLabel() string {
 	return ""
 	return ""
 }
 }
 
 
-// KVMContainerLabels returns the default processLabel and mountLabel to be used
-// for kvm containers by the calling process.
-func KVMContainerLabels() (string, string) {
+func kvmContainerLabels() (string, string) {
 	return "", ""
 	return "", ""
 }
 }
 
 
-// InitContainerLabels returns the default processLabel and file labels to be
-// used for containers running an init system like systemd by the calling
-func InitContainerLabels() (string, string) {
+func initContainerLabels() (string, string) {
 	return "", ""
 	return "", ""
 }
 }
 
 
-/*
-ContainerLabels returns an allocated processLabel and fileLabel to be used for
-container labeling by the calling process.
-*/
-func ContainerLabels() (processLabel string, fileLabel string) {
+func containerLabels() (processLabel string, fileLabel string) {
 	return "", ""
 	return "", ""
 }
 }
 
 
-// SecurityCheckContext validates that the SELinux label is understood by the kernel
-func SecurityCheckContext(val string) error {
+func securityCheckContext(val string) error {
 	return nil
 	return nil
 }
 }
 
 
-/*
-CopyLevel returns a label with the MLS/MCS level from src label replaced on
-the dest label.
-*/
-func CopyLevel(src, dest string) (string, error) {
+func copyLevel(src, dest string) (string, error) {
 	return "", nil
 	return "", nil
 }
 }
 
 
-// Chcon changes the `fpath` file object to the SELinux label `label`.
-// If `fpath` is a directory and `recurse`` is true, Chcon will walk the
-// directory tree setting the label.
-func Chcon(fpath string, label string, recurse bool) error {
+func chcon(fpath string, label string, recurse bool) error {
 	return nil
 	return nil
 }
 }
 
 
-// DupSecOpt takes an SELinux process label and returns security options that
-// can be used to set the SELinux Type and Level for future container processes.
-func DupSecOpt(src string) ([]string, error) {
+func dupSecOpt(src string) ([]string, error) {
 	return nil, nil
 	return nil, nil
 }
 }
 
 
-// DisableSecOpt returns a security opt that can be used to disable SELinux
-// labeling support for future container processes.
-func DisableSecOpt() []string {
+func disableSecOpt() []string {
 	return []string{"disable"}
 	return []string{"disable"}
 }
 }

+ 2 - 1
vendor/github.com/opencontainers/selinux/go.mod

@@ -3,6 +3,7 @@ module github.com/opencontainers/selinux
 go 1.13
 go 1.13
 
 
 require (
 require (
-	github.com/pkg/errors v0.8.1
+	github.com/pkg/errors v0.9.1
+	github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243
 	golang.org/x/sys v0.0.0-20191115151921-52ab43148777
 	golang.org/x/sys v0.0.0-20191115151921-52ab43148777
 )
 )

+ 6 - 2
vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go

@@ -48,7 +48,11 @@ func WalkN(root string, walkFn WalkFunc, num int) error {
 	errCh := make(chan error, 1) // get the first error, ignore others
 	errCh := make(chan error, 1) // get the first error, ignore others
 
 
 	// Start walking a tree asap
 	// Start walking a tree asap
-	var err error
+	var (
+		err error
+		wg  sync.WaitGroup
+	)
+	wg.Add(1)
 	go func() {
 	go func() {
 		err = filepath.Walk(root, func(p string, info os.FileInfo, err error) error {
 		err = filepath.Walk(root, func(p string, info os.FileInfo, err error) error {
 			if err != nil {
 			if err != nil {
@@ -68,9 +72,9 @@ func WalkN(root string, walkFn WalkFunc, num int) error {
 		if err == nil {
 		if err == nil {
 			close(files)
 			close(files)
 		}
 		}
+		wg.Done()
 	}()
 	}()
 
 
-	var wg sync.WaitGroup
 	wg.Add(num)
 	wg.Add(num)
 	for i := 0; i < num; i++ {
 	for i := 0; i < num; i++ {
 		go func() {
 		go func() {

+ 27 - 0
vendor/github.com/willf/bitset/LICENSE

@@ -0,0 +1,27 @@
+Copyright (c) 2014 Will Fitzgerald. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 94 - 0
vendor/github.com/willf/bitset/README.md

@@ -0,0 +1,94 @@
+# bitset
+
+*Go language library to map between non-negative integers and boolean values*
+
+[![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)
+[![PkgGoDev](https://pkg.go.dev/badge/github.com/willf/bitset?tab=doc)](https://pkg.go.dev/github.com/willf/bitset?tab=doc)
+
+
+## Description
+
+Package bitset implements bitsets, a mapping between non-negative integers and boolean values.
+It should be more efficient than map[uint] bool.
+
+It provides methods for setting, clearing, flipping, and testing individual integers.
+
+But it also provides set intersection, union, difference, complement, and symmetric operations, as well as tests to check whether any, all, or no bits are set, and querying a bitset's current length and number of positive bits.
+
+BitSets are expanded to the size of the largest set bit; the memory allocation is approximately Max bits, where Max is the largest set bit. BitSets are never shrunk. On creation, a hint can be given for the number of bits that will be used.
+
+Many of the methods, including Set, Clear, and Flip, return a BitSet pointer, which allows for chaining.
+
+### Example use:
+
+```go
+package main
+
+import (
+	"fmt"
+	"math/rand"
+
+	"github.com/willf/bitset"
+)
+
+func main() {
+	fmt.Printf("Hello from BitSet!\n")
+	var b bitset.BitSet
+	// play some Go Fish
+	for i := 0; i < 100; i++ {
+		card1 := uint(rand.Intn(52))
+		card2 := uint(rand.Intn(52))
+		b.Set(card1)
+		if b.Test(card2) {
+			fmt.Println("Go Fish!")
+		}
+		b.Clear(card1)
+	}
+
+	// Chaining
+	b.Set(10).Set(11)
+
+	for i, e := b.NextSet(0); e; i, e = b.NextSet(i + 1) {
+		fmt.Println("The following bit is set:", i)
+	}
+	if b.Intersection(bitset.New(100).Set(10)).Count() == 1 {
+		fmt.Println("Intersection works.")
+	} else {
+		fmt.Println("Intersection doesn't work???")
+	}
+}
+```
+
+As an alternative to BitSets, one should check out the 'big' package, which provides a (less set-theoretical) view of bitsets.
+
+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
+
+Go 1.9 introduced a native `math/bits` library. We provide backward compatibility to Go 1.7, which might be removed.
+
+It is possible that a later version will match the `math/bits` return signature for counts (which is `int`, rather than our library's `unit64`). If so, the version will be bumped.
+
+## Installation
+
+```bash
+go get github.com/willf/bitset
+```
+
+## Contributing
+
+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/)")
+
+## Running all tests
+
+Before committing the code, please check if it passes tests, has adequate coverage, etc.
+```bash
+go test
+go test -cover
+```

+ 931 - 0
vendor/github.com/willf/bitset/bitset.go

@@ -0,0 +1,931 @@
+/*
+Package bitset implements bitsets, a mapping
+between non-negative integers and boolean values. It should be more
+efficient than map[uint] bool.
+
+It provides methods for setting, clearing, flipping, and testing
+individual integers.
+
+But it also provides set intersection, union, difference,
+complement, and symmetric operations, as well as tests to
+check whether any, all, or no bits are set, and querying a
+bitset's current length and number of positive bits.
+
+BitSets are expanded to the size of the largest set bit; the
+memory allocation is approximately Max bits, where Max is
+the largest set bit. BitSets are never shrunk. On creation,
+a hint can be given for the number of bits that will be used.
+
+Many of the methods, including Set,Clear, and Flip, return
+a BitSet pointer, which allows for chaining.
+
+Example use:
+
+	import "bitset"
+	var b BitSet
+	b.Set(10).Set(11)
+	if b.Test(1000) {
+		b.Clear(1000)
+	}
+	if B.Intersection(bitset.New(100).Set(10)).Count() > 1 {
+		fmt.Println("Intersection works.")
+	}
+
+As an alternative to BitSets, one should check out the 'big' package,
+which provides a (less set-theoretical) view of bitsets.
+
+*/
+package bitset
+
+import (
+	"bufio"
+	"bytes"
+	"encoding/base64"
+	"encoding/binary"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io"
+	"strconv"
+)
+
+// the wordSize of a bit set
+const wordSize = uint(64)
+
+// log2WordSize is lg(wordSize)
+const log2WordSize = uint(6)
+
+// allBits has every bit set
+const allBits uint64 = 0xffffffffffffffff
+
+// default binary BigEndian
+var binaryOrder binary.ByteOrder = binary.BigEndian
+
+// default json encoding base64.URLEncoding
+var base64Encoding = base64.URLEncoding
+
+// Base64StdEncoding Marshal/Unmarshal BitSet with base64.StdEncoding(Default: base64.URLEncoding)
+func Base64StdEncoding() { base64Encoding = base64.StdEncoding }
+
+// LittleEndian Marshal/Unmarshal Binary as Little Endian(Default: binary.BigEndian)
+func LittleEndian() { binaryOrder = binary.LittleEndian }
+
+// A BitSet is a set of bits. The zero value of a BitSet is an empty set of length 0.
+type BitSet struct {
+	length uint
+	set    []uint64
+}
+
+// Error is used to distinguish errors (panics) generated in this package.
+type Error string
+
+// safeSet will fixup b.set to be non-nil and return the field value
+func (b *BitSet) safeSet() []uint64 {
+	if b.set == nil {
+		b.set = make([]uint64, wordsNeeded(0))
+	}
+	return b.set
+}
+
+// From is a constructor used to create a BitSet from an array of integers
+func From(buf []uint64) *BitSet {
+	return &BitSet{uint(len(buf)) * 64, buf}
+}
+
+// Bytes returns the bitset as array of integers
+func (b *BitSet) Bytes() []uint64 {
+	return b.set
+}
+
+// wordsNeeded calculates the number of words needed for i bits
+func wordsNeeded(i uint) int {
+	if i > (Cap() - wordSize + 1) {
+		return int(Cap() >> log2WordSize)
+	}
+	return int((i + (wordSize - 1)) >> log2WordSize)
+}
+
+// New creates a new BitSet with a hint that length bits will be required
+func New(length uint) (bset *BitSet) {
+	defer func() {
+		if r := recover(); r != nil {
+			bset = &BitSet{
+				0,
+				make([]uint64, 0),
+			}
+		}
+	}()
+
+	bset = &BitSet{
+		length,
+		make([]uint64, wordsNeeded(length)),
+	}
+
+	return bset
+}
+
+// Cap returns the total possible capacity, or number of bits
+func Cap() uint {
+	return ^uint(0)
+}
+
+// Len returns the number of bits in the BitSet.
+// Note the difference to method Count, see example.
+func (b *BitSet) Len() uint {
+	return b.length
+}
+
+// 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)
+		} else if cap(b.set) >= nsize {
+			b.set = b.set[:nsize] // fast resize
+		} else if len(b.set) < nsize {
+			newset := make([]uint64, nsize, 2*nsize) // increase capacity 2x
+			copy(newset, b.set)
+			b.set = newset
+		}
+		b.length = i + 1
+	}
+}
+
+// Test whether bit i is set.
+func (b *BitSet) Test(i uint) bool {
+	if i >= b.length {
+		return false
+	}
+	return b.set[i>>log2WordSize]&(1<<(i&(wordSize-1))) != 0
+}
+
+// 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))
+	return b
+}
+
+// Clear bit i to 0
+func (b *BitSet) Clear(i uint) *BitSet {
+	if i >= b.length {
+		return b
+	}
+	b.set[i>>log2WordSize] &^= 1 << (i & (wordSize - 1))
+	return b
+}
+
+// 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)
+	}
+	return b.Clear(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)
+	}
+	b.set[i>>log2WordSize] ^= 1 << (i & (wordSize - 1))
+	return b
+}
+
+// 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(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
+	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.
+//
+// Depending on the size of your BitSet, and where you are inserting the new entry,
+// this method could be extremely slow and in some cases might cause the entire BitSet
+// to be recopied.
+func (b *BitSet) InsertAt(idx uint) *BitSet {
+	insertAtElement := (idx >> log2WordSize)
+
+	// if length of set is a multiple of wordSize we need to allocate more space first
+	if b.isLenExactMultiple() {
+		b.set = append(b.set, uint64(0))
+	}
+
+	var i uint
+	for i = uint(len(b.set) - 1); i > insertAtElement; i-- {
+		// all elements above the position where we want to insert can simply by shifted
+		b.set[i] <<= 1
+
+		// we take the most significant bit of the previous element and set it as
+		// the least significant bit of the current element
+		b.set[i] |= (b.set[i-1] & 0x8000000000000000) >> 63
+	}
+
+	// generate a mask to extract the data that we need to shift left
+	// within the element where we insert a bit
+	dataMask := ^(uint64(1)<<uint64(idx&(wordSize-1)) - 1)
+
+	// extract that data that we'll shift
+	data := b.set[i] & dataMask
+
+	// set the positions of the data mask to 0 in the element where we insert
+	b.set[i] &= ^dataMask
+
+	// shift data mask to the left and insert its data to the slice element
+	b.set[i] |= data << 1
+
+	// add 1 to length of BitSet
+	b.length++
+
+	return b
+}
+
+// String creates a string representation of the Bitmap
+func (b *BitSet) String() string {
+	// follows code from https://github.com/RoaringBitmap/roaring
+	var buffer bytes.Buffer
+	start := []byte("{")
+	buffer.Write(start)
+	counter := 0
+	i, e := b.NextSet(0)
+	for e {
+		counter = counter + 1
+		// to avoid exhausting the memory
+		if counter > 0x40000 {
+			buffer.WriteString("...")
+			break
+		}
+		buffer.WriteString(strconv.FormatInt(int64(i), 10))
+		i, e = b.NextSet(i + 1)
+		if e {
+			buffer.WriteString(",")
+		}
+	}
+	buffer.WriteString("}")
+	return buffer.String()
+}
+
+// DeleteAt deletes the bit at the given index position from
+// within the bitset
+// All the bits residing on the left of the deleted bit get
+// shifted right by 1
+// The running time of this operation may potentially be
+// relatively slow, O(length)
+func (b *BitSet) DeleteAt(i uint) *BitSet {
+	// the index of the slice element where we'll delete a bit
+	deleteAtElement := i >> log2WordSize
+
+	// generate a mask for the data that needs to be shifted right
+	// within that slice element that gets modified
+	dataMask := ^((uint64(1) << (i & (wordSize - 1))) - 1)
+
+	// extract the data that we'll shift right from the slice element
+	data := b.set[deleteAtElement] & dataMask
+
+	// set the masked area to 0 while leaving the rest as it is
+	b.set[deleteAtElement] &= ^dataMask
+
+	// shift the previously extracted data to the right and then
+	// set it in the previously masked area
+	b.set[deleteAtElement] |= (data >> 1) & dataMask
+
+	// loop over all the consecutive slice elements to copy each
+	// lowest bit into the highest position of the previous element,
+	// then shift the entire content to the right by 1
+	for i := int(deleteAtElement) + 1; i < len(b.set); i++ {
+		b.set[i-1] |= (b.set[i] & 1) << 63
+		b.set[i] >>= 1
+	}
+
+	b.length = b.length - 1
+
+	return b
+}
+
+// NextSet returns the next bit set from the specified index,
+// 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) {
+		return 0, false
+	}
+	w := b.set[x]
+	w = w >> (i & (wordSize - 1))
+	if w != 0 {
+		return i + trailingZeroes64(w), true
+	}
+	x = x + 1
+	for x < len(b.set) {
+		if b.set[x] != 0 {
+			return uint(x)*wordSize + trailingZeroes64(b.set[x]), true
+		}
+		x = x + 1
+
+	}
+	return 0, false
+}
+
+// NextSetMany returns many next bit sets from the specified index,
+// including possibly the current index and up to cap(buffer).
+// If the returned slice has len zero, then no more set bits were found
+//
+//    buffer := make([]uint, 256) // this should be reused
+//    j := uint(0)
+//    j, buffer = bitmap.NextSetMany(j, buffer)
+//    for ; len(buffer) > 0; j, buffer = bitmap.NextSetMany(j,buffer) {
+//     for k := range buffer {
+//      do something with buffer[k]
+//     }
+//     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)
+	x := int(i >> log2WordSize)
+	if x >= len(b.set) || capacity == 0 {
+		return 0, myanswer[:0]
+	}
+	skip := i & (wordSize - 1)
+	word := b.set[x] >> skip
+	myanswer = myanswer[:capacity]
+	size := int(0)
+	for word != 0 {
+		r := trailingZeroes64(word)
+		t := word & ((^word) + 1)
+		myanswer[size] = r + i
+		size++
+		if size == capacity {
+			goto End
+		}
+		word = word ^ t
+	}
+	x++
+	for idx, word := range b.set[x:] {
+		for word != 0 {
+			r := trailingZeroes64(word)
+			t := word & ((^word) + 1)
+			myanswer[size] = r + (uint(x+idx) << 6)
+			size++
+			if size == capacity {
+				goto End
+			}
+			word = word ^ t
+		}
+	}
+End:
+	if size > 0 {
+		return myanswer[size-1], myanswer[:size]
+	}
+	return 0, myanswer[:0]
+}
+
+// NextClear returns the next clear bit from the specified index,
+// including possibly the current index
+// along with an error code (true = valid, false = no bit found i.e. all bits are set)
+func (b *BitSet) NextClear(i uint) (uint, bool) {
+	x := int(i >> log2WordSize)
+	if x >= len(b.set) {
+		return 0, false
+	}
+	w := b.set[x]
+	w = w >> (i & (wordSize - 1))
+	wA := allBits >> (i & (wordSize - 1))
+	index := i + trailingZeroes64(^w)
+	if w != wA && index < b.length {
+		return index, true
+	}
+	x++
+	for x < len(b.set) {
+		index = uint(x)*wordSize + trailingZeroes64(^b.set[x])
+		if b.set[x] != allBits && index < b.length {
+			return index, true
+		}
+		x++
+	}
+	return 0, false
+}
+
+// ClearAll clears the entire BitSet
+func (b *BitSet) ClearAll() *BitSet {
+	if b != nil && b.set != nil {
+		for i := range b.set {
+			b.set[i] = 0
+		}
+	}
+	return b
+}
+
+// wordCount returns the number of words used in a bit set
+func (b *BitSet) wordCount() int {
+	return len(b.set)
+}
+
+// Clone this BitSet
+func (b *BitSet) Clone() *BitSet {
+	c := New(b.length)
+	if b.set != nil { // Clone should not modify current object
+		copy(c.set, b.set)
+	}
+	return c
+}
+
+// Copy into a destination BitSet
+// Returning the size of the destination BitSet
+// like array copy
+func (b *BitSet) Copy(c *BitSet) (count uint) {
+	if c == nil {
+		return
+	}
+	if b.set != nil { // Copy should not modify current object
+		copy(c.set, b.set)
+	}
+	count = c.length
+	if b.length < c.length {
+		count = b.length
+	}
+	return
+}
+
+// Count (number of set bits).
+// Also known as "popcount" or "popularity count".
+func (b *BitSet) Count() uint {
+	if b != nil && b.set != nil {
+		return uint(popcntSlice(b.set))
+	}
+	return 0
+}
+
+// Equal tests the equivalence of two BitSets.
+// False if they are of different sizes, otherwise true
+// only if all the same bits are set
+func (b *BitSet) Equal(c *BitSet) bool {
+	if c == nil || b == nil {
+		return c == b
+	}
+	if b.length != c.length {
+		return false
+	}
+	if b.length == 0 { // if they have both length == 0, then could have nil set
+		return true
+	}
+	// testing for equality shoud not transform the bitset (no call to safeSet)
+
+	for p, v := range b.set {
+		if c.set[p] != v {
+			return false
+		}
+	}
+	return true
+}
+
+func panicIfNull(b *BitSet) {
+	if b == nil {
+		panic(Error("BitSet must not be null"))
+	}
+}
+
+// Difference of base set and other set
+// This is the BitSet equivalent of &^ (and not)
+func (b *BitSet) Difference(compare *BitSet) (result *BitSet) {
+	panicIfNull(b)
+	panicIfNull(compare)
+	result = b.Clone() // clone b (in case b is bigger than compare)
+	l := int(compare.wordCount())
+	if l > int(b.wordCount()) {
+		l = int(b.wordCount())
+	}
+	for i := 0; i < l; i++ {
+		result.set[i] = b.set[i] &^ compare.set[i]
+	}
+	return
+}
+
+// DifferenceCardinality computes the cardinality of the differnce
+func (b *BitSet) DifferenceCardinality(compare *BitSet) uint {
+	panicIfNull(b)
+	panicIfNull(compare)
+	l := int(compare.wordCount())
+	if l > int(b.wordCount()) {
+		l = int(b.wordCount())
+	}
+	cnt := uint64(0)
+	cnt += popcntMaskSlice(b.set[:l], compare.set[:l])
+	cnt += popcntSlice(b.set[l:])
+	return uint(cnt)
+}
+
+// InPlaceDifference computes the difference of base set and other set
+// This is the BitSet equivalent of &^ (and not)
+func (b *BitSet) InPlaceDifference(compare *BitSet) {
+	panicIfNull(b)
+	panicIfNull(compare)
+	l := int(compare.wordCount())
+	if l > int(b.wordCount()) {
+		l = int(b.wordCount())
+	}
+	for i := 0; i < l; i++ {
+		b.set[i] &^= compare.set[i]
+	}
+}
+
+// Convenience function: return two bitsets ordered by
+// increasing length. Note: neither can be nil
+func sortByLength(a *BitSet, b *BitSet) (ap *BitSet, bp *BitSet) {
+	if a.length <= b.length {
+		ap, bp = a, b
+	} else {
+		ap, bp = b, a
+	}
+	return
+}
+
+// Intersection of base set and other set
+// This is the BitSet equivalent of & (and)
+func (b *BitSet) Intersection(compare *BitSet) (result *BitSet) {
+	panicIfNull(b)
+	panicIfNull(compare)
+	b, compare = sortByLength(b, compare)
+	result = New(b.length)
+	for i, word := range b.set {
+		result.set[i] = word & compare.set[i]
+	}
+	return
+}
+
+// IntersectionCardinality computes the cardinality of the union
+func (b *BitSet) IntersectionCardinality(compare *BitSet) uint {
+	panicIfNull(b)
+	panicIfNull(compare)
+	b, compare = sortByLength(b, compare)
+	cnt := popcntAndSlice(b.set, compare.set)
+	return uint(cnt)
+}
+
+// InPlaceIntersection destructively computes the intersection of
+// base set and the compare set.
+// This is the BitSet equivalent of & (and)
+func (b *BitSet) InPlaceIntersection(compare *BitSet) {
+	panicIfNull(b)
+	panicIfNull(compare)
+	l := int(compare.wordCount())
+	if l > int(b.wordCount()) {
+		l = int(b.wordCount())
+	}
+	for i := 0; i < l; i++ {
+		b.set[i] &= compare.set[i]
+	}
+	for i := l; i < len(b.set); i++ {
+		b.set[i] = 0
+	}
+	if compare.length > 0 {
+		b.extendSetMaybe(compare.length - 1)
+	}
+}
+
+// Union of base set and other set
+// This is the BitSet equivalent of | (or)
+func (b *BitSet) Union(compare *BitSet) (result *BitSet) {
+	panicIfNull(b)
+	panicIfNull(compare)
+	b, compare = sortByLength(b, compare)
+	result = compare.Clone()
+	for i, word := range b.set {
+		result.set[i] = word | compare.set[i]
+	}
+	return
+}
+
+// UnionCardinality computes the cardinality of the uniton of the base set
+// and the compare set.
+func (b *BitSet) UnionCardinality(compare *BitSet) uint {
+	panicIfNull(b)
+	panicIfNull(compare)
+	b, compare = sortByLength(b, compare)
+	cnt := popcntOrSlice(b.set, compare.set)
+	if len(compare.set) > len(b.set) {
+		cnt += popcntSlice(compare.set[len(b.set):])
+	}
+	return uint(cnt)
+}
+
+// InPlaceUnion creates the destructive union of base set and compare set.
+// This is the BitSet equivalent of | (or).
+func (b *BitSet) InPlaceUnion(compare *BitSet) {
+	panicIfNull(b)
+	panicIfNull(compare)
+	l := int(compare.wordCount())
+	if l > int(b.wordCount()) {
+		l = int(b.wordCount())
+	}
+	if compare.length > 0 {
+		b.extendSetMaybe(compare.length - 1)
+	}
+	for i := 0; i < l; i++ {
+		b.set[i] |= compare.set[i]
+	}
+	if len(compare.set) > l {
+		for i := l; i < len(compare.set); i++ {
+			b.set[i] = compare.set[i]
+		}
+	}
+}
+
+// SymmetricDifference of base set and other set
+// This is the BitSet equivalent of ^ (xor)
+func (b *BitSet) SymmetricDifference(compare *BitSet) (result *BitSet) {
+	panicIfNull(b)
+	panicIfNull(compare)
+	b, compare = sortByLength(b, compare)
+	// compare is bigger, so clone it
+	result = compare.Clone()
+	for i, word := range b.set {
+		result.set[i] = word ^ compare.set[i]
+	}
+	return
+}
+
+// SymmetricDifferenceCardinality computes the cardinality of the symmetric difference
+func (b *BitSet) SymmetricDifferenceCardinality(compare *BitSet) uint {
+	panicIfNull(b)
+	panicIfNull(compare)
+	b, compare = sortByLength(b, compare)
+	cnt := popcntXorSlice(b.set, compare.set)
+	if len(compare.set) > len(b.set) {
+		cnt += popcntSlice(compare.set[len(b.set):])
+	}
+	return uint(cnt)
+}
+
+// InPlaceSymmetricDifference creates the destructive SymmetricDifference of base set and other set
+// This is the BitSet equivalent of ^ (xor)
+func (b *BitSet) InPlaceSymmetricDifference(compare *BitSet) {
+	panicIfNull(b)
+	panicIfNull(compare)
+	l := int(compare.wordCount())
+	if l > int(b.wordCount()) {
+		l = int(b.wordCount())
+	}
+	if compare.length > 0 {
+		b.extendSetMaybe(compare.length - 1)
+	}
+	for i := 0; i < l; i++ {
+		b.set[i] ^= compare.set[i]
+	}
+	if len(compare.set) > l {
+		for i := l; i < len(compare.set); i++ {
+			b.set[i] = compare.set[i]
+		}
+	}
+}
+
+// Is the length an exact multiple of word sizes?
+func (b *BitSet) isLenExactMultiple() bool {
+	return b.length%wordSize == 0
+}
+
+// Clean last word by setting unused bits to 0
+func (b *BitSet) cleanLastWord() {
+	if !b.isLenExactMultiple() {
+		b.set[len(b.set)-1] &= allBits >> (wordSize - b.length%wordSize)
+	}
+}
+
+// Complement computes the (local) complement of a biset (up to length bits)
+func (b *BitSet) Complement() (result *BitSet) {
+	panicIfNull(b)
+	result = New(b.length)
+	for i, word := range b.set {
+		result.set[i] = ^word
+	}
+	result.cleanLastWord()
+	return
+}
+
+// All returns true if all bits are set, false otherwise. Returns true for
+// empty sets.
+func (b *BitSet) All() bool {
+	panicIfNull(b)
+	return b.Count() == b.length
+}
+
+// None returns true if no bit is set, false otherwise. Returns true for
+// empty sets.
+func (b *BitSet) None() bool {
+	panicIfNull(b)
+	if b != nil && b.set != nil {
+		for _, word := range b.set {
+			if word > 0 {
+				return false
+			}
+		}
+		return true
+	}
+	return true
+}
+
+// Any returns true if any bit is set, false otherwise
+func (b *BitSet) Any() bool {
+	panicIfNull(b)
+	return !b.None()
+}
+
+// IsSuperSet returns true if this is a superset of the other set
+func (b *BitSet) IsSuperSet(other *BitSet) bool {
+	for i, e := other.NextSet(0); e; i, e = other.NextSet(i + 1) {
+		if !b.Test(i) {
+			return false
+		}
+	}
+	return true
+}
+
+// IsStrictSuperSet returns true if this is a strict superset of the other set
+func (b *BitSet) IsStrictSuperSet(other *BitSet) bool {
+	return b.Count() > other.Count() && b.IsSuperSet(other)
+}
+
+// DumpAsBits dumps a bit set as a string of bits
+func (b *BitSet) DumpAsBits() string {
+	if b.set == nil {
+		return "."
+	}
+	buffer := bytes.NewBufferString("")
+	i := len(b.set) - 1
+	for ; i >= 0; i-- {
+		fmt.Fprintf(buffer, "%064b.", b.set[i])
+	}
+	return buffer.String()
+}
+
+// BinaryStorageSize returns the binary storage requirements
+func (b *BitSet) BinaryStorageSize() int {
+	return binary.Size(uint64(0)) + binary.Size(b.set)
+}
+
+// WriteTo writes a BitSet to a stream
+func (b *BitSet) WriteTo(stream io.Writer) (int64, error) {
+	length := uint64(b.length)
+
+	// Write length
+	err := binary.Write(stream, binaryOrder, length)
+	if err != nil {
+		return 0, err
+	}
+
+	// Write set
+	err = binary.Write(stream, binaryOrder, b.set)
+	return int64(b.BinaryStorageSize()), err
+}
+
+// ReadFrom reads a BitSet from a stream written using WriteTo
+func (b *BitSet) ReadFrom(stream io.Reader) (int64, error) {
+	var length uint64
+
+	// Read length first
+	err := binary.Read(stream, binaryOrder, &length)
+	if err != nil {
+		return 0, err
+	}
+	newset := New(uint(length))
+
+	if uint64(newset.length) != length {
+		return 0, errors.New("unmarshalling error: type mismatch")
+	}
+
+	// Read remaining bytes as set
+	err = binary.Read(stream, binaryOrder, newset.set)
+	if err != nil {
+		return 0, err
+	}
+
+	*b = *newset
+	return int64(b.BinaryStorageSize()), nil
+}
+
+// MarshalBinary encodes a BitSet into a binary form and returns the result.
+func (b *BitSet) MarshalBinary() ([]byte, error) {
+	var buf bytes.Buffer
+	writer := bufio.NewWriter(&buf)
+
+	_, err := b.WriteTo(writer)
+	if err != nil {
+		return []byte{}, err
+	}
+
+	err = writer.Flush()
+
+	return buf.Bytes(), err
+}
+
+// UnmarshalBinary decodes the binary form generated by MarshalBinary.
+func (b *BitSet) UnmarshalBinary(data []byte) error {
+	buf := bytes.NewReader(data)
+	reader := bufio.NewReader(buf)
+
+	_, err := b.ReadFrom(reader)
+
+	return err
+}
+
+// MarshalJSON marshals a BitSet as a JSON structure
+func (b *BitSet) MarshalJSON() ([]byte, error) {
+	buffer := bytes.NewBuffer(make([]byte, 0, b.BinaryStorageSize()))
+	_, err := b.WriteTo(buffer)
+	if err != nil {
+		return nil, err
+	}
+
+	// URLEncode all bytes
+	return json.Marshal(base64Encoding.EncodeToString(buffer.Bytes()))
+}
+
+// UnmarshalJSON unmarshals a BitSet from JSON created using MarshalJSON
+func (b *BitSet) UnmarshalJSON(data []byte) error {
+	// Unmarshal as string
+	var s string
+	err := json.Unmarshal(data, &s)
+	if err != nil {
+		return err
+	}
+
+	// URLDecode string
+	buf, err := base64Encoding.DecodeString(s)
+	if err != nil {
+		return err
+	}
+
+	_, err = b.ReadFrom(bytes.NewReader(buf))
+	return err
+}

+ 3 - 0
vendor/github.com/willf/bitset/go.mod

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

+ 53 - 0
vendor/github.com/willf/bitset/popcnt.go

@@ -0,0 +1,53 @@
+package bitset
+
+// bit population count, take from
+// https://code.google.com/p/go/issues/detail?id=4988#c11
+// credit: https://code.google.com/u/arnehormann/
+func popcount(x uint64) (n uint64) {
+	x -= (x >> 1) & 0x5555555555555555
+	x = (x>>2)&0x3333333333333333 + x&0x3333333333333333
+	x += x >> 4
+	x &= 0x0f0f0f0f0f0f0f0f
+	x *= 0x0101010101010101
+	return x >> 56
+}
+
+func popcntSliceGo(s []uint64) uint64 {
+	cnt := uint64(0)
+	for _, x := range s {
+		cnt += popcount(x)
+	}
+	return cnt
+}
+
+func popcntMaskSliceGo(s, m []uint64) uint64 {
+	cnt := uint64(0)
+	for i := range s {
+		cnt += popcount(s[i] &^ m[i])
+	}
+	return cnt
+}
+
+func popcntAndSliceGo(s, m []uint64) uint64 {
+	cnt := uint64(0)
+	for i := range s {
+		cnt += popcount(s[i] & m[i])
+	}
+	return cnt
+}
+
+func popcntOrSliceGo(s, m []uint64) uint64 {
+	cnt := uint64(0)
+	for i := range s {
+		cnt += popcount(s[i] | m[i])
+	}
+	return cnt
+}
+
+func popcntXorSliceGo(s, m []uint64) uint64 {
+	cnt := uint64(0)
+	for i := range s {
+		cnt += popcount(s[i] ^ m[i])
+	}
+	return cnt
+}

+ 45 - 0
vendor/github.com/willf/bitset/popcnt_19.go

@@ -0,0 +1,45 @@
+// +build go1.9
+
+package bitset
+
+import "math/bits"
+
+func popcntSlice(s []uint64) uint64 {
+	var cnt int
+	for _, x := range s {
+		cnt += bits.OnesCount64(x)
+	}
+	return uint64(cnt)
+}
+
+func popcntMaskSlice(s, m []uint64) uint64 {
+	var cnt int
+	for i := range s {
+		cnt += bits.OnesCount64(s[i] &^ m[i])
+	}
+	return uint64(cnt)
+}
+
+func popcntAndSlice(s, m []uint64) uint64 {
+	var cnt int
+	for i := range s {
+		cnt += bits.OnesCount64(s[i] & m[i])
+	}
+	return uint64(cnt)
+}
+
+func popcntOrSlice(s, m []uint64) uint64 {
+	var cnt int
+	for i := range s {
+		cnt += bits.OnesCount64(s[i] | m[i])
+	}
+	return uint64(cnt)
+}
+
+func popcntXorSlice(s, m []uint64) uint64 {
+	var cnt int
+	for i := range s {
+		cnt += bits.OnesCount64(s[i] ^ m[i])
+	}
+	return uint64(cnt)
+}

+ 68 - 0
vendor/github.com/willf/bitset/popcnt_amd64.go

@@ -0,0 +1,68 @@
+// +build !go1.9
+// +build amd64,!appengine
+
+package bitset
+
+// *** the following functions are defined in popcnt_amd64.s
+
+//go:noescape
+
+func hasAsm() bool
+
+// useAsm is a flag used to select the GO or ASM implementation of the popcnt function
+var useAsm = hasAsm()
+
+//go:noescape
+
+func popcntSliceAsm(s []uint64) uint64
+
+//go:noescape
+
+func popcntMaskSliceAsm(s, m []uint64) uint64
+
+//go:noescape
+
+func popcntAndSliceAsm(s, m []uint64) uint64
+
+//go:noescape
+
+func popcntOrSliceAsm(s, m []uint64) uint64
+
+//go:noescape
+
+func popcntXorSliceAsm(s, m []uint64) uint64
+
+func popcntSlice(s []uint64) uint64 {
+	if useAsm {
+		return popcntSliceAsm(s)
+	}
+	return popcntSliceGo(s)
+}
+
+func popcntMaskSlice(s, m []uint64) uint64 {
+	if useAsm {
+		return popcntMaskSliceAsm(s, m)
+	}
+	return popcntMaskSliceGo(s, m)
+}
+
+func popcntAndSlice(s, m []uint64) uint64 {
+	if useAsm {
+		return popcntAndSliceAsm(s, m)
+	}
+	return popcntAndSliceGo(s, m)
+}
+
+func popcntOrSlice(s, m []uint64) uint64 {
+	if useAsm {
+		return popcntOrSliceAsm(s, m)
+	}
+	return popcntOrSliceGo(s, m)
+}
+
+func popcntXorSlice(s, m []uint64) uint64 {
+	if useAsm {
+		return popcntXorSliceAsm(s, m)
+	}
+	return popcntXorSliceGo(s, m)
+}

+ 104 - 0
vendor/github.com/willf/bitset/popcnt_amd64.s

@@ -0,0 +1,104 @@
+// +build !go1.9
+// +build amd64,!appengine
+
+TEXT ·hasAsm(SB),4,$0-1
+MOVQ $1, AX
+CPUID
+SHRQ $23, CX
+ANDQ $1, CX
+MOVB CX, ret+0(FP)
+RET
+
+#define POPCNTQ_DX_DX BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0xd2
+
+TEXT ·popcntSliceAsm(SB),4,$0-32
+XORQ	AX, AX
+MOVQ	s+0(FP), SI
+MOVQ	s_len+8(FP), CX
+TESTQ	CX, CX
+JZ		popcntSliceEnd
+popcntSliceLoop:
+BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0x16 // POPCNTQ (SI), DX
+ADDQ	DX, AX
+ADDQ	$8, SI
+LOOP	popcntSliceLoop
+popcntSliceEnd:
+MOVQ	AX, ret+24(FP)
+RET
+
+TEXT ·popcntMaskSliceAsm(SB),4,$0-56
+XORQ	AX, AX
+MOVQ	s+0(FP), SI
+MOVQ	s_len+8(FP), CX
+TESTQ	CX, CX
+JZ		popcntMaskSliceEnd
+MOVQ	m+24(FP), DI
+popcntMaskSliceLoop:
+MOVQ	(DI), DX
+NOTQ	DX
+ANDQ	(SI), DX
+POPCNTQ_DX_DX
+ADDQ	DX, AX
+ADDQ	$8, SI
+ADDQ	$8, DI
+LOOP	popcntMaskSliceLoop
+popcntMaskSliceEnd:
+MOVQ	AX, ret+48(FP)
+RET
+
+TEXT ·popcntAndSliceAsm(SB),4,$0-56
+XORQ	AX, AX
+MOVQ	s+0(FP), SI
+MOVQ	s_len+8(FP), CX
+TESTQ	CX, CX
+JZ		popcntAndSliceEnd
+MOVQ	m+24(FP), DI
+popcntAndSliceLoop:
+MOVQ	(DI), DX
+ANDQ	(SI), DX
+POPCNTQ_DX_DX
+ADDQ	DX, AX
+ADDQ	$8, SI
+ADDQ	$8, DI
+LOOP	popcntAndSliceLoop
+popcntAndSliceEnd:
+MOVQ	AX, ret+48(FP)
+RET
+
+TEXT ·popcntOrSliceAsm(SB),4,$0-56
+XORQ	AX, AX
+MOVQ	s+0(FP), SI
+MOVQ	s_len+8(FP), CX
+TESTQ	CX, CX
+JZ		popcntOrSliceEnd
+MOVQ	m+24(FP), DI
+popcntOrSliceLoop:
+MOVQ	(DI), DX
+ORQ		(SI), DX
+POPCNTQ_DX_DX
+ADDQ	DX, AX
+ADDQ	$8, SI
+ADDQ	$8, DI
+LOOP	popcntOrSliceLoop
+popcntOrSliceEnd:
+MOVQ	AX, ret+48(FP)
+RET
+
+TEXT ·popcntXorSliceAsm(SB),4,$0-56
+XORQ	AX, AX
+MOVQ	s+0(FP), SI
+MOVQ	s_len+8(FP), CX
+TESTQ	CX, CX
+JZ		popcntXorSliceEnd
+MOVQ	m+24(FP), DI
+popcntXorSliceLoop:
+MOVQ	(DI), DX
+XORQ	(SI), DX
+POPCNTQ_DX_DX
+ADDQ	DX, AX
+ADDQ	$8, SI
+ADDQ	$8, DI
+LOOP	popcntXorSliceLoop
+popcntXorSliceEnd:
+MOVQ	AX, ret+48(FP)
+RET

+ 24 - 0
vendor/github.com/willf/bitset/popcnt_generic.go

@@ -0,0 +1,24 @@
+// +build !go1.9
+// +build !amd64 appengine
+
+package bitset
+
+func popcntSlice(s []uint64) uint64 {
+	return popcntSliceGo(s)
+}
+
+func popcntMaskSlice(s, m []uint64) uint64 {
+	return popcntMaskSliceGo(s, m)
+}
+
+func popcntAndSlice(s, m []uint64) uint64 {
+	return popcntAndSliceGo(s, m)
+}
+
+func popcntOrSlice(s, m []uint64) uint64 {
+	return popcntOrSliceGo(s, m)
+}
+
+func popcntXorSlice(s, m []uint64) uint64 {
+	return popcntXorSliceGo(s, m)
+}

+ 14 - 0
vendor/github.com/willf/bitset/trailing_zeros_18.go

@@ -0,0 +1,14 @@
+// +build !go1.9
+
+package bitset
+
+var deBruijn = [...]byte{
+	0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4,
+	62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5,
+	63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11,
+	54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6,
+}
+
+func trailingZeroes64(v uint64) uint {
+	return uint(deBruijn[((v&-v)*0x03f79d71b4ca8b09)>>58])
+}

+ 9 - 0
vendor/github.com/willf/bitset/trailing_zeros_19.go

@@ -0,0 +1,9 @@
+// +build go1.9
+
+package bitset
+
+import "math/bits"
+
+func trailingZeroes64(v uint64) uint {
+	return uint(bits.TrailingZeros64(v))
+}