SHA256
3
0
forked from pool/libcap
Dirk Mueller 2020-11-15 16:29:16 +00:00 committed by Git OBS Bridge
parent 94f4e5b306
commit 37271ea66e
4 changed files with 123 additions and 5 deletions

View File

@ -0,0 +1,114 @@
From 7cfe15ee579ea83a7780c6190576fdcab3e2faac Mon Sep 17 00:00:00 2001
From: "Andrew G. Morgan" <morgan@kernel.org>
Date: Wed, 11 Nov 2020 19:53:06 -0800
Subject: [PATCH] Allow a dying thread to participate in the psx mechanism.
If a dying thread blocks all interrupts in order to die in peace,
it can deadlock the psx mechanism for all the surviving threads.
To account for this corner case, while waiting to enter the
_PSX_EXITING state, temporarily unblock the psx_tracker.psx_sig.
https://github.com/golang/go/issues/42494
Add a psx_test.go:TestThreadChurn() test case for this issue.
Signed-off-by: Andrew G. Morgan <morgan@kernel.org>
---
psx/psx.c | 34 ++++++++++++++++++++++++++++++++++
psx/psx_test.go | 33 +++++++++++++++++++++++++++++++++
2 files changed, 67 insertions(+)
diff --git a/psx/psx.c b/psx/psx.c
index 72c2098..233267d 100644
--- a/psx/psx.c
+++ b/psx/psx.c
@@ -336,11 +336,45 @@ typedef struct {
* https://sourceware.org/bugzilla/show_bug.cgi?id=12889
*/
static void _psx_exiting(void *node) {
+ /*
+ * Until we are in the _PSX_EXITING state, we must not block the
+ * psx_sig interrupt for this dying thread. That is, until this
+ * exiting thread can set ref->gone to 1, this dying thread is
+ * still participating in the psx syscall distribution.
+ *
+ * See https://github.com/golang/go/issues/42494 for a situation
+ * where this code is called with psx_tracker.psx_sig blocked.
+ */
+ sigset_t sigbit, orig_sigbits;
+ sigemptyset(&sigbit);
+ pthread_sigmask(SIG_UNBLOCK, &sigbit, &orig_sigbits);
+ sigaddset(&sigbit, psx_tracker.psx_sig);
+ pthread_sigmask(SIG_UNBLOCK, &sigbit, NULL);
+
+ /*
+ * With psx_tracker.psx_sig unblocked we can wait until this
+ * thread can enter the _PSX_EXITING state.
+ */
psx_new_state(_PSX_IDLE, _PSX_EXITING);
+
+ /*
+ * We now indicate that this thread is no longer participating in
+ * the psx mechanism.
+ */
registered_thread_t *ref = node;
pthread_mutex_lock(&ref->mu);
ref->gone = 1;
pthread_mutex_unlock(&ref->mu);
+
+ /*
+ * At this point, we can restore the calling sigmask to whatever
+ * the caller thought was appropriate for a dying thread to have.
+ */
+ pthread_sigmask(SIG_SETMASK, &orig_sigbits, NULL);
+
+ /*
+ * Allow the rest of the psx system carry on as per normal.
+ */
psx_new_state(_PSX_EXITING, _PSX_IDLE);
}
diff --git a/psx/psx_test.go b/psx/psx_test.go
index ae6ccd2..3f0445c 100644
--- a/psx/psx_test.go
+++ b/psx/psx_test.go
@@ -64,3 +64,36 @@ func TestErrno(t *testing.T) {
t.Errorf("psx changes prevailing errno got=%v(%d) want=%v", syscall.Errno(v), v, syscall.EPERM)
}
}
+
+// killAThread locks the goroutine to a thread and exits. This has the
+// effect of making the go runtime terminate the thread.
+func killAThread(c <-chan struct{}) {
+ runtime.LockOSThread()
+ <-c
+}
+
+// Test to confirm no regression against:
+//
+// https://github.com/golang/go/issues/42494
+func TestThreadChurn(t *testing.T) {
+ const prSetKeepCaps = 8
+
+ for j := 0; j < 4; j++ {
+ kill := (j & 1) != 0
+ sysc := (j & 2) != 0
+ t.Logf("[%d] testing kill=%v, sysc=%v", j, kill, sysc)
+ for i := 50; i > 0; i-- {
+ if kill {
+ c := make(chan struct{})
+ go killAThread(c)
+ close(c)
+ }
+ if sysc {
+ if _, _, e := Syscall3(syscall.SYS_PRCTL, prSetKeepCaps, uintptr(i&1), 0); e != 0 {
+ t.Fatalf("[%d] psx:prctl(SET_KEEPCAPS, %d) failed: %v", i, i&1, syscall.Errno(e))
+ }
+ }
+ }
+ t.Logf("[%d] PASSED kill=%v, sysc=%v", j, kill, sysc)
+ }
+}
--
2.29.2

3
libcap-2.44.tar.xz Normal file
View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:92188359cd5be86e8e5bd3f6483ac6ce582264f912398937ef763def2205c8e1
size 125568

View File

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d66639f765c0e10557666b00f519caf0bd07a95f867dddaee131cd284fac3286
size 127608

View File

@ -17,7 +17,7 @@
Name: libcap
Version: 2.45
Version: 2.44
Release: 0
Summary: Library for Capabilities (linux-privs) Support
License: BSD-3-Clause AND GPL-2.0-only
@ -25,6 +25,7 @@ Group: Development/Libraries/C and C++
URL: https://sites.google.com/site/fullycapable/
Source: https://www.kernel.org/pub/linux/libs/security/linux-privs/libcap2/libcap-%{version}.tar.xz
Source2: baselibs.conf
Patch: 0001-Allow-a-dying-thread-to-participate-in-the-psx-mecha.patch
BuildRequires: fdupes
BuildRequires: glibc-devel-static
BuildRequires: pkgconfig
@ -89,11 +90,12 @@ libcap.
%prep
%setup -q
%patch -p1
%build
%global _lto_cflags %{_lto_cflags} -ffat-lto-objects
make prefix=%{_prefix} lib=%{_lib} LIBDIR=%{_libdir} SBINDIR=%{_sbindir} \
INCDIR=%{_includedir} MANDIR=%{_mandir} DYNAMIC=yes DEBUG="-g %{optflags}"
INCDIR=%{_includedir} MANDIR=%{_mandir} SHARED=yes DEBUG="-g %{optflags}"
%install
make install RAISE_SETFCAP=no \
@ -115,12 +117,14 @@ make test
%post -n libcap2 -p /sbin/ldconfig
%postun -n libcap2 -p /sbin/ldconfig
%ifarch aarch64
%post -n libpsx2 -p /sbin/ldconfig
%postun -n libpsx2 -p /sbin/ldconfig
%files -n libpsx2
%license License
%{_libdir}/libpsx.so.2*
%endif
%files -n libcap2
%license License