From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id B03D11FF138 for ; Wed, 04 Mar 2026 14:46:32 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 8C2C7A714; Wed, 4 Mar 2026 14:47:28 +0100 (CET) From: Hannes Laimer To: pve-devel@lists.proxmox.com Subject: [PATCH pve-access-control 1/1] pam: fork for PAM authentication to isolate SIGCHLD handler Date: Wed, 4 Mar 2026 14:46:49 +0100 Message-ID: <20260304134649.82272-3-h.laimer@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260304134649.82272-1-h.laimer@proxmox.com> References: <20260304134649.82272-1-h.laimer@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1772631988776 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.065 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: IA6HE3DXDIRI4VWTUXXMMGYK3JXKGJLP X-Message-ID-Hash: IA6HE3DXDIRI4VWTUXXMMGYK3JXKGJLP X-MailFrom: h.laimer@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: PAM modules can temporarily override $SIG{CHLD}, causing SIGCHLDs from RESTEnvironment worker processes to be lost. Run the PAM interaction in a subprocess via PVE::Tools::run_fork to contain any signal handler manipulation to the child. Signed-off-by: Hannes Laimer --- src/PVE/Auth/PAM.pm | 74 +++++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/src/PVE/Auth/PAM.pm b/src/PVE/Auth/PAM.pm index 3aacfc0..8586da5 100755 --- a/src/PVE/Auth/PAM.pm +++ b/src/PVE/Auth/PAM.pm @@ -27,45 +27,55 @@ sub authenticate_user { # user (www-data) need to be able to read /etc/passwd /etc/shadow die "no password\n" if !$password; - my $pamh = Authen::PAM->new( - 'proxmox-ve-auth', - $username, - sub { - my @res; - while (@_) { - my $msg_type = shift; - my $msg = shift; - push @res, (0, $password); - } - push @res, 0; - return @res; - }, - ); - - if (!ref($pamh)) { - my $err = $pamh->pam_strerror($pamh); - die "error during PAM init: $err"; + # PAM modules may temporarily override $SIG{CHLD}, causing SIGCHLDs from + # RESTEnvironment workers to be lost. Running the PAM interaction in a fork + # isolates any such handler manipulation from the parent process. + my $client_ip; + if (my $rpcenv = PVE::RPCEnvironment::get()) { + $client_ip = $rpcenv->get_client_ip(); } - if (my $rpcenv = PVE::RPCEnvironment::get()) { - if (my $ip = $rpcenv->get_client_ip()) { - $pamh->pam_set_item(PAM_RHOST(), $ip); + PVE::Tools::run_fork(sub { + my $pamh = Authen::PAM->new( + 'proxmox-ve-auth', + $username, + sub { + my @res; + while (@_) { + my $msg_type = shift; + my $msg = shift; + push @res, (0, $password); + } + push @res, 0; + return @res; + }, + ); + + if (!ref($pamh)) { + my $err = $pamh->pam_strerror($pamh); + die "error during PAM init: $err"; } - } - my $res; + if ($client_ip) { + $pamh->pam_set_item(PAM_RHOST(), $client_ip); + } - if (($res = $pamh->pam_authenticate(0)) != PAM_SUCCESS) { - my $err = $pamh->pam_strerror($res); - die "$err\n"; - } + my $res; - if (($res = $pamh->pam_acct_mgmt(0)) != PAM_SUCCESS) { - my $err = $pamh->pam_strerror($res); - die "$err\n"; - } + if (($res = $pamh->pam_authenticate(0)) != PAM_SUCCESS) { + my $err = $pamh->pam_strerror($res); + die "$err\n"; + } + + if (($res = $pamh->pam_acct_mgmt(0)) != PAM_SUCCESS) { + my $err = $pamh->pam_strerror($res); + die "$err\n"; + } + + $pamh = 0; # call destructor - $pamh = 0; # call destructor + return 1; + }); return 1; } -- 2.47.3