From 505b9d36fdb51b6235f535c406ed2aa790287140 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 5 Nov 2020 18:53:34 -0800 Subject: [PATCH] go-selinux: retry on EINTR Wrap some syscalls (lgetattr, lsetattr, fstatfs, statfs) to retry on EINTR. Related: - https://github.com/containers/storage/pull/757 - https://go-review.googlesource.com/c/go/+/249178 - https://github.com/golang/go/issues/38033 Signed-off-by: Kir Kolyshkin --- go-selinux/selinux_linux.go | 25 +++++++++++++++++++------ go-selinux/xattrs.go | 22 ++++++++++++++++------ 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/go-selinux/selinux_linux.go b/go-selinux/selinux_linux.go index f995b34..c884319 100644 --- a/go-selinux/selinux_linux.go +++ b/go-selinux/selinux_linux.go @@ -111,7 +111,7 @@ func verifySELinuxfsMount(mnt string) bool { if err == nil { break } - if err == unix.EAGAIN { + if err == unix.EAGAIN || err == unix.EINTR { continue } return false @@ -251,9 +251,15 @@ func getSELinuxPolicyRoot() string { 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 +313,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 } diff --git a/go-selinux/xattrs.go b/go-selinux/xattrs.go index de5c80e..2365b4b 100644 --- a/go-selinux/xattrs.go +++ b/go-selinux/xattrs.go @@ -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 + } + } +}