mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
vendor: opencontainers/selinux v1.7.0
full diff: https://github.com/opencontainers/selinux/compare/v1.6.0...v1.7.0 - Implement get_default_context_with_level() from libselinux - Wrap some syscalls (lgetattr, lsetattr, fstatfs, statfs) to retry on EINTR. - Improve code quality by turning fixing many problems found by linters - Use bufio.Scanner for parsing labels and policy confilabelg - Cache the value for SELinux policy directory - test on ppc64le and go 1.15 Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
parent
4d6bc59f81
commit
ab06bb3ec0
9 changed files with 237 additions and 80 deletions
|
@ -176,7 +176,7 @@ github.com/morikuni/aec 39771216ff4c63d11f5e604076f9
|
|||
# metrics
|
||||
github.com/docker/go-metrics b619b3592b65de4f087d9f16863a7e6ff905973c # v0.0.1
|
||||
|
||||
github.com/opencontainers/selinux 25504e34a9826d481f6e2903963ecaa881749124 # v1.6.0
|
||||
github.com/opencontainers/selinux 63ad55b76fd78d4c76c2f5491f68516e60c9d523 # v1.7.0
|
||||
github.com/willf/bitset 559910e8471e48d76d9e5a1ba15842dee77ad45d # v1.1.11
|
||||
|
||||
|
||||
|
|
2
vendor/github.com/opencontainers/selinux/README.md
generated
vendored
2
vendor/github.com/opencontainers/selinux/README.md
generated
vendored
|
@ -18,5 +18,5 @@ Participation in the OpenContainers community is governed by [OpenContainer's Co
|
|||
|
||||
If you find an issue, please follow the [security][security] protocol to report it.
|
||||
|
||||
[security]: https://github.com/opencontainers/org/blob/master/security
|
||||
[security]: https://github.com/opencontainers/org/blob/master/SECURITY.md
|
||||
[code-of-conduct]: https://github.com/opencontainers/org/blob/master/CODE_OF_CONDUCT.md
|
||||
|
|
5
vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go
generated
vendored
5
vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go
generated
vendored
|
@ -27,14 +27,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 +57,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]
|
||||
|
|
41
vendor/github.com/opencontainers/selinux/go-selinux/selinux.go
generated
vendored
41
vendor/github.com/opencontainers/selinux/go-selinux/selinux.go
generated
vendored
|
@ -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)
|
||||
}
|
||||
|
|
222
vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go
generated
vendored
222
vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go
generated
vendored
|
@ -28,6 +28,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 +37,8 @@ const (
|
|||
xattrNameSelinux = "security.selinux"
|
||||
)
|
||||
|
||||
var policyRoot = filepath.Join(selinuxDir, readConfig(selinuxTypeTag))
|
||||
|
||||
type selinuxState struct {
|
||||
enabledSet bool
|
||||
enabled bool
|
||||
|
@ -54,6 +58,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 +122,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 +216,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 +235,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,15 +244,17 @@ 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
|
||||
err := unix.Fstatfs(int(fh.Fd()), &buf)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "statfs(%q) failed", fh.Name())
|
||||
|
||||
for {
|
||||
err := unix.Fstatfs(int(fh.Fd()), &buf)
|
||||
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 +308,16 @@ func setFileLabel(fpath string, label string) error {
|
|||
if fpath == "" {
|
||||
return ErrEmptyPath
|
||||
}
|
||||
if err := unix.Lsetxattr(fpath, xattrNameSelinux, []byte(label), 0); err != nil {
|
||||
return errors.Wrapf(err, "failed to set file label on %s", fpath)
|
||||
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 +759,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 +836,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,16 +852,14 @@ 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 {
|
||||
c1, c2 = c2, c1
|
||||
}
|
||||
} else if c1 > c2 {
|
||||
c1, c2 = c2, c1
|
||||
}
|
||||
mcs = fmt.Sprintf("s0:c%d,c%d", c1, c2)
|
||||
if err := mcsAdd(mcs); err != nil {
|
||||
|
@ -884,18 +890,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 +904,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 +917,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 +1008,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 +1088,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)
|
||||
}
|
||||
|
|
4
vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go
generated
vendored
4
vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go
generated
vendored
|
@ -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
|
||||
}
|
||||
|
|
22
vendor/github.com/opencontainers/selinux/go-selinux/xattrs.go
generated
vendored
22
vendor/github.com/opencontainers/selinux/go-selinux/xattrs.go
generated
vendored
|
@ -6,21 +6,21 @@ 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) {
|
||||
// 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 := unix.Lgetxattr(path, attr, dest)
|
||||
sz, errno := doLgetxattr(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{})
|
||||
sz, errno = doLgetxattr(path, attr, []byte{})
|
||||
if errno != nil {
|
||||
return nil, errno
|
||||
}
|
||||
|
||||
dest = make([]byte, sz)
|
||||
sz, errno = unix.Lgetxattr(path, attr, dest)
|
||||
sz, errno = doLgetxattr(path, attr, dest)
|
||||
}
|
||||
if errno != nil {
|
||||
return nil, errno
|
||||
|
@ -28,3 +28,13 @@ func lgetxattr(path string, attr string) ([]byte, error) {
|
|||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
2
vendor/github.com/opencontainers/selinux/go.mod
generated
vendored
2
vendor/github.com/opencontainers/selinux/go.mod
generated
vendored
|
@ -4,6 +4,6 @@ go 1.13
|
|||
|
||||
require (
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243
|
||||
github.com/willf/bitset v1.1.11
|
||||
golang.org/x/sys v0.0.0-20191115151921-52ab43148777
|
||||
)
|
||||
|
|
17
vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go
generated
vendored
17
vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go
generated
vendored
|
@ -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
|
||||
// and the error is returned to the caller of Walk;
|
||||
// - 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;
|
||||
//
|
||||
// * 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.
|
||||
// - filepath.SkipDir is not supported;
|
||||
//
|
||||
// - 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 {
|
||||
|
|
Loading…
Reference in a new issue