forked from pool/libcap
This commit is contained in:
parent
94f4e5b306
commit
37271ea66e
114
0001-Allow-a-dying-thread-to-participate-in-the-psx-mecha.patch
Normal file
114
0001-Allow-a-dying-thread-to-participate-in-the-psx-mecha.patch
Normal 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
3
libcap-2.44.tar.xz
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:92188359cd5be86e8e5bd3f6483ac6ce582264f912398937ef763def2205c8e1
|
||||||
|
size 125568
|
@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:d66639f765c0e10557666b00f519caf0bd07a95f867dddaee131cd284fac3286
|
|
||||||
size 127608
|
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
|
|
||||||
Name: libcap
|
Name: libcap
|
||||||
Version: 2.45
|
Version: 2.44
|
||||||
Release: 0
|
Release: 0
|
||||||
Summary: Library for Capabilities (linux-privs) Support
|
Summary: Library for Capabilities (linux-privs) Support
|
||||||
License: BSD-3-Clause AND GPL-2.0-only
|
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/
|
URL: https://sites.google.com/site/fullycapable/
|
||||||
Source: https://www.kernel.org/pub/linux/libs/security/linux-privs/libcap2/libcap-%{version}.tar.xz
|
Source: https://www.kernel.org/pub/linux/libs/security/linux-privs/libcap2/libcap-%{version}.tar.xz
|
||||||
Source2: baselibs.conf
|
Source2: baselibs.conf
|
||||||
|
Patch: 0001-Allow-a-dying-thread-to-participate-in-the-psx-mecha.patch
|
||||||
BuildRequires: fdupes
|
BuildRequires: fdupes
|
||||||
BuildRequires: glibc-devel-static
|
BuildRequires: glibc-devel-static
|
||||||
BuildRequires: pkgconfig
|
BuildRequires: pkgconfig
|
||||||
@ -89,11 +90,12 @@ libcap.
|
|||||||
|
|
||||||
%prep
|
%prep
|
||||||
%setup -q
|
%setup -q
|
||||||
|
%patch -p1
|
||||||
|
|
||||||
%build
|
%build
|
||||||
%global _lto_cflags %{_lto_cflags} -ffat-lto-objects
|
%global _lto_cflags %{_lto_cflags} -ffat-lto-objects
|
||||||
make prefix=%{_prefix} lib=%{_lib} LIBDIR=%{_libdir} SBINDIR=%{_sbindir} \
|
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
|
%install
|
||||||
make install RAISE_SETFCAP=no \
|
make install RAISE_SETFCAP=no \
|
||||||
@ -115,12 +117,14 @@ make test
|
|||||||
%post -n libcap2 -p /sbin/ldconfig
|
%post -n libcap2 -p /sbin/ldconfig
|
||||||
%postun -n libcap2 -p /sbin/ldconfig
|
%postun -n libcap2 -p /sbin/ldconfig
|
||||||
|
|
||||||
|
%ifarch aarch64
|
||||||
%post -n libpsx2 -p /sbin/ldconfig
|
%post -n libpsx2 -p /sbin/ldconfig
|
||||||
%postun -n libpsx2 -p /sbin/ldconfig
|
%postun -n libpsx2 -p /sbin/ldconfig
|
||||||
|
|
||||||
%files -n libpsx2
|
%files -n libpsx2
|
||||||
%license License
|
%license License
|
||||||
%{_libdir}/libpsx.so.2*
|
%{_libdir}/libpsx.so.2*
|
||||||
|
%endif
|
||||||
|
|
||||||
%files -n libcap2
|
%files -n libcap2
|
||||||
%license License
|
%license License
|
||||||
|
Loading…
Reference in New Issue
Block a user