NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: kern/56979: fork(2) fails to be signal safe



The following reply was made to PR lib/56979; it has been noted by GNATS.

From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
To: Tom Lane <tgl%sss.pgh.pa.us@localhost>
Cc: gnats-bugs%NetBSD.org@localhost
Subject: Re: kern/56979: fork(2) fails to be signal safe
Date: Thu, 25 Aug 2022 22:54:52 +0000

 This is a multi-part message in MIME format.
 --=_3LM3Qr5snjR6jwWdKR2eeC80vJ4rOpBA
 
 Can you try the attached patch series?  Do you have a quick reproducer
 for the problem?  Ideally we could make an automatic test for this if
 there's a cheap reproducer to trigger the race.
 
 --=_3LM3Qr5snjR6jwWdKR2eeC80vJ4rOpBA
 Content-Type: text/plain; charset="ISO-8859-1"; name="forksignalsafety"
 Content-Transfer-Encoding: quoted-printable
 Content-Disposition: attachment; filename="forksignalsafety.patch"
 
 From 14e63dd753fad250b3b82701b02a654dd6913a32 Mon Sep 17 00:00:00 2001
 From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
 Date: Thu, 25 Aug 2022 22:49:00 +0000
 Subject: [PATCH 1/2] pthread_atfork(3): Block signals during the call to
  pthread_atfork.
 
 This doesn't affect the calls to the atfork handlers -- it only
 protects access to the lists of handlers from interruption by a
 signal, in case the signal handler calls fork(2).
 ---
  lib/libc/gen/pthread_atfork.c | 23 +++++++++++++++--------
  1 file changed, 15 insertions(+), 8 deletions(-)
 
 diff --git a/lib/libc/gen/pthread_atfork.c b/lib/libc/gen/pthread_atfork.c
 index 9d72261eb6cf..22f2371f44b2 100644
 --- a/lib/libc/gen/pthread_atfork.c
 +++ b/lib/libc/gen/pthread_atfork.c
 @@ -101,15 +101,20 @@ pthread_atfork(void (*prepare)(void), void (*parent)(=
 void),
      void (*child)(void))
  {
  	struct atfork_callback *newprepare, *newparent, *newchild;
 +	sigset_t mask, omask;
 +	int error;
 =20
  	newprepare =3D newparent =3D newchild =3D NULL;
 =20
 +	sigfillset(&mask);
 +	thr_sigsetmask(SIG_SETMASK, &mask, &omask);
 +
  	mutex_lock(&atfork_lock);
  	if (prepare !=3D NULL) {
  		newprepare =3D af_alloc();
  		if (newprepare =3D=3D NULL) {
 -			mutex_unlock(&atfork_lock);
 -			return ENOMEM;
 +			error =3D ENOMEM;
 +			goto out;
  		}
  		newprepare->fn =3D prepare;
  	}
 @@ -119,8 +124,8 @@ pthread_atfork(void (*prepare)(void), void (*parent)(vo=
 id),
  		if (newparent =3D=3D NULL) {
  			if (newprepare !=3D NULL)
  				af_free(newprepare);
 -			mutex_unlock(&atfork_lock);
 -			return ENOMEM;
 +			error =3D ENOMEM;
 +			goto out;
  		}
  		newparent->fn =3D parent;
  	}
 @@ -132,8 +137,8 @@ pthread_atfork(void (*prepare)(void), void (*parent)(vo=
 id),
  				af_free(newprepare);
  			if (newparent !=3D NULL)
  				af_free(newparent);
 -			mutex_unlock(&atfork_lock);
 -			return ENOMEM;
 +			error =3D ENOMEM;
 +			goto out;
  		}
  		newchild->fn =3D child;
  	}
 @@ -150,9 +155,11 @@ pthread_atfork(void (*prepare)(void), void (*parent)(v=
 oid),
  		SIMPLEQ_INSERT_TAIL(&parentq, newparent, next);
  	if (child)
  		SIMPLEQ_INSERT_TAIL(&childq, newchild, next);
 -	mutex_unlock(&atfork_lock);
 +	error =3D 0;
 =20
 -	return 0;
 +out:	mutex_unlock(&atfork_lock);
 +	thr_sigsetmask(SIG_SETMASK, &omask, NULL);
 +	return error;
  }
 =20
  pid_t
 
 From f21ba3adae5fddd6a991b1ba40642db1465ecc99 Mon Sep 17 00:00:00 2001
 From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
 Date: Thu, 25 Aug 2022 22:50:00 +0000
 Subject: [PATCH 2/2] ld.elf_so(8): Make fork take a shared, not exclusive,
  lock.
 
 We only need to ensure that there are no concurrent modifications to
 the rtld data structures in flight, since the threads that began
 those modifications will not exist in the child and will therefore be
 unable to complete them in the child.
 
 A shared lock suffices to ensure there are no such concurrent
 modifications in flight; an exclusive lock is not necessary, and can
 cause deadlock if fork is executed from a signal handler, which is
 explicitly allowed by POSIX (and our own sigaction(2) man page) which
 marks fork as async-signal-safe.
 
 PR lib/56979
 ---
  libexec/ld.elf_so/rtld.c | 5 ++---
  1 file changed, 2 insertions(+), 3 deletions(-)
 
 diff --git a/libexec/ld.elf_so/rtld.c b/libexec/ld.elf_so/rtld.c
 index 5ea978e2e61d..bb37b7f9f232 100644
 --- a/libexec/ld.elf_so/rtld.c
 +++ b/libexec/ld.elf_so/rtld.c
 @@ -1539,14 +1539,13 @@ pid_t __fork(void);
  __dso_public pid_t
  __locked_fork(int *my_errno)
  {
 -	sigset_t mask;
  	pid_t result;
 =20
 -	_rtld_exclusive_enter(&mask);
 +	_rtld_shared_enter();
  	result =3D __fork();
  	if (result =3D=3D -1)
  		*my_errno =3D errno;
 -	_rtld_exclusive_exit(&mask);
 +	_rtld_shared_exit();
 =20
  	return result;
  }
 
 --=_3LM3Qr5snjR6jwWdKR2eeC80vJ4rOpBA--
 


Home | Main Index | Thread Index | Old Index