Subject: | Race condition with signal handling |
Hello!
I found the race condition which can provide:
1. segmentation fault in child
2. memory leak
3. hang on in sig handler subroutine
The problem manifests itself because of unsafe signal processing via sigaction. The signal handler call $hash{key}++ and the main code calls if($hash{key}), and if we receive the signal during the perl's $hash{key} operation, we will change the same $hash{key}, and will get undefined behavior. In the attachment (test.pl) you can see a script which shows how the race works. Some outputs of running this script
perl-5.26.2
$ perl test.pl
FastCGI: manager (pid 19350): initialized
FastCGI: manager (pid 19350): server (pid 19351) started
FastCGI: server (pid 19351): initialized
Attempt to free unreferenced scalar: SV 0x55a2611743c0 at /usr/lib64/perl5/vendor_perl/5.26.2/FCGI/ProcManager.pm line 585.
Attempt to free unreferenced scalar: SV 0x55a2611743c0 at test.pl line 29.
Attempt to free unreferenced scalar: SV 0x55a2611743d8 at /usr/lib64/perl5/vendor_perl/5.26.2/FCGI/ProcManager.pm line 585.
Attempt to free unreferenced scalar: SV 0x55a2611743f0 at /usr/lib64/perl5/vendor_perl/5.26.2/FCGI/ProcManager.pm line 585.
pid exited with status 11
FastCGI: manager (pid 19350):
perl-5.22.1
$ perl test.pl
FastCGI: manager (pid 364262): initialized
FastCGI: manager (pid 364262): server (pid 364263) started
FastCGI: server (pid 364263): initialized
pid exited with status 139
FastCGI: manager (pid 364262):
$ perl /test.pl
FastCGI: manager (pid 364264): initialized
FastCGI: manager (pid 364264): server (pid 364265) started
FastCGI: server (pid 364265): initialized
Attempt to free unreferenced scalar: SV 0x23d9fc0, Perl interpreter: 0x21c6010 at ./test.pl line 31.
pid exited with status 139
FastCGI: manager (pid 364264):
$ perl test.pl
FastCGI: manager (pid 367294): initialized
FastCGI: manager (pid 367294): server (pid 367295) started
FastCGI: server (pid 367295): initialized
panic: leave_scope inconsistency 63 at /usr/share/perl5/FCGI/ProcManager.pm line 541.
pid exited with status 139
FastCGI: manager (pid 367294):
$ perl test.pl
FastCGI: manager (pid 367326): initialized
FastCGI: manager (pid 367326): server (pid 367327) started
FastCGI: server (pid 367327): initialized
Attempt to free unreferenced scalar: SV 0x29d5068, Perl interpreter: 0x27ce010 at ./test.pl line 29.
Attempt to free unreferenced scalar: SV 0x29d5080, Perl interpreter: 0x27ce010 at ./test.pl line 29.
pid exited with status 139
FastCGI: manager (pid 367326):
The solution is to add SIGTERM, SIGHUP into sigprocmask before checking the receieved signal and to restore old_procmask after check (see attachment patch)
Subject: | patch |
Message body not shown because it is not plain text.
Subject: | test.pl |
#!/usr/bin/env perl
use strict;
use warnings;
package ProcManager::Test;
use parent 'FCGI::ProcManager';
use POSIX qw(:sys_wait_h);
sub pm_wait {
my ($this) = FCGI::ProcManager::self_or_default(@_);
while (1) {
kill HUP => keys %{$this->{PIDS}};
my $pid;
while (($pid = waitpid(-1, WNOHANG)) > 0) {
print "pid exited with status $?\n";
delete $this->{PIDS}->{$pid};
$this->pm_abort();
}
}
}
package main;
my $manager = ProcManager::Test->new({n_processes => 1});
$manager->pm_manage();
while (1) {
1 while $manager->pm_received_signal("HUP");
}